mirror of
https://github.com/Kistler-Group/sdbus-cpp.git
synced 2025-07-29 17:47:18 +02:00
feat: add support for std::variant as D-Bus variant representation (#415)
Signed-off-by: Anthony Brandon <anthony@amarulasolutions.com> Co-authored-by: Stanislav Angelovič <stanislav.angelovic@protonmail.com>
This commit is contained in:
@ -1516,7 +1516,7 @@ sdbus-c++ provides many default, pre-defined C++ type representations for D-Bus
|
||||
| string-like, basic | 103 | g | SIGNATURE | `sdbus::Signature` |
|
||||
| container | 97 | a | ARRAY | `std::vector<T>`, `std::array<T>`, `std::span<T>` - if used as an array followed by a single complete type `T` <br /> `std::map<T1, T2>`, `std::unordered_map<T1, T2>` - if used as an array of dict entries |
|
||||
| container | 114,40,41 | r() | STRUCT | `sdbus::Struct<T1, T2, ...>` variadic class template |
|
||||
| container | 118 | v | VARIANT | `sdbus::Variant` |
|
||||
| container | 118 | v | VARIANT | `sdbus::Variant`, `std::variant<T1, ...>` |
|
||||
| container | 101,123,125 | e{} | DICT_ENTRY | - |
|
||||
| fixed, basic | 104 | h | UNIX_FD | `sdbus::UnixFd` |
|
||||
| reserved | 109 | m | (reserved) | - |
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include <functional>
|
||||
#include <sys/types.h>
|
||||
#include <algorithm>
|
||||
#include <variant>
|
||||
|
||||
// Forward declarations
|
||||
namespace sdbus {
|
||||
@ -89,10 +90,11 @@ namespace sdbus {
|
||||
Message& operator<<(const char *item);
|
||||
Message& operator<<(const std::string &item);
|
||||
Message& operator<<(const Variant &item);
|
||||
template <typename ...Elements>
|
||||
Message& operator<<(const std::variant<Elements...>& value);
|
||||
Message& operator<<(const ObjectPath &item);
|
||||
Message& operator<<(const Signature &item);
|
||||
Message& operator<<(const UnixFd &item);
|
||||
|
||||
template <typename _Element, typename _Allocator>
|
||||
Message& operator<<(const std::vector<_Element, _Allocator>& items);
|
||||
template <typename _Element, std::size_t _Size>
|
||||
@ -124,6 +126,8 @@ namespace sdbus {
|
||||
Message& operator>>(char*& item);
|
||||
Message& operator>>(std::string &item);
|
||||
Message& operator>>(Variant &item);
|
||||
template <typename ...Elements>
|
||||
Message& operator>>(std::variant<Elements...>& value);
|
||||
Message& operator>>(ObjectPath &item);
|
||||
Message& operator>>(Signature &item);
|
||||
Message& operator>>(UnixFd &item);
|
||||
@ -311,6 +315,18 @@ namespace sdbus {
|
||||
PlainMessage() = default;
|
||||
};
|
||||
|
||||
template <typename ...Elements>
|
||||
inline Message& Message::operator<<(const std::variant<Elements...>& value)
|
||||
{
|
||||
std::visit([this](const auto& inner){
|
||||
openVariant(signature_of<decltype(inner)>::str());
|
||||
*this << inner;
|
||||
closeVariant();
|
||||
}, value);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename _Element, typename _Allocator>
|
||||
inline Message& Message::operator<<(const std::vector<_Element, _Allocator>& items)
|
||||
{
|
||||
@ -442,6 +458,34 @@ namespace sdbus {
|
||||
return *this;
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename _Element, typename... _Elements>
|
||||
bool deserialize_variant(Message& msg, std::variant<_Elements...>& value, const std::string& signature)
|
||||
{
|
||||
if (signature != signature_of<_Element>::str())
|
||||
return false;
|
||||
|
||||
_Element temp;
|
||||
msg.enterVariant(signature);
|
||||
msg >> temp;
|
||||
msg.exitVariant();
|
||||
value = std::move(temp);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... Elements>
|
||||
inline Message& Message::operator>>(std::variant<Elements...>& value)
|
||||
{
|
||||
std::string type;
|
||||
std::string contentType;
|
||||
peekType(type, contentType);
|
||||
bool result = (detail::deserialize_variant<Elements>(*this, value, contentType) || ...);
|
||||
SDBUS_THROW_ERROR_IF(!result, "Failed to deserialize variant: signature did not match any of the variant types", EINVAL);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename _Element, typename _Allocator>
|
||||
inline Message& Message::operator>>(std::vector<_Element, _Allocator>& items)
|
||||
{
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <variant>
|
||||
#if __cplusplus >= 202002L
|
||||
#include <span>
|
||||
#endif
|
||||
@ -331,6 +332,10 @@ namespace sdbus {
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... Elements>
|
||||
struct signature_of<std::variant<Elements...>> : signature_of<Variant>
|
||||
{};
|
||||
|
||||
template <>
|
||||
struct signature_of<ObjectPath>
|
||||
{
|
||||
|
@ -501,3 +501,39 @@ TEST(AMessage, CanCarryDBusStructGivenAsCustomType)
|
||||
|
||||
ASSERT_THAT(dataRead, Eq(dataWritten));
|
||||
}
|
||||
|
||||
class AMessage : public ::testing::TestWithParam<std::variant<int32_t, std::string, my::Struct>>
|
||||
{
|
||||
};
|
||||
|
||||
TEST_P(AMessage, CanCarryDBusVariantGivenAsStdVariant)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
const std::variant<int32_t, std::string, my::Struct> dataWritten{GetParam()};
|
||||
|
||||
msg << dataWritten;
|
||||
msg.seal();
|
||||
|
||||
std::variant<int32_t, std::string, my::Struct> dataRead;
|
||||
msg >> dataRead;
|
||||
|
||||
ASSERT_THAT(dataRead, Eq(dataWritten));
|
||||
}
|
||||
|
||||
TEST_P(AMessage, ThrowsWhenDestinationStdVariantHasWrongTypeDuringDeserialization)
|
||||
{
|
||||
auto msg = sdbus::createPlainMessage();
|
||||
|
||||
const std::variant<int32_t, std::string, my::Struct> dataWritten{GetParam()};
|
||||
|
||||
msg << dataWritten;
|
||||
msg.seal();
|
||||
|
||||
std::variant<std::vector<bool>> dataRead;
|
||||
ASSERT_THROW(msg >> dataRead, sdbus::Error);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P( StringIntStruct
|
||||
, AMessage
|
||||
, ::testing::Values("hello"s, 1, my::Struct{}));
|
||||
|
@ -93,6 +93,7 @@ namespace
|
||||
TYPE(sdbus::Struct<uint16_t, double, std::string, sdbus::Variant>)HAS_DBUS_TYPE_SIGNATURE("(qdsv)")
|
||||
TYPE(std::vector<int16_t>)HAS_DBUS_TYPE_SIGNATURE("an")
|
||||
TYPE(std::array<int16_t, 3>)HAS_DBUS_TYPE_SIGNATURE("an")
|
||||
TYPE(std::variant<int16_t, std::string>)HAS_DBUS_TYPE_SIGNATURE("v")
|
||||
#if __cplusplus >= 202002L
|
||||
TYPE(std::span<int16_t>)HAS_DBUS_TYPE_SIGNATURE("an")
|
||||
#endif
|
||||
@ -142,6 +143,7 @@ namespace
|
||||
, sdbus::Struct<uint16_t, double, std::string, sdbus::Variant>
|
||||
, std::vector<int16_t>
|
||||
, std::array<int16_t, 3>
|
||||
, std::variant<int16_t, std::string>
|
||||
#if __cplusplus >= 202002L
|
||||
, std::span<int16_t>
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user