#pragma once #include #include namespace sp { namespace option { // Provide static numeric ID, to facilitate implementation of GetIdImpl() template struct StaticNumIdImpl {}; // Facilitate implementation of DispatchImpl() template struct DispatchImpl {}; // Provide fields of the message, facilitate implementation of // ReadImpl(), WriteImpl(), ValidImpl(), etc... template struct FieldsImpl {}; } // namespace option template class MessageImplParsedOptions; template <> struct MessageImplParsedOptions<> { static const bool HasStaticNumIdImpl = false; static const bool HasDispatchImpl = false; static const bool HasFieldsImpl = false; }; template struct MessageImplParsedOptions, TOptions...> : public MessageImplParsedOptions { static const bool HasStaticNumIdImpl = true; static const std::intmax_t MsgId = TId; }; template struct MessageImplParsedOptions, TOptions...> : public MessageImplParsedOptions { static const bool HasDispatchImpl = true; using ActualMessage = TActual; }; template struct MessageImplParsedOptions, TOptions...> : public MessageImplParsedOptions { static const bool HasFieldsImpl = true; using Fields = TFields; }; // ID information chunk template class MessageImplStaticNumIdBase : public TBase { public: // Reuse the message ID type defined in the interface using MsgIdType = typename TBase::MsgIdType; protected: virtual MsgIdType GetIdImpl() const override { return static_cast(TId); } }; // Dispatch implementation chunk template class MessageImplDispatchBase : public TBase { public: // Reuse the Handler type defined in the interface class using Handler = typename TBase::HandlerType; protected: virtual void DispatchImpl(Handler& handler) override { handler.Handle(static_cast(*this)); } }; template class MessageImplFieldsBase : public TBase { public: using AllFields = TFields; AllFields& GetFields() { return m_Fields; } const AllFields& GetFields() const { return m_Fields; } template auto& GetField() { return std::get(GetFields()).GetValue(); } private: TFields m_Fields; }; template class MessageImplFieldsReadBase : public TBase { protected: void ReadImpl(DataBuffer& buffer) override { //TODO: add endianess auto& allFields = TBase::GetFields(); tupleForEach(allFields, FieldReader{buffer}); } }; template class MessageImplFieldsWriteBase : public TBase { protected: void WriteImpl(DataBuffer& buffer) override { //TODO: add endianess auto& allFields = TBase::GetFields(); tupleForEach(allFields, FieldWriter{buffer}); } }; template class MessageImplFieldsValidBase : public TBase { protected: bool ValidImpl() const override { // Access fields via interface provided in previous chunk // auto& allFields = TBase::GetFields(); //... // validate all the fields } }; // id impl template struct MessageImplProcessStaticNumId; template struct MessageImplProcessStaticNumId { using Type = MessageImplStaticNumIdBase; }; template struct MessageImplProcessStaticNumId { using Type = TBase; }; // dispatch impl template struct MessageImplProcessDispatch; template struct MessageImplProcessDispatch { using Type = MessageImplDispatchBase; }; template struct MessageImplProcessDispatch { using Type = TBase; }; // fields impl template struct MessageImplProcessFields; template struct MessageImplProcessFields { using Type = MessageImplFieldsBase; }; template struct MessageImplProcessFields { using Type = TBase; }; // read impl template struct MessageImplProcessReadFields; template struct MessageImplProcessReadFields { using Type = MessageImplFieldsReadBase; }; template struct MessageImplProcessReadFields { using Type = TBase; }; // write impl template struct MessageImplProcessWriteFields; template struct MessageImplProcessWriteFields { using Type = MessageImplFieldsWriteBase; }; template struct MessageImplProcessWriteFields { using Type = TBase; }; // valid impl template struct MessageImplProcessValidFields; template struct MessageImplProcessValidFields { using Type = MessageImplFieldsValidBase; }; template struct MessageImplProcessValidFields { using Type = TBase; }; // TBase is interface class // TOptions... are the implementation options template struct MessageImplBuilder { // ParsedOptions class is supposed to be defined in comms::Message class using InterfaceOptions = typename TBase::ParsedOptions; // Parse implementation options using ImplOptions = MessageImplParsedOptions; // Provide GetIdImpl() if possible static const bool HasStaticNumIdImpl = InterfaceOptions::HasMsgIdType && ImplOptions::HasStaticNumIdImpl; using Base1 = typename MessageImplProcessStaticNumId::Type; // Provide DispatchImpl() if possible static const bool HasDispatchImpl = InterfaceOptions::HasHandler && ImplOptions::HasDispatchImpl; using Base2 = typename MessageImplProcessDispatch::Type; // Provide access to fields if possible using Base3 = typename MessageImplProcessFields::Type; // Provide ReadImpl() if possible static const bool HasReadImpl = InterfaceOptions::HasReadOperations && ImplOptions::HasFieldsImpl; using Base4 = typename MessageImplProcessReadFields::Type; // Provide WriteImpl() if possible static const bool HasWriteImpl = InterfaceOptions::HasWriteOperations && ImplOptions::HasFieldsImpl; using Base5 = typename MessageImplProcessWriteFields::Type; // Provide ValidImpl() if possible static const bool HasValidImpl = InterfaceOptions::HasWriteOperations && ImplOptions::HasFieldsImpl; using Base6 = typename MessageImplProcessValidFields::Type; // The last BaseN must be taken as final type. using Type = Base6; }; template class MessageBase : public MessageImplBuilder::Type {}; } // namespace sp