#pragma once #include "traits.h" #include #include #include namespace NProtoBuf { // C++ compatible conversions of FieldDescriptor::CppType's using ECppType = FieldDescriptor::CppType; namespace NCast { template struct TIsCompatibleCppType { enum { Result = src == dst || (TIsNumericCppType::Result && TIsNumericCppType::Result) }; }; template struct TIsEnumToNumericCppType { enum { Result = (src == FieldDescriptor::CPPTYPE_ENUM && TIsNumericCppType::Result) }; }; template // compatible == true struct TCompatCastBase { static const bool IsCompatible = true; typedef typename TCppTypeTraits::T TSrc; typedef typename TCppTypeTraits::T TDst; static inline TDst Cast(TSrc value) { return value; } }; template // compatible == false struct TCompatCastBase { static const bool IsCompatible = false; typedef typename TCppTypeTraits::T TSrc; typedef typename TCppTypeTraits::T TDst; static inline TDst Cast(TSrc) { ythrow TBadCastException() << "Incompatible FieldDescriptor::CppType conversion: #" << (size_t)src << " to #" << (size_t)dst; } }; template // enum -> numeric struct TCompatCastImpl { static const bool IsCompatible = true; typedef typename TCppTypeTraits::T TDst; static inline TDst Cast(const EnumValueDescriptor* value) { Y_ASSERT(value != nullptr); return value->number(); } }; template struct TCompatCastImpl: public TCompatCastBase::Result> { using TCompatCastBase::Result>::IsCompatible; }; template struct TCompatCast: public TCompatCastImpl::Result> { typedef TCompatCastImpl::Result> TBase; typedef typename TCppTypeTraits::T TSrc; typedef typename TCppTypeTraits::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 inline typename TCppTypeTraits::T CompatCast(typename TCppTypeTraits::T value) { return NCast::TCompatCast::Cast(value); } template inline bool TryCompatCast(typename TCppTypeTraits::T value, typename TCppTypeTraits::T& res) { return NCast::TCompatCast::Try(value, res); } // Message static/dynamic checked casts template inline const TpMessage* TryCast(const Message* msg) { if (!msg || TpMessage::descriptor() != msg->GetDescriptor()) return NULL; return CheckedCast(msg); } template inline const TpMessage* TryCast(const Message* msg, const TpMessage*& ret) { ret = TryCast(msg); return ret; } template inline TpMessage* TryCast(Message* msg) { if (!msg || TpMessage::descriptor() != msg->GetDescriptor()) return nullptr; return CheckedCast(msg); } template inline TpMessage* TryCast(Message* msg, TpMessage*& ret) { ret = TryCast(msg); return ret; } // specialize for Message itself template <> inline const Message* TryCast(const Message* msg) { return msg; } template <> inline Message* TryCast(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); } }