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