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:
Stanislav Angelovič authored and GitHub committed 2024-11-20 23:25:13 +01:00
1 parent 8a117f8b42
commit 02ca7212d1
9 files changed
+501 -136

No files matched your search

+59 -39
View File
@@ -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