aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/protobuf/util/cast.h
diff options
context:
space:
mode:
authorDevtools Arcadia <arcadia-devtools@yandex-team.ru>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/protobuf/util/cast.h
downloadydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/protobuf/util/cast.h')
-rw-r--r--library/cpp/protobuf/util/cast.h156
1 files changed, 156 insertions, 0 deletions
diff --git a/library/cpp/protobuf/util/cast.h b/library/cpp/protobuf/util/cast.h
new file mode 100644
index 0000000000..83749dfcee
--- /dev/null
+++ b/library/cpp/protobuf/util/cast.h
@@ -0,0 +1,156 @@
+#pragma once
+
+#include "traits.h"
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/message.h>
+
+#include <util/generic/cast.h>
+
+namespace NProtoBuf {
+ // C++ compatible conversions of FieldDescriptor::CppType's
+
+ using ECppType = FieldDescriptor::CppType;
+
+ namespace NCast {
+ template <ECppType src, ECppType dst>
+ struct TIsCompatibleCppType {
+ enum {
+ Result = src == dst ||
+ (TIsNumericCppType<src>::Result && TIsNumericCppType<dst>::Result)
+ };
+ };
+
+ template <ECppType src, ECppType dst>
+ struct TIsEnumToNumericCppType {
+ enum {
+ Result = (src == FieldDescriptor::CPPTYPE_ENUM && TIsNumericCppType<dst>::Result)
+ };
+ };
+
+ template <ECppType src, ECppType dst, bool compatible> // compatible == true
+ struct TCompatCastBase {
+ static const bool IsCompatible = true;
+
+ typedef typename TCppTypeTraits<src>::T TSrc;
+ typedef typename TCppTypeTraits<dst>::T TDst;
+
+ static inline TDst Cast(TSrc value) {
+ return value;
+ }
+ };
+
+ template <ECppType src, ECppType dst> // compatible == false
+ struct TCompatCastBase<src, dst, false> {
+ static const bool IsCompatible = false;
+
+ typedef typename TCppTypeTraits<src>::T TSrc;
+ typedef typename TCppTypeTraits<dst>::T TDst;
+
+ static inline TDst Cast(TSrc) {
+ ythrow TBadCastException() << "Incompatible FieldDescriptor::CppType conversion: #"
+ << (size_t)src << " to #" << (size_t)dst;
+ }
+ };
+
+ template <ECppType src, ECppType dst, bool isEnumToNum> // enum -> numeric
+ struct TCompatCastImpl {
+ static const bool IsCompatible = true;
+
+ typedef typename TCppTypeTraits<dst>::T TDst;
+
+ static inline TDst Cast(const EnumValueDescriptor* value) {
+ Y_ASSERT(value != nullptr);
+ return value->number();
+ }
+ };
+
+ template <ECppType src, ECppType dst>
+ struct TCompatCastImpl<src, dst, false>: public TCompatCastBase<src, dst, TIsCompatibleCppType<src, dst>::Result> {
+ using TCompatCastBase<src, dst, TIsCompatibleCppType<src, dst>::Result>::IsCompatible;
+ };
+
+ template <ECppType src, ECppType dst>
+ struct TCompatCast: public TCompatCastImpl<src, dst, TIsEnumToNumericCppType<src, dst>::Result> {
+ typedef TCompatCastImpl<src, dst, TIsEnumToNumericCppType<src, dst>::Result> TBase;
+
+ typedef typename TCppTypeTraits<src>::T TSrc;
+ typedef typename TCppTypeTraits<dst>::T TDst;
+
+ using TBase::Cast;
+ using TBase::IsCompatible;
+
+ inline bool Try(TSrc value, TDst& res) {
+ if (IsCompatible) {
+ res = Cast(value);
+ return true;
+ }
+ return false;
+ }
+ };
+
+ }
+
+ template <ECppType src, ECppType dst>
+ inline typename TCppTypeTraits<dst>::T CompatCast(typename TCppTypeTraits<src>::T value) {
+ return NCast::TCompatCast<src, dst>::Cast(value);
+ }
+
+ template <ECppType src, ECppType dst>
+ inline bool TryCompatCast(typename TCppTypeTraits<src>::T value, typename TCppTypeTraits<dst>::T& res) {
+ return NCast::TCompatCast<src, dst>::Try(value, res);
+ }
+
+ // Message static/dynamic checked casts
+
+ template <typename TpMessage>
+ inline const TpMessage* TryCast(const Message* msg) {
+ if (!msg || TpMessage::descriptor() != msg->GetDescriptor())
+ return NULL;
+ return CheckedCast<const TpMessage*>(msg);
+ }
+
+ template <typename TpMessage>
+ inline const TpMessage* TryCast(const Message* msg, const TpMessage*& ret) {
+ ret = TryCast<TpMessage>(msg);
+ return ret;
+ }
+
+ template <typename TpMessage>
+ inline TpMessage* TryCast(Message* msg) {
+ if (!msg || TpMessage::descriptor() != msg->GetDescriptor())
+ return nullptr;
+ return CheckedCast<TpMessage*>(msg);
+ }
+
+ template <typename TpMessage>
+ inline TpMessage* TryCast(Message* msg, TpMessage*& ret) {
+ ret = TryCast<TpMessage>(msg);
+ return ret;
+ }
+
+ // specialize for Message itself
+
+ template <>
+ inline const Message* TryCast<Message>(const Message* msg) {
+ return msg;
+ }
+
+ template <>
+ inline Message* TryCast<Message>(Message* msg) {
+ return msg;
+ }
+
+ // Binary serialization compatible conversion
+ inline bool TryBinaryCast(const Message* from, Message* to, TString* buffer = nullptr) {
+ TString tmpbuf;
+ if (!buffer)
+ buffer = &tmpbuf;
+
+ if (!from->SerializeToString(buffer))
+ return false;
+
+ return to->ParseFromString(*buffer);
+ }
+
+}