#pragma once #include #include #include #include #include #include #include namespace NBus { using TBusBufferRecord = ::google::protobuf::Message; template class TBusBufferMessagePtr; template class TBusBufferMessageAutoPtr; class TBusBufferBase: public TBusMessage { public: TBusBufferBase(int type) : TBusMessage((ui16)type) { } TBusBufferBase(ECreateUninitialized) : TBusMessage(MESSAGE_CREATE_UNINITIALIZED) { } ui16 GetType() const { return GetHeader()->Type; } virtual TBusBufferRecord* GetRecord() const = 0; virtual TBusBufferBase* New() = 0; }; /////////////////////////////////////////////////////////////////// /// \brief Template for all messages that have protobuf description /// @param TBufferRecord is record described in .proto file with namespace /// @param MessageFile is offset for .proto file message ids /// \attention If you want one protocol NBus::TBusBufferProtocol to handle /// messageges described in different .proto files, make sure that they have /// unique values for MessageFile template class TBusBufferMessage: public TBusBufferBase { public: static const int MessageType = MType; typedef TBusBufferMessagePtr> TPtr; typedef TBusBufferMessageAutoPtr> TAutoPtr; public: typedef TBufferRecord RecordType; TBufferRecord Record; public: TBusBufferMessage() : TBusBufferBase(MessageType) { } TBusBufferMessage(ECreateUninitialized) : TBusBufferBase(MESSAGE_CREATE_UNINITIALIZED) { } explicit TBusBufferMessage(const TBufferRecord& record) : TBusBufferBase(MessageType) , Record(record) { } explicit TBusBufferMessage(TBufferRecord&& record) : TBusBufferBase(MessageType) , Record(std::move(record)) { } public: TBusBufferRecord* GetRecord() const override { return (TBusBufferRecord*)&Record; } TBusBufferBase* New() override { return new TBusBufferMessage(); } }; template class TBusBufferMessagePtrBase { public: typedef typename TBufferMessage::RecordType RecordType; private: TSelf* GetSelf() { return static_cast(this); } const TSelf* GetSelf() const { return static_cast(this); } public: RecordType* operator->() { Y_ASSERT(GetSelf()->Get()); return &(GetSelf()->Get()->Record); } const RecordType* operator->() const { Y_ASSERT(GetSelf()->Get()); return &(GetSelf()->Get()->Record); } RecordType& operator*() { Y_ASSERT(GetSelf()->Get()); return GetSelf()->Get()->Record; } const RecordType& operator*() const { Y_ASSERT(GetSelf()->Get()); return GetSelf()->Get()->Record; } TBusHeader* GetHeader() { return GetSelf()->Get()->GetHeader(); } const TBusHeader* GetHeader() const { return GetSelf()->Get()->GetHeader(); } }; template class TBusBufferMessagePtr: public TBusBufferMessagePtrBase, TBufferMessage> { protected: TBufferMessage* Holder; public: TBusBufferMessagePtr(TBufferMessage* mess) : Holder(mess) { } static TBusBufferMessagePtr DynamicCast(TBusMessage* message) { return dynamic_cast(message); } TBufferMessage* Get() { return Holder; } const TBufferMessage* Get() const { return Holder; } operator TBufferMessage*() { return Holder; } operator const TBufferMessage*() const { return Holder; } operator TAutoPtr() { TAutoPtr r(Holder); Holder = 0; return r; } operator TBusMessageAutoPtr() { TBusMessageAutoPtr r(Holder); Holder = nullptr; return r; } }; template class TBusBufferMessageAutoPtr: public TBusBufferMessagePtrBase, TBufferMessage> { public: TAutoPtr AutoPtr; public: TBusBufferMessageAutoPtr() { } TBusBufferMessageAutoPtr(TBufferMessage* message) : AutoPtr(message) { } TBufferMessage* Get() { return AutoPtr.Get(); } const TBufferMessage* Get() const { return AutoPtr.Get(); } TBufferMessage* Release() const { return AutoPtr.Release(); } operator TAutoPtr() { return AutoPtr.Release(); } operator TBusMessageAutoPtr() { return AutoPtr.Release(); } }; ///////////////////////////////////////////// /// \brief Generic protocol object for messages descibed with protobuf /// \attention If you mix messages in the same protocol from more than /// .proto file make sure that they have different MessageFile parameter /// in the NBus::TBusBufferMessage template class TBusBufferProtocol: public TBusProtocol { private: TVector Types; std::array> 5)> TypeMask; TBusBufferBase* FindType(int type); bool IsRegisteredType(unsigned type); public: TBusBufferProtocol(TBusService name, int port); ~TBusBufferProtocol() override; /// register all the message that this protocol should handle void RegisterType(TAutoPtr mess); TArrayRef GetTypes() const; /// serialized protocol specific data into TBusData void Serialize(const TBusMessage* mess, TBuffer& data) override; TAutoPtr Deserialize(ui16 messageType, TArrayRef payload) override; }; }