diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/protobuf/util/cast.h | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/protobuf/util/cast.h')
-rw-r--r-- | library/cpp/protobuf/util/cast.h | 156 |
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); + } + +} |