MessagePrinter (Fixes #2)
All checks were successful
Linux arm64 / Build (push) Successful in 15s
All checks were successful
Linux arm64 / Build (push) Successful in 15s
This commit is contained in:
@@ -14,7 +14,8 @@ using UpgradeTowerFields = std::tuple<
|
|||||||
sp::BitField<std::uint16_t,
|
sp::BitField<std::uint16_t,
|
||||||
sp::Field<std::uint16_t, 12>, //<- m_Tower
|
sp::Field<std::uint16_t, 12>, //<- m_Tower
|
||||||
sp::Field<std::uint8_t, 4> //<- m_Upgrade
|
sp::Field<std::uint8_t, 4> //<- m_Upgrade
|
||||||
>
|
>,
|
||||||
|
sp::VarInt //<- just for testing
|
||||||
>;
|
>;
|
||||||
|
|
||||||
DeclarePacket(UpgradeTower){
|
DeclarePacket(UpgradeTower){
|
||||||
|
|||||||
26
include/sp/common/Reflection.h
Normal file
26
include/sp/common/Reflection.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cxxabi.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace sp {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::string GetClassName(const T& a_Value) {
|
||||||
|
int status;
|
||||||
|
char* demangled = abi::__cxa_demangle(typeid(a_Value).name(), 0, 0, &status);
|
||||||
|
if (status != 0)
|
||||||
|
return "";
|
||||||
|
return std::string(demangled);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::string GetClassName() {
|
||||||
|
int status;
|
||||||
|
char* demangled = abi::__cxa_demangle(typeid(T).name(), 0, 0, &status);
|
||||||
|
if (status != 0)
|
||||||
|
return "";
|
||||||
|
return std::string(demangled);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sp
|
||||||
@@ -70,29 +70,32 @@ class BitField {
|
|||||||
* \tparam ValueType the type of the value to store
|
* \tparam ValueType the type of the value to store
|
||||||
* \tparam IAlignment 0 means no alignment
|
* \tparam IAlignment 0 means no alignment
|
||||||
*/
|
*/
|
||||||
template <typename ValueType, int IAlignment>
|
template <typename ValueType, std::size_t IAlignment>
|
||||||
class Field {
|
class Field {
|
||||||
public:
|
public:
|
||||||
|
using StorageType = ValueType;
|
||||||
|
static constexpr std::size_t AlignmentValue = IAlignment;
|
||||||
|
|
||||||
// Provide an access to the stored value
|
// Provide an access to the stored value
|
||||||
ValueType& GetValue() {
|
StorageType& GetValue() {
|
||||||
return m_Value;
|
return m_Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ValueType& GetValue() const {
|
const StorageType& GetValue() const {
|
||||||
return m_Value;
|
return m_Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Field& operator=(const ValueType& value) {
|
Field& operator=(const StorageType& value) {
|
||||||
m_Value = value;
|
m_Value = value;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr int GetAlignment() const {
|
constexpr std::size_t GetAlignment() const {
|
||||||
return IAlignment;
|
return IAlignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ValueType m_Value;
|
StorageType m_Value;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace details {
|
namespace details {
|
||||||
|
|||||||
19
include/sp/protocol/MessagePrinter.h
Normal file
19
include/sp/protocol/MessagePrinter.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ostream>
|
||||||
|
#include <sp/common/Reflection.h>
|
||||||
|
#include <sp/protocol/message/MessagePrinterImpl.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Prints a message in a human readable string
|
||||||
|
*/
|
||||||
|
template <typename TBase, typename... TOptions>
|
||||||
|
std::ostream& operator<<(std::ostream& a_Stream, const sp::MessageBase<TBase, TOptions...>& a_Message) {
|
||||||
|
a_Stream
|
||||||
|
<< sp::GetClassName(a_Message)
|
||||||
|
<< sp::details::IdPrinter<TOptions...>::PrintMessageId()
|
||||||
|
<< "["
|
||||||
|
<< sp::details::PrintFields(a_Message.GetFields())
|
||||||
|
<< "]";
|
||||||
|
return a_Stream;
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@ namespace sp {
|
|||||||
namespace option {
|
namespace option {
|
||||||
|
|
||||||
// Provide static numeric ID, to facilitate implementation of GetIdImpl()
|
// Provide static numeric ID, to facilitate implementation of GetIdImpl()
|
||||||
template <std::intmax_t TId>
|
template <std::uintmax_t TId>
|
||||||
struct StaticNumIdImpl {};
|
struct StaticNumIdImpl {};
|
||||||
|
|
||||||
// Facilitate implementation of DispatchImpl()
|
// Facilitate implementation of DispatchImpl()
|
||||||
@@ -39,10 +39,10 @@ struct MessageImplParsedOptions<> {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
template <std::intmax_t TId, typename... TOptions>
|
template <std::uintmax_t TId, typename... TOptions>
|
||||||
struct MessageImplParsedOptions<option::StaticNumIdImpl<TId>, TOptions...> : public MessageImplParsedOptions<TOptions...> {
|
struct MessageImplParsedOptions<option::StaticNumIdImpl<TId>, TOptions...> : public MessageImplParsedOptions<TOptions...> {
|
||||||
static const bool HasStaticNumIdImpl = true;
|
static const bool HasStaticNumIdImpl = true;
|
||||||
static const std::intmax_t MsgId = TId;
|
static const std::uintmax_t MsgId = TId;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename TActual, typename... TOptions>
|
template <typename TActual, typename... TOptions>
|
||||||
|
|||||||
81
include/sp/protocol/message/MessagePrinterImpl.h
Normal file
81
include/sp/protocol/message/MessagePrinterImpl.h
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <sp/protocol/MessageBase.h>
|
||||||
|
|
||||||
|
namespace sp {
|
||||||
|
namespace details {
|
||||||
|
|
||||||
|
template <typename... TOptions>
|
||||||
|
struct IdPrinter {};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct IdPrinter<> {
|
||||||
|
static std::string PrintMessageId() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TOption, typename... TOptions>
|
||||||
|
struct IdPrinter<TOption, TOptions...> {
|
||||||
|
static std::string PrintMessageId() {
|
||||||
|
return IdPrinter<TOptions...>::PrintMessageId();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename... TOptions, std::uintmax_t TId>
|
||||||
|
struct IdPrinter<option::StaticNumIdImpl<TId>, TOptions...> {
|
||||||
|
static std::string PrintMessageId() {
|
||||||
|
return "(Id: " + std::to_string(TId) + ")";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::string PrintData(const T& a_Data) {
|
||||||
|
std::stringstream sStream;
|
||||||
|
sStream << a_Data;
|
||||||
|
return sStream.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
std::string PrintData<char>(const char& a_Data) {
|
||||||
|
return std::to_string(a_Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
std::string PrintData<unsigned char>(const unsigned char& a_Data) {
|
||||||
|
return std::to_string(a_Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... TFields>
|
||||||
|
std::string PrintFields(const std::tuple<TFields...>& a_Fields);
|
||||||
|
|
||||||
|
template <typename TField, unsigned int IAlignment>
|
||||||
|
struct FieldPrinter {
|
||||||
|
static std::string PrintField(const sp::Field<TField, IAlignment>& a_Field) {
|
||||||
|
return GetClassName<TField>() + "=" + PrintData(a_Field.GetValue());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <unsigned int IAlignment, typename TContainer, typename... TFields>
|
||||||
|
struct FieldPrinter<sp::BitField<TContainer, TFields...>, IAlignment> {
|
||||||
|
static std::string PrintField(const sp::Field<sp::BitField<TContainer, TFields...>, IAlignment>& a_Field) {
|
||||||
|
return "BitField<" + GetClassName<TContainer>() + ">[" + PrintFields(a_Field.GetValue().GetFields()) + "]";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename... TFields>
|
||||||
|
std::string PrintFields(const std::tuple<TFields...>& a_Fields) {
|
||||||
|
std::string concat;
|
||||||
|
TupleForEach(
|
||||||
|
[&concat](const auto& a_Field) {
|
||||||
|
using TField = typename std::decay<decltype(a_Field)>::type;
|
||||||
|
constexpr std::size_t alignment = TField::AlignmentValue;
|
||||||
|
concat += FieldPrinter<typename TField::StorageType, alignment>::PrintField(a_Field) + ", ";
|
||||||
|
},
|
||||||
|
a_Fields);
|
||||||
|
return concat.substr(0, concat.size() - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace details
|
||||||
|
} // namespace sp
|
||||||
@@ -81,7 +81,7 @@ class MessageImplFieldsReadBase : public TBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// reading field in bitfield
|
// reading field in bitfield
|
||||||
template <typename TFieldType, typename TField, int IAlignment>
|
template <typename TFieldType, typename TField, std::size_t IAlignment>
|
||||||
void ReadField(Field<TField, IAlignment>& field, TFieldType data, std::size_t offset) {
|
void ReadField(Field<TField, IAlignment>& field, TFieldType data, std::size_t offset) {
|
||||||
static constexpr std::size_t TotalBitCount = sizeof(TFieldType) * 8;
|
static constexpr std::size_t TotalBitCount = sizeof(TFieldType) * 8;
|
||||||
// we suppose that the first element is at the highest bits
|
// we suppose that the first element is at the highest bits
|
||||||
@@ -118,7 +118,7 @@ class MessageImplFieldsWriteBase : public TBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// writing field in bitfield
|
// writing field in bitfield
|
||||||
template <typename TFieldType, typename TField, int IAlignment>
|
template <typename TFieldType, typename TField, std::size_t IAlignment>
|
||||||
void WriteField(const Field<TField, IAlignment>& field, TFieldType& data, std::size_t offset) const {
|
void WriteField(const Field<TField, IAlignment>& field, TFieldType& data, std::size_t offset) const {
|
||||||
static constexpr std::size_t TotalBitCount = sizeof(TFieldType) * 8;
|
static constexpr std::size_t TotalBitCount = sizeof(TFieldType) * 8;
|
||||||
// we suppose that the first element is at the highest bits
|
// we suppose that the first element is at the highest bits
|
||||||
|
|||||||
@@ -5,10 +5,12 @@
|
|||||||
|
|
||||||
#include <sp/default/DefaultPacketDispatcher.h>
|
#include <sp/default/DefaultPacketDispatcher.h>
|
||||||
#include <sp/extensions/Extensions.h>
|
#include <sp/extensions/Extensions.h>
|
||||||
|
#include <sp/protocol/MessagePrinter.h>
|
||||||
|
|
||||||
class KeepAliveHandler : public sp::PacketHandler {
|
class KeepAliveHandler : public sp::PacketHandler {
|
||||||
void Handle(const KeepAlivePacket& packet) {
|
void Handle(const KeepAlivePacket& packet) {
|
||||||
std::cout << "KeepAlive handled !\n";
|
std::cout << "KeepAlive handled !!\n";
|
||||||
|
std::cout << packet << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Handle(const DisconnectPacket& packet) {
|
void Handle(const DisconnectPacket& packet) {
|
||||||
@@ -21,12 +23,14 @@ class KeepAliveHandler : public sp::PacketHandler {
|
|||||||
};
|
};
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
auto upgradeTower = std::make_unique<UpgradeTowerPacket>(std::make_tuple(666, 9));
|
auto upgradeTower = std::make_unique<UpgradeTowerPacket>(std::make_tuple(666, 9), 789);
|
||||||
|
auto keepAlive = std::make_unique<KeepAlivePacket>(6969);
|
||||||
|
|
||||||
sp::PacketMessage* msg = upgradeTower.get();
|
sp::PacketMessage* msg = upgradeTower.get();
|
||||||
|
|
||||||
auto handler = std::make_shared<KeepAliveHandler>();
|
auto handler = std::make_shared<KeepAliveHandler>();
|
||||||
msg->Dispatch(*handler);
|
msg->Dispatch(*handler);
|
||||||
|
keepAlive->Dispatch(*handler);
|
||||||
|
|
||||||
sp::DataBuffer buffer = msg->Write();
|
sp::DataBuffer buffer = msg->Write();
|
||||||
|
|
||||||
@@ -36,7 +40,7 @@ int main() {
|
|||||||
auto upgradeTower2 = std::make_unique<UpgradeTowerPacket>();
|
auto upgradeTower2 = std::make_unique<UpgradeTowerPacket>();
|
||||||
upgradeTower2->Read(buffer);
|
upgradeTower2->Read(buffer);
|
||||||
|
|
||||||
std::cout << "Test : " << (unsigned)upgradeTower2->GetTowerId() << "\n";
|
std::cout << "Test : " << *upgradeTower2 << "\n";
|
||||||
|
|
||||||
sp::PacketFactory factory;
|
sp::PacketFactory factory;
|
||||||
auto packet = factory.CreateMessage(msgId);
|
auto packet = factory.CreateMessage(msgId);
|
||||||
|
|||||||
Reference in New Issue
Block a user