cast.h 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. #pragma once
  2. #include "traits.h"
  3. #include <google/protobuf/descriptor.h>
  4. #include <google/protobuf/message.h>
  5. #include <util/generic/cast.h>
  6. namespace NProtoBuf {
  7. // C++ compatible conversions of FieldDescriptor::CppType's
  8. using ECppType = FieldDescriptor::CppType;
  9. namespace NCast {
  10. template <ECppType src, ECppType dst>
  11. struct TIsCompatibleCppType {
  12. enum {
  13. Result = src == dst ||
  14. (TIsNumericCppType<src>::Result && TIsNumericCppType<dst>::Result)
  15. };
  16. };
  17. template <ECppType src, ECppType dst>
  18. struct TIsEnumToNumericCppType {
  19. enum {
  20. Result = (src == FieldDescriptor::CPPTYPE_ENUM && TIsNumericCppType<dst>::Result)
  21. };
  22. };
  23. template <ECppType src, ECppType dst, bool compatible> // compatible == true
  24. struct TCompatCastBase {
  25. static const bool IsCompatible = true;
  26. typedef typename TCppTypeTraits<src>::T TSrc;
  27. typedef typename TCppTypeTraits<dst>::T TDst;
  28. static inline TDst Cast(TSrc value) {
  29. return value;
  30. }
  31. };
  32. template <ECppType src, ECppType dst> // compatible == false
  33. struct TCompatCastBase<src, dst, false> {
  34. static const bool IsCompatible = false;
  35. typedef typename TCppTypeTraits<src>::T TSrc;
  36. typedef typename TCppTypeTraits<dst>::T TDst;
  37. static inline TDst Cast(TSrc) {
  38. ythrow TBadCastException() << "Incompatible FieldDescriptor::CppType conversion: #"
  39. << (size_t)src << " to #" << (size_t)dst;
  40. }
  41. };
  42. template <ECppType src, ECppType dst, bool isEnumToNum> // enum -> numeric
  43. struct TCompatCastImpl {
  44. static const bool IsCompatible = true;
  45. typedef typename TCppTypeTraits<dst>::T TDst;
  46. static inline TDst Cast(const EnumValueDescriptor* value) {
  47. Y_ASSERT(value != nullptr);
  48. return value->number();
  49. }
  50. };
  51. template <ECppType src, ECppType dst>
  52. struct TCompatCastImpl<src, dst, false>: public TCompatCastBase<src, dst, TIsCompatibleCppType<src, dst>::Result> {
  53. using TCompatCastBase<src, dst, TIsCompatibleCppType<src, dst>::Result>::IsCompatible;
  54. };
  55. template <ECppType src, ECppType dst>
  56. struct TCompatCast: public TCompatCastImpl<src, dst, TIsEnumToNumericCppType<src, dst>::Result> {
  57. typedef TCompatCastImpl<src, dst, TIsEnumToNumericCppType<src, dst>::Result> TBase;
  58. typedef typename TCppTypeTraits<src>::T TSrc;
  59. typedef typename TCppTypeTraits<dst>::T TDst;
  60. using TBase::Cast;
  61. using TBase::IsCompatible;
  62. inline bool Try(TSrc value, TDst& res) {
  63. if (IsCompatible) {
  64. res = Cast(value);
  65. return true;
  66. }
  67. return false;
  68. }
  69. };
  70. }
  71. template <ECppType src, ECppType dst>
  72. inline typename TCppTypeTraits<dst>::T CompatCast(typename TCppTypeTraits<src>::T value) {
  73. return NCast::TCompatCast<src, dst>::Cast(value);
  74. }
  75. template <ECppType src, ECppType dst>
  76. inline bool TryCompatCast(typename TCppTypeTraits<src>::T value, typename TCppTypeTraits<dst>::T& res) {
  77. return NCast::TCompatCast<src, dst>::Try(value, res);
  78. }
  79. // Message static/dynamic checked casts
  80. template <typename TpMessage>
  81. inline const TpMessage* TryCast(const Message* msg) {
  82. if (!msg || TpMessage::descriptor() != msg->GetDescriptor())
  83. return NULL;
  84. return CheckedCast<const TpMessage*>(msg);
  85. }
  86. template <typename TpMessage>
  87. inline const TpMessage* TryCast(const Message* msg, const TpMessage*& ret) {
  88. ret = TryCast<TpMessage>(msg);
  89. return ret;
  90. }
  91. template <typename TpMessage>
  92. inline TpMessage* TryCast(Message* msg) {
  93. if (!msg || TpMessage::descriptor() != msg->GetDescriptor())
  94. return nullptr;
  95. return CheckedCast<TpMessage*>(msg);
  96. }
  97. template <typename TpMessage>
  98. inline TpMessage* TryCast(Message* msg, TpMessage*& ret) {
  99. ret = TryCast<TpMessage>(msg);
  100. return ret;
  101. }
  102. // specialize for Message itself
  103. template <>
  104. inline const Message* TryCast<Message>(const Message* msg) {
  105. return msg;
  106. }
  107. template <>
  108. inline Message* TryCast<Message>(Message* msg) {
  109. return msg;
  110. }
  111. // Binary serialization compatible conversion
  112. inline bool TryBinaryCast(const Message* from, Message* to, TString* buffer = nullptr) {
  113. TString tmpbuf;
  114. if (!buffer)
  115. buffer = &tmpbuf;
  116. if (!from->SerializeToString(buffer))
  117. return false;
  118. return to->ParseFromString(*buffer);
  119. }
  120. }