#pragma once namespace sp { namespace details { // 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 = typename details::FieldsBuilder::Type; template void Construct(Args... args) { m_Fields = std::make_tuple(args...); } AllFields& GetFields() { return m_Fields; } const AllFields& GetFields() const { return m_Fields; } template auto& GetField() { return std::get(GetFields()).GetValue(); } template const auto& GetField() const { return std::get(GetFields()).GetValue(); } // allow use of enums template const auto& GetField() const { return std::get(FIndex)>(this->GetFields()).GetValue(); } private: AllFields m_Fields; }; template class MessageImplFieldsReadBase : public TBase { private: // normal reading template void ReadField(Field& field, DataBuffer& buffer) { this->ReadData(field.GetValue(), buffer); } // reading field in bitfield template void ReadField(Field& field, TFieldType data, std::size_t offset) { static constexpr std::size_t TotalBitCount = sizeof(TFieldType) * 8; // we suppose that the first element is at the highest bits field.GetValue() = (data >> TotalBitCount - IAlignment - offset) & ((1 << IAlignment) - 1); } // reading bitfield template void ReadField(Field, 0>& field, DataBuffer& buffer) { TContainer data; this->ReadData(data, buffer); std::size_t offset = 0; TupleForEach( [data, this, &offset](auto& field) { this->ReadField(field, data, offset); offset += field.GetAlignment(); }, field.GetValue().GetFields()); } void ReadImpl(DataBuffer& buffer) override { auto& allFields = this->GetFields(); TupleForEach([&buffer, this](auto& field) { this->ReadField(field, buffer); }, allFields); } }; template class MessageImplFieldsWriteBase : public TBase { private: // normal writing template void WriteField(Field& field, DataBuffer& buffer) { this->WriteData(field.GetValue(), buffer); } // writing field in bitfield template void WriteField(Field& field, TFieldType& data, std::size_t offset) { static constexpr std::size_t TotalBitCount = sizeof(TFieldType) * 8; // we suppose that the first element is at the highest bits data |= (field.GetValue() & ((1 << IAlignment) - 1)) << TotalBitCount - IAlignment - offset; } // writing bitfield template void WriteField(Field, 0>& field, DataBuffer& buffer) { TContainer data = 0; std::size_t offset = 0; TupleForEach( [&data, this, &offset](auto& field) { this->WriteField(field, data, offset); offset += field.GetAlignment(); }, field.GetValue().GetFields()); this->WriteData(data, buffer); } void WriteImpl(DataBuffer& buffer) override { auto& allFields = this->GetFields(); TupleForEach([&buffer, this](auto& field) { this->WriteField(field, buffer); }, allFields); } }; 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 return true; } }; } // namespace details } // namespace sp