aboutsummaryrefslogblamecommitdiffstats
path: root/library/cpp/protobuf/util/cast.h
blob: 83749dfcee50e1b489c097729de92e675db302e5 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
            
 
                   
 
                                       
 
                              
                     
                                                               
 
                                              
 





                                                                                           
          



                                                                                                 
          

                                                                                    
 
                                                         
 

                                                 
          
 

                                                                    
 
                                                         
 



                                                                                                   
 

                                                                                  
 
                                                         
 



                                                                       
 


                                                                                                                           
 

                                                                                                         
 
                                                         
 
                                      
 






                                                    
 
     
                                         

                                                                                              
                                         

                                                                                                            
 
                                           
 




                                                                    
 



                                                                                
 




                                                                    
 



                                                              
 
                                    
 


                                                                
 


                                                    
 



                                                                                            
 
                                             
 
                                            
 
#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);
    }

}