forked from Kistler-Group/sdbus-cpp
feat: introduce support for struct-as-dict serialization (#459)
This extends the functionality of SDBUSCPP_REGISTER_STRUCT macro.
It now provides functionality for serializing a user-defined struct as an a{sv} dictionary, and for deserializing an a{sv} dictionary into a user-defined struct. The former one is achieved by decorating the struct with sdbus::as_dictionary(struct), the latter one is an automatic behavior -- when sdbus-c++ is asked to deserialize into a struct but the data in the message is of type a{sv}, then the dict-to-struct deserialization is performed automatically.
There are some aspects of behavior in the serialization/deserialization functionality that can be customized by the client. Newly introduced SDBUSCPP_ENABLE_NESTED_STRUCT2DICT_SERIALIZATION and SDBUSCPP_ENABLE_RELAXED_DICT2STRUCT_DESERIALIZATION macros serve the purpose.
This commit is contained in:
+59
-39
@@ -114,6 +114,8 @@ namespace sdbus {
|
||||
#endif
|
||||
template <typename _Enum, typename = std::enable_if_t<std::is_enum_v<_Enum>>>
|
||||
Message& operator<<(const _Enum& item);
|
||||
template <typename _Key, typename _Value>
|
||||
Message& operator<<(const DictEntry<_Key, _Value>& value);
|
||||
template <typename _Key, typename _Value, typename _Compare, typename _Allocator>
|
||||
Message& operator<<(const std::map<_Key, _Value, _Compare, _Allocator>& items);
|
||||
template <typename _Key, typename _Value, typename _Hash, typename _KeyEqual, typename _Allocator>
|
||||
@@ -150,6 +152,8 @@ namespace sdbus {
|
||||
#endif
|
||||
template <typename _Enum, typename = std::enable_if_t<std::is_enum_v<_Enum>>>
|
||||
Message& operator>>(_Enum& item);
|
||||
template <typename _Key, typename _Value>
|
||||
Message& operator>>(DictEntry<_Key, _Value>& value);
|
||||
template <typename _Key, typename _Value, typename _Compare, typename _Allocator>
|
||||
Message& operator>>(std::map<_Key, _Value, _Compare, _Allocator>& items);
|
||||
template <typename _Key, typename _Value, typename _Hash, typename _KeyEqual, typename _Allocator>
|
||||
@@ -196,6 +200,13 @@ namespace sdbus {
|
||||
Message& appendArray(char type, const void *ptr, size_t size);
|
||||
Message& readArray(char type, const void **ptr, size_t *size);
|
||||
|
||||
template <typename _Key, typename _Value, typename _Callback>
|
||||
Message& serializeDictionary(const _Callback& callback);
|
||||
template <typename _Key, typename _Value>
|
||||
Message& serializeDictionary(const std::initializer_list<DictEntry<_Key, _Value>>& dictEntries);
|
||||
template <typename _Key, typename _Value, typename _Callback>
|
||||
Message& deserializeDictionary(const _Callback& callback);
|
||||
|
||||
explicit operator bool() const;
|
||||
void clearFlags();
|
||||
|
||||
@@ -238,11 +249,6 @@ namespace sdbus {
|
||||
template <typename _Element, typename _Allocator>
|
||||
void deserializeArraySlow(std::vector<_Element, _Allocator>& items);
|
||||
|
||||
template <typename _Dictionary>
|
||||
void serializeDictionary(const _Dictionary& items);
|
||||
template <typename _Dictionary>
|
||||
void deserializeDictionary(_Dictionary& items);
|
||||
|
||||
protected:
|
||||
Message() = default;
|
||||
explicit Message(internal::IConnection* connection) noexcept;
|
||||
@@ -402,10 +408,21 @@ namespace sdbus {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename _Key, typename _Value>
|
||||
inline Message& Message::operator<<(const DictEntry<_Key, _Value>& value)
|
||||
{
|
||||
openDictEntry<_Key, _Value>();
|
||||
*this << value.first;
|
||||
*this << value.second;
|
||||
closeDictEntry();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename _Key, typename _Value, typename _Compare, typename _Allocator>
|
||||
inline Message& Message::operator<<(const std::map<_Key, _Value, _Compare, _Allocator>& items)
|
||||
{
|
||||
serializeDictionary(items);
|
||||
serializeDictionary<_Key, _Value>([&items](Message& msg){ for (const auto& item : items) msg << item; });
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -413,28 +430,27 @@ namespace sdbus {
|
||||
template <typename _Key, typename _Value, typename _Hash, typename _KeyEqual, typename _Allocator>
|
||||
inline Message& Message::operator<<(const std::unordered_map<_Key, _Value, _Hash, _KeyEqual, _Allocator>& items)
|
||||
{
|
||||
serializeDictionary(items);
|
||||
serializeDictionary<_Key, _Value>([&items](Message& msg){ for (const auto& item : items) msg << item; });
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename _Dictionary>
|
||||
inline void Message::serializeDictionary(const _Dictionary& items)
|
||||
template <typename _Key, typename _Value>
|
||||
inline Message& Message::serializeDictionary(const std::initializer_list<DictEntry<_Key, _Value>>& items)
|
||||
{
|
||||
using KeyType = typename _Dictionary::key_type;
|
||||
using MappedType = typename _Dictionary::mapped_type;
|
||||
serializeDictionary<_Key, _Value>([&](Message& msg){ for (const auto& item : items) msg << item; });
|
||||
|
||||
openContainer<DictEntry<KeyType, MappedType>>();
|
||||
|
||||
for (const auto& item : items)
|
||||
{
|
||||
openDictEntry<KeyType, MappedType>();
|
||||
*this << item.first;
|
||||
*this << item.second;
|
||||
closeDictEntry();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename _Key, typename _Value, typename _Callback>
|
||||
inline Message& Message::serializeDictionary(const _Callback& callback)
|
||||
{
|
||||
openContainer<DictEntry<_Key, _Value>>();
|
||||
callback(*this);
|
||||
closeContainer();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
namespace detail
|
||||
@@ -619,10 +635,21 @@ namespace sdbus {
|
||||
exitContainer();
|
||||
}
|
||||
|
||||
template <typename _Key, typename _Value>
|
||||
inline Message& Message::operator>>(DictEntry<_Key, _Value>& value)
|
||||
{
|
||||
if (!enterDictEntry<_Key, _Value>())
|
||||
return *this;
|
||||
*this >> value.first >> value.second;
|
||||
exitDictEntry();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename _Key, typename _Value, typename _Compare, typename _Allocator>
|
||||
inline Message& Message::operator>>(std::map<_Key, _Value, _Compare, _Allocator>& items)
|
||||
{
|
||||
deserializeDictionary(items);
|
||||
deserializeDictionary<_Key, _Value>([&items](auto dictEntry){ items.insert(std::move(dictEntry)); });
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -630,37 +657,30 @@ namespace sdbus {
|
||||
template <typename _Key, typename _Value, typename _Hash, typename _KeyEqual, typename _Allocator>
|
||||
inline Message& Message::operator>>(std::unordered_map<_Key, _Value, _Hash, _KeyEqual, _Allocator>& items)
|
||||
{
|
||||
deserializeDictionary(items);
|
||||
deserializeDictionary<_Key, _Value>([&items](auto dictEntry){ items.insert(std::move(dictEntry)); });
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename _Dictionary>
|
||||
inline void Message::deserializeDictionary(_Dictionary& items)
|
||||
template <typename _Key, typename _Value, typename _Callback>
|
||||
inline Message& Message::deserializeDictionary(const _Callback& callback)
|
||||
{
|
||||
using KeyType = typename _Dictionary::key_type;
|
||||
using MappedType = typename _Dictionary::mapped_type;
|
||||
|
||||
if (!enterContainer<DictEntry<KeyType, MappedType>>())
|
||||
return;
|
||||
if (!enterContainer<DictEntry<_Key, _Value>>())
|
||||
return *this;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (!enterDictEntry<KeyType, MappedType>())
|
||||
DictEntry<_Key, _Value> dictEntry;
|
||||
*this >> dictEntry;
|
||||
if (!*this)
|
||||
break;
|
||||
|
||||
KeyType key;
|
||||
MappedType value;
|
||||
*this >> key >> value;
|
||||
|
||||
items.emplace(std::move(key), std::move(value));
|
||||
|
||||
exitDictEntry();
|
||||
callback(std::move(dictEntry));
|
||||
}
|
||||
|
||||
clearFlags();
|
||||
|
||||
exitContainer();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
namespace detail
|
||||
|
||||
@@ -273,6 +273,7 @@ namespace sdbus {
|
||||
{
|
||||
static constexpr std::array contents = (signature_of_v<_ValueTypes> + ...);
|
||||
static constexpr std::array value = std::array{'('} + contents + std::array{')'};
|
||||
static constexpr char type_value{'r'}; /* Not actually used in signatures on D-Bus, see specs */
|
||||
static constexpr bool is_valid = true;
|
||||
static constexpr bool is_trivial_dbus_type = false;
|
||||
};
|
||||
@@ -317,6 +318,7 @@ namespace sdbus {
|
||||
struct signature_of<DictEntry<_T1, _T2>>
|
||||
{
|
||||
static constexpr std::array value = std::array{'{'} + signature_of_v<std::tuple<_T1, _T2>> + std::array{'}'};
|
||||
static constexpr char type_value{'e'}; /* Not actually used in signatures on D-Bus, see specs */
|
||||
static constexpr bool is_valid = true;
|
||||
static constexpr bool is_trivial_dbus_type = false;
|
||||
};
|
||||
@@ -349,9 +351,7 @@ namespace sdbus {
|
||||
template <typename _Key, typename _Value, typename _Compare, typename _Allocator>
|
||||
struct signature_of<std::map<_Key, _Value, _Compare, _Allocator>>
|
||||
{
|
||||
static constexpr std::array contents = signature_of_v<std::tuple<_Key, _Value>>;
|
||||
static constexpr std::array dict_entry = std::array{'{'} + contents + std::array{'}'};
|
||||
static constexpr std::array value = std::array{'a'} + dict_entry;
|
||||
static constexpr std::array value = std::array{'a'} + signature_of_v<DictEntry<_Key, _Value>>;
|
||||
static constexpr bool is_valid = true;
|
||||
static constexpr bool is_trivial_dbus_type = false;
|
||||
};
|
||||
@@ -575,6 +575,36 @@ namespace sdbus {
|
||||
constexpr bool is_one_of_variants_types<std::variant<_VariantTypes...>, _QueriedType>
|
||||
= (std::is_same_v<_QueriedType, _VariantTypes> || ...);
|
||||
|
||||
// Wrapper (tag) denoting we want to serialize user-defined struct
|
||||
// into a D-Bus message as a dictionary of strings to variants.
|
||||
template <typename _Struct>
|
||||
struct as_dictionary
|
||||
{
|
||||
explicit as_dictionary(const _Struct& s) : m_struct(s) {}
|
||||
const _Struct& m_struct;
|
||||
};
|
||||
|
||||
template <typename _Type>
|
||||
const _Type& as_dictionary_if_struct(const _Type& object)
|
||||
{
|
||||
return object; // identity in case _Type is not struct (user-defined structs shall provide an overload)
|
||||
}
|
||||
|
||||
// By default, the dict-as-struct deserialization strategy is strict.
|
||||
// Strict means that every key of the deserialized dictionary must have its counterpart member in the struct, otherwise an exception is thrown.
|
||||
// Relaxed means that a key that does not have a matching struct member is silently ignored.
|
||||
// The behavior can be overridden for user-defined struct by specializing this variable template.
|
||||
template <typename _Struct>
|
||||
constexpr auto strict_dict_as_struct_deserialization_v = true;
|
||||
|
||||
// By default, the struct-as-dict serialization strategy is single-level only (as opposed to nested).
|
||||
// Single-level means that only the specific struct is serialized as a dictionary, serializing members that are structs always as structs.
|
||||
// Nested means that the struct *and* its members that are structs are all serialized as a dictionary. If nested strategy is also
|
||||
// defined for the nested struct, then the same behavior applies for that struct, recursively.
|
||||
// The behavior can be overridden for user-defined struct by specializing this variable template.
|
||||
template <typename _Struct>
|
||||
constexpr auto nested_struct_as_dict_serialization_v = false;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <class _Function, class _Tuple, typename... _Args, std::size_t... _I>
|
||||
|
||||
+142
-59
@@ -31,6 +31,7 @@
|
||||
#include <sdbus-c++/TypeTraits.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
@@ -66,6 +67,15 @@ namespace sdbus {
|
||||
msg_.seal();
|
||||
}
|
||||
|
||||
template <typename _Struct>
|
||||
explicit Variant(const as_dictionary<_Struct>& value) : Variant()
|
||||
{
|
||||
msg_.openVariant<std::map<std::string, Variant>>();
|
||||
msg_ << as_dictionary(value.m_struct);
|
||||
msg_.closeVariant();
|
||||
msg_.seal();
|
||||
}
|
||||
|
||||
template <typename... _Elements>
|
||||
Variant(const std::variant<_Elements...>& value)
|
||||
: Variant()
|
||||
@@ -77,10 +87,10 @@ namespace sdbus {
|
||||
template <typename _ValueType>
|
||||
_ValueType get() const
|
||||
{
|
||||
_ValueType val;
|
||||
msg_.rewind(false);
|
||||
|
||||
msg_.enterVariant<_ValueType>();
|
||||
_ValueType val;
|
||||
msg_ >> val;
|
||||
msg_.exitVariant();
|
||||
return val;
|
||||
@@ -405,6 +415,9 @@ struct std::tuple_size<sdbus::Struct<_ValueTypes...>>
|
||||
* clients to use their struct conveniently instead of the (too
|
||||
* generic and less expressive) `sdbus::Struct<...>` in sdbus-c++ API.
|
||||
*
|
||||
* It also enables to serialize a user-defined struct as an a{sv} dictionary,
|
||||
* and to deserialize an a{sv} dictionary into the user-defined struct.
|
||||
*
|
||||
* The first argument is the struct type name and the remaining arguments
|
||||
* are names of struct members. Members must be of types supported by
|
||||
* sdbus-c++ (or of user-defined types that sdbus-c++ was taught to support).
|
||||
@@ -426,31 +439,96 @@ struct std::tuple_size<sdbus::Struct<_ValueTypes...>>
|
||||
*
|
||||
* SDBUSCPP_REGISTER_STRUCT(foo::ABC, number, name, data);
|
||||
*
|
||||
* The macro effectively generates the `sdbus::Message` serialization
|
||||
* and deserialization operators and the `sdbus::signature_of`
|
||||
* specialization for `foo::ABC`.
|
||||
*
|
||||
* Up to 16 struct members are supported by the macro.
|
||||
*
|
||||
***********************************************/
|
||||
#define SDBUSCPP_REGISTER_STRUCT(STRUCT, ...) \
|
||||
namespace sdbus { \
|
||||
static_assert(SDBUSCPP_PP_NARG(__VA_ARGS__) <= 16, \
|
||||
"Not more than 16 struct members are supported, please open an issue if you need more"); \
|
||||
inline sdbus::Message& operator<<(sdbus::Message& msg, const STRUCT& items) \
|
||||
{ \
|
||||
return msg << sdbus::Struct{std::forward_as_tuple(SDBUSCPP_STRUCT_MEMBERS(items, __VA_ARGS__))}; \
|
||||
} \
|
||||
inline sdbus::Message& operator>>(sdbus::Message& msg, STRUCT& items) \
|
||||
{ \
|
||||
sdbus::Struct s{std::forward_as_tuple(SDBUSCPP_STRUCT_MEMBERS(items, __VA_ARGS__))}; \
|
||||
return msg >> s; \
|
||||
} \
|
||||
template <> \
|
||||
struct signature_of<STRUCT> \
|
||||
: signature_of<sdbus::Struct<SDBUSCPP_STRUCT_MEMBER_TYPES(STRUCT, __VA_ARGS__)>> \
|
||||
{}; \
|
||||
} \
|
||||
#define SDBUSCPP_REGISTER_STRUCT(STRUCT, ...) \
|
||||
namespace sdbus { \
|
||||
static_assert(SDBUSCPP_PP_NARG(__VA_ARGS__) <= 16, \
|
||||
"Not more than 16 struct members are supported, please open an issue if you need more"); \
|
||||
\
|
||||
template <> \
|
||||
struct signature_of<STRUCT> \
|
||||
: signature_of<sdbus::Struct<SDBUSCPP_STRUCT_MEMBER_TYPES(STRUCT, __VA_ARGS__)>> \
|
||||
{}; \
|
||||
\
|
||||
inline auto as_dictionary_if_struct(const STRUCT& object) \
|
||||
{ \
|
||||
return as_dictionary<STRUCT>(object); \
|
||||
} \
|
||||
\
|
||||
inline sdbus::Message& operator<<(sdbus::Message& msg, const STRUCT& items) \
|
||||
{ \
|
||||
return msg << sdbus::Struct{std::forward_as_tuple(SDBUSCPP_STRUCT_MEMBERS(items, __VA_ARGS__))}; \
|
||||
} \
|
||||
\
|
||||
inline Message& operator<<(Message& msg, const as_dictionary<STRUCT>& s) \
|
||||
{ \
|
||||
if constexpr (!nested_struct_as_dict_serialization_v<STRUCT>) \
|
||||
return msg.serializeDictionary<std::string, Variant>({SDBUSCPP_STRUCT_MEMBERS_AS_DICT_ENTRIES(s.m_struct, __VA_ARGS__)}); \
|
||||
else \
|
||||
return msg.serializeDictionary<std::string, Variant>({SDBUSCPP_STRUCT_MEMBERS_AS_NESTED_DICT_ENTRIES(s.m_struct, __VA_ARGS__)}); \
|
||||
} \
|
||||
\
|
||||
inline Message& operator>>(Message& msg, STRUCT& s) \
|
||||
{ \
|
||||
/* First, try to deserialize as a struct */ \
|
||||
if (msg.peekType().first == signature_of<STRUCT>::type_value) \
|
||||
{ \
|
||||
Struct sdbusStruct{std::forward_as_tuple(SDBUSCPP_STRUCT_MEMBERS(s, __VA_ARGS__))}; \
|
||||
return msg >> sdbusStruct; \
|
||||
} \
|
||||
\
|
||||
/* Otherwise try to deserialize as a dictionary of strings to variants */ \
|
||||
\
|
||||
return msg.deserializeDictionary<std::string, Variant>([&s](const auto& dictEntry) \
|
||||
{ \
|
||||
const std::string& key = dictEntry.first; /* Intentionally not using structured bindings */ \
|
||||
const Variant& value = dictEntry.second; \
|
||||
\
|
||||
using namespace std::string_literals; \
|
||||
/* This also handles members which are structs serialized as dict of strings to variants, recursively */ \
|
||||
SDBUSCPP_FIND_AND_DESERIALIZE_STRUCT_MEMBERS(s, __VA_ARGS__) \
|
||||
SDBUS_THROW_ERROR_IF( strict_dict_as_struct_deserialization_v<STRUCT> \
|
||||
, ("Failed to deserialize struct from a dictionary: could not find field '"s += key) += "' in struct 'my::Struct'" \
|
||||
, EINVAL ); \
|
||||
}); \
|
||||
} \
|
||||
} \
|
||||
/**/
|
||||
|
||||
/********************************************//**
|
||||
* @name SDBUSCPP_ENABLE_RELAXED_DICT2STRUCT_DESERIALIZATION
|
||||
*
|
||||
* Enables relaxed deserialization of an a{sv} dictionary into a user-defined struct STRUCT.
|
||||
*
|
||||
* The default (strict) deserialization mode is that if there are entries in the dictionary
|
||||
* which do not have a corresponding field in the struct, an exception is thrown.
|
||||
* In the relaxed mode, such entries are silently skipped.
|
||||
*
|
||||
* The macro can only be used in combination with SDBUSCPP_REGISTER_STRUCT macro,
|
||||
* and must be placed before SDBUSCPP_REGISTER_STRUCT macro.
|
||||
***********************************************/
|
||||
#define SDBUSCPP_ENABLE_RELAXED_DICT2STRUCT_DESERIALIZATION(STRUCT) \
|
||||
template <> \
|
||||
constexpr auto sdbus::strict_dict_as_struct_deserialization_v<STRUCT> = false; \
|
||||
/**/
|
||||
|
||||
/********************************************//**
|
||||
* @name SDBUSCPP_ENABLE_NESTED_STRUCT2DICT_SERIALIZATION
|
||||
*
|
||||
* Enables nested serialization of user-defined struct STRUCT as an a{sv} dictionary.
|
||||
*
|
||||
* By default, STRUCT fields which are structs themselves are serialized as D-Bus structs.
|
||||
* This macro tells sdbus-c++ to also serialize nested structs, in a recursive fashion,
|
||||
* as a{sv} dictionaries.
|
||||
*
|
||||
* The macro can only be used in combination with SDBUSCPP_REGISTER_STRUCT macro,
|
||||
* and must be placed before SDBUSCPP_REGISTER_STRUCT macro.
|
||||
***********************************************/
|
||||
#define SDBUSCPP_ENABLE_NESTED_STRUCT2DICT_SERIALIZATION(STRUCT) \
|
||||
template <> \
|
||||
constexpr auto sdbus::nested_struct_as_dict_serialization_v<STRUCT> = true \
|
||||
/**/
|
||||
|
||||
/*!
|
||||
@@ -458,49 +536,54 @@ struct std::tuple_size<sdbus::Struct<_ValueTypes...>>
|
||||
*
|
||||
* Internal helper preprocessor facilities
|
||||
*/
|
||||
#define SDBUSCPP_STRUCT_MEMBERS(STRUCT, ...) \
|
||||
SDBUSCPP_PP_CAT(SDBUSCPP_STRUCT_MEMBERS_, SDBUSCPP_PP_NARG(__VA_ARGS__))(STRUCT, __VA_ARGS__) \
|
||||
#define SDBUSCPP_STRUCT_MEMBERS(STRUCT, ...) \
|
||||
SDBUSCPP_PP_CAT(SDBUSCPP_FOR_EACH_, SDBUSCPP_PP_NARG(__VA_ARGS__))(SDBUSCPP_STRUCT_MEMBER, SDBUSCPP_PP_COMMA, STRUCT, __VA_ARGS__) \
|
||||
/**/
|
||||
#define SDBUSCPP_STRUCT_MEMBERS_1(S, M1) S.M1
|
||||
#define SDBUSCPP_STRUCT_MEMBERS_2(S, M1, M2) S.M1, S.M2
|
||||
#define SDBUSCPP_STRUCT_MEMBERS_3(S, M1, M2, M3) S.M1, S.M2, S.M3
|
||||
#define SDBUSCPP_STRUCT_MEMBERS_4(S, M1, M2, M3, M4) S.M1, S.M2, S.M3, S.M4
|
||||
#define SDBUSCPP_STRUCT_MEMBERS_5(S, M1, M2, M3, M4, M5) S.M1, S.M2, S.M3, S.M4, S.M5
|
||||
#define SDBUSCPP_STRUCT_MEMBERS_6(S, M1, M2, M3, M4, M5, M6) S.M1, S.M2, S.M3, S.M4, S.M5, S.M6
|
||||
#define SDBUSCPP_STRUCT_MEMBERS_7(S, M1, M2, M3, M4, M5, M6, M7) S.M1, S.M2, S.M3, S.M4, S.M5, S.M6, S.M7
|
||||
#define SDBUSCPP_STRUCT_MEMBERS_8(S, M1, M2, M3, M4, M5, M6, M7, M8) S.M1, S.M2, S.M3, S.M4, S.M5, S.M6, S.M7, S.M8
|
||||
#define SDBUSCPP_STRUCT_MEMBERS_9(S, M1, M2, M3, M4, M5, M6, M7, M8, M9) S.M1, S.M2, S.M3, S.M4, S.M5, S.M6, S.M7, S.M8, S.M9
|
||||
#define SDBUSCPP_STRUCT_MEMBERS_10(S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10) S.M1, S.M2, S.M3, S.M4, S.M5, S.M6, S.M7, S.M8, S.M9, S.M10
|
||||
#define SDBUSCPP_STRUCT_MEMBERS_11(S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11) S.M1, S.M2, S.M3, S.M4, S.M5, S.M6, S.M7, S.M8, S.M9, S.M10, S.M11
|
||||
#define SDBUSCPP_STRUCT_MEMBERS_12(S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12) S.M1, S.M2, S.M3, S.M4, S.M5, S.M6, S.M7, S.M8, S.M9, S.M10, S.M11, S.M12
|
||||
#define SDBUSCPP_STRUCT_MEMBERS_13(S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13) S.M1, S.M2, S.M3, S.M4, S.M5, S.M6, S.M7, S.M8, S.M9, S.M10, S.M11, S.M12, S.M13
|
||||
#define SDBUSCPP_STRUCT_MEMBERS_14(S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13, M14) S.M1, S.M2, S.M3, S.M4, S.M5, S.M6, S.M7, S.M8, S.M9, S.M10, S.M11, S.M12, S.M13, S.M14
|
||||
#define SDBUSCPP_STRUCT_MEMBERS_15(S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13, M14, M15) S.M1, S.M2, S.M3, S.M4, S.M5, S.M6, S.M7, S.M8, S.M9, S.M10, S.M11, S.M12, S.M13, S.M14, S.M15
|
||||
#define SDBUSCPP_STRUCT_MEMBERS_16(S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13, M14, M15, M16) S.M1, S.M2, S.M3, S.M4, S.M5, S.M6, S.M7, S.M8, S.M9, S.M10, S.M11, S.M12, S.M13, S.M14, S.M15, S.M16
|
||||
#define SDBUSCPP_STRUCT_MEMBER(STRUCT, MEMBER) STRUCT.MEMBER
|
||||
|
||||
#define SDBUSCPP_STRUCT_MEMBER_TYPES(STRUCT, ...) \
|
||||
SDBUSCPP_PP_CAT(SDBUSCPP_STRUCT_MEMBER_TYPES_, SDBUSCPP_PP_NARG(__VA_ARGS__))(STRUCT, __VA_ARGS__) \
|
||||
#define SDBUSCPP_STRUCT_MEMBER_TYPES(STRUCT, ...) \
|
||||
SDBUSCPP_PP_CAT(SDBUSCPP_FOR_EACH_, SDBUSCPP_PP_NARG(__VA_ARGS__))(SDBUSCPP_STRUCT_MEMBER_TYPE, SDBUSCPP_PP_COMMA, STRUCT, __VA_ARGS__) \
|
||||
/**/
|
||||
#define SDBUSCPP_STRUCT_MEMBER_TYPES_1(S, M1) decltype(S::M1)
|
||||
#define SDBUSCPP_STRUCT_MEMBER_TYPES_2(S, M1, M2) decltype(S::M1), decltype(S::M2)
|
||||
#define SDBUSCPP_STRUCT_MEMBER_TYPES_3(S, M1, M2, M3) decltype(S::M1), decltype(S::M2), decltype(S::M3)
|
||||
#define SDBUSCPP_STRUCT_MEMBER_TYPES_4(S, M1, M2, M3, M4) decltype(S::M1), decltype(S::M2), decltype(S::M3), decltype(S::M4)
|
||||
#define SDBUSCPP_STRUCT_MEMBER_TYPES_5(S, M1, M2, M3, M4, M5) decltype(S::M1), decltype(S::M2), decltype(S::M3), decltype(S::M4), decltype(S::M5)
|
||||
#define SDBUSCPP_STRUCT_MEMBER_TYPES_6(S, M1, M2, M3, M4, M5, M6) decltype(S::M1), decltype(S::M2), decltype(S::M3), decltype(S::M4), decltype(S::M5), decltype(S::M6)
|
||||
#define SDBUSCPP_STRUCT_MEMBER_TYPES_7(S, M1, M2, M3, M4, M5, M6, M7) decltype(S::M1), decltype(S::M2), decltype(S::M3), decltype(S::M4), decltype(S::M5), decltype(S::M6), decltype(S::M7)
|
||||
#define SDBUSCPP_STRUCT_MEMBER_TYPES_8(S, M1, M2, M3, M4, M5, M6, M7, M8) decltype(S::M1), decltype(S::M2), decltype(S::M3), decltype(S::M4), decltype(S::M5), decltype(S::M6), decltype(S::M7), decltype(S::M8)
|
||||
#define SDBUSCPP_STRUCT_MEMBER_TYPES_9(S, M1, M2, M3, M4, M5, M6, M7, M8, M9) decltype(S::M1), decltype(S::M2), decltype(S::M3), decltype(S::M4), decltype(S::M5), decltype(S::M6), decltype(S::M7), decltype(S::M8), decltype(S::M9)
|
||||
#define SDBUSCPP_STRUCT_MEMBER_TYPES_10(S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10) decltype(S::M1), decltype(S::M2), decltype(S::M3), decltype(S::M4), decltype(S::M5), decltype(S::M6), decltype(S::M7), decltype(S::M8), decltype(S::M9), decltype(S::M10)
|
||||
#define SDBUSCPP_STRUCT_MEMBER_TYPES_11(S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11) decltype(S::M1), decltype(S::M2), decltype(S::M3), decltype(S::M4), decltype(S::M5), decltype(S::M6), decltype(S::M7), decltype(S::M8), decltype(S::M9), decltype(S::M10), decltype(S::M11)
|
||||
#define SDBUSCPP_STRUCT_MEMBER_TYPES_12(S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12) decltype(S::M1), decltype(S::M2), decltype(S::M3), decltype(S::M4), decltype(S::M5), decltype(S::M6), decltype(S::M7), decltype(S::M8), decltype(S::M9), decltype(S::M10), decltype(S::M11), decltype(S::M12)
|
||||
#define SDBUSCPP_STRUCT_MEMBER_TYPES_13(S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13) decltype(S::M1), decltype(S::M2), decltype(S::M3), decltype(S::M4), decltype(S::M5), decltype(S::M6), decltype(S::M7), decltype(S::M8), decltype(S::M9), decltype(S::M10), decltype(S::M11), decltype(S::M12), decltype(S::M13)
|
||||
#define SDBUSCPP_STRUCT_MEMBER_TYPES_14(S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13, M14) decltype(S::M1), decltype(S::M2), decltype(S::M3), decltype(S::M4), decltype(S::M5), decltype(S::M6), decltype(S::M7), decltype(S::M8), decltype(S::M9), decltype(S::M10), decltype(S::M11), decltype(S::M12), decltype(S::M13), decltype(S::M14)
|
||||
#define SDBUSCPP_STRUCT_MEMBER_TYPES_15(S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13, M14, M15) decltype(S::M1), decltype(S::M2), decltype(S::M3), decltype(S::M4), decltype(S::M5), decltype(S::M6), decltype(S::M7), decltype(S::M8), decltype(S::M9), decltype(S::M10), decltype(S::M11), decltype(S::M12), decltype(S::M13), decltype(S::M14), decltype(S::M15)
|
||||
#define SDBUSCPP_STRUCT_MEMBER_TYPES_16(S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13, M14, M15, M16) decltype(S::M1), decltype(S::M2), decltype(S::M3), decltype(S::M4), decltype(S::M5), decltype(S::M6), decltype(S::M7), decltype(S::M8), decltype(S::M9), decltype(S::M10), decltype(S::M11), decltype(S::M12), decltype(S::M13), decltype(S::M14), decltype(S::M15), decltype(S::M16)
|
||||
#define SDBUSCPP_STRUCT_MEMBER_TYPE(STRUCT, MEMBER) decltype(STRUCT::MEMBER)
|
||||
|
||||
#define SDBUSCPP_STRUCT_MEMBERS_AS_DICT_ENTRIES(STRUCT, ...) \
|
||||
SDBUSCPP_PP_CAT(SDBUSCPP_FOR_EACH_, SDBUSCPP_PP_NARG(__VA_ARGS__))(SDBUSCPP_STRUCT_MEMBER_AS_DICT_ENTRY, SDBUSCPP_PP_COMMA, STRUCT, __VA_ARGS__) \
|
||||
/**/
|
||||
#define SDBUSCPP_STRUCT_MEMBER_AS_DICT_ENTRY(STRUCT, MEMBER) {#MEMBER, Variant{STRUCT.MEMBER}}
|
||||
|
||||
#define SDBUSCPP_STRUCT_MEMBERS_AS_NESTED_DICT_ENTRIES(STRUCT, ...) \
|
||||
SDBUSCPP_PP_CAT(SDBUSCPP_FOR_EACH_, SDBUSCPP_PP_NARG(__VA_ARGS__))(SDBUSCPP_STRUCT_MEMBER_AS_NESTED_DICT_ENTRY, SDBUSCPP_PP_COMMA, STRUCT, __VA_ARGS__) \
|
||||
/**/
|
||||
#define SDBUSCPP_STRUCT_MEMBER_AS_NESTED_DICT_ENTRY(STRUCT, MEMBER) {#MEMBER, Variant{as_dictionary_if_struct(STRUCT.MEMBER)}}
|
||||
|
||||
#define SDBUSCPP_FIND_AND_DESERIALIZE_STRUCT_MEMBERS(STRUCT, ...) \
|
||||
SDBUSCPP_PP_CAT(SDBUSCPP_FOR_EACH_, SDBUSCPP_PP_NARG(__VA_ARGS__))(SDBUSCPP_FIND_AND_DESERIALIZE_STRUCT_MEMBER, SDBUSCPP_PP_SPACE, STRUCT, __VA_ARGS__) \
|
||||
/**/
|
||||
#define SDBUSCPP_FIND_AND_DESERIALIZE_STRUCT_MEMBER(STRUCT, MEMBER) if (key == #MEMBER) STRUCT.MEMBER = value.get<decltype(STRUCT.MEMBER)>(); else
|
||||
|
||||
#define SDBUSCPP_FOR_EACH_1(M, D, S, M1) M(S, M1)
|
||||
#define SDBUSCPP_FOR_EACH_2(M, D, S, M1, M2) M(S, M1) D M(S, M2)
|
||||
#define SDBUSCPP_FOR_EACH_3(M, D, S, M1, M2, M3) M(S, M1) D M(S, M2) D M(S, M3)
|
||||
#define SDBUSCPP_FOR_EACH_4(M, D, S, M1, M2, M3, M4) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4)
|
||||
#define SDBUSCPP_FOR_EACH_5(M, D, S, M1, M2, M3, M4, M5) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5)
|
||||
#define SDBUSCPP_FOR_EACH_6(M, D, S, M1, M2, M3, M4, M5, M6) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6)
|
||||
#define SDBUSCPP_FOR_EACH_7(M, D, S, M1, M2, M3, M4, M5, M6, M7) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7)
|
||||
#define SDBUSCPP_FOR_EACH_8(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8)
|
||||
#define SDBUSCPP_FOR_EACH_9(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8, M9) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) D M(S, M9)
|
||||
#define SDBUSCPP_FOR_EACH_10(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) D M(S, M9) D M(S, M10)
|
||||
#define SDBUSCPP_FOR_EACH_11(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) D M(S, M9) D M(S, M10) D M(S, M11)
|
||||
#define SDBUSCPP_FOR_EACH_12(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) D M(S, M9) D M(S, M10) D M(S, M11) D M(S, M12)
|
||||
#define SDBUSCPP_FOR_EACH_13(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) D M(S, M9) D M(S, M10) D M(S, M11) D M(S, M12) D M(S, M13)
|
||||
#define SDBUSCPP_FOR_EACH_14(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13, M14) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) D M(S, M9) D M(S, M10) D M(S, M11) D M(S, M12) D M(S, M13) D M(S, M14)
|
||||
#define SDBUSCPP_FOR_EACH_15(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13, M14, M15) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) D M(S, M9) D M(S, M10) D M(S, M11) D M(S, M12) D M(S, M13) D M(S, M14) D M(S, M15)
|
||||
#define SDBUSCPP_FOR_EACH_16(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13, M14, M15, M16) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) D M(S, M9) D M(S, M10) D M(S, M11) D M(S, M12) D M(S, M13) D M(S, M14) D M(S, M15) D M(S, M16)
|
||||
|
||||
#define SDBUSCPP_PP_CAT(X, Y) SDBUSCPP_PP_CAT_IMPL(X, Y)
|
||||
#define SDBUSCPP_PP_CAT_IMPL(X, Y) X##Y
|
||||
#define SDBUSCPP_PP_NARG(...) SDBUSCPP_PP_NARG_IMPL(__VA_ARGS__, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
|
||||
#define SDBUSCPP_PP_NARG_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _N, ...) _N
|
||||
|
||||
#define SDBUSCPP_PP_COMMA ,
|
||||
#define SDBUSCPP_PP_SPACE
|
||||
|
||||
#endif /* SDBUS_CXX_TYPES_H_ */
|
||||
|
||||
Reference in New Issue
Block a user