std::tuple support for append/read
Change-Id: If914032fa4f655af509ac58a5e0057968f71aa32
Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
diff --git a/sdbusplus/message/append.hpp b/sdbusplus/message/append.hpp
index da8dc1a..2db790b 100644
--- a/sdbusplus/message/append.hpp
+++ b/sdbusplus/message/append.hpp
@@ -56,6 +56,9 @@
// std::map needs a loop.
template<typename T1, typename T2>
struct can_append_multiple<std::map<T1,T2>> : std::false_type {};
+ // std::tuple needs to be broken down into components.
+template<typename ...Args>
+struct can_append_multiple<std::tuple<Args...>> : std::false_type {};
/** @struct append_single
* @brief Utility to append a single C++ element into a sd_bus_message.
@@ -159,6 +162,32 @@
}
};
+/** @brief Specialization of append_single for std::tuples. */
+template <typename ...Args> struct append_single<std::tuple<Args...>>
+{
+ template<typename S, std::size_t... I>
+ static void _op(sd_bus_message* m, S&& s,
+ std::integer_sequence<std::size_t, I...>)
+ {
+ sdbusplus::message::append(m, std::get<I>(s)...);
+ }
+
+ template<typename S>
+ static void op(sd_bus_message* m, S&& s)
+ {
+ constexpr auto dbusType = utility::tuple_to_array(std::tuple_cat(
+ types::type_id_nonull<Args...>(),
+ std::make_tuple('\0') /* null terminator for C-string */));
+
+ sd_bus_message_open_container(
+ m, SD_BUS_TYPE_STRUCT, dbusType.data());
+ _op(m, std::forward<S>(s),
+ std::make_index_sequence<sizeof...(Args)>());
+ sd_bus_message_close_container(m);
+
+ }
+};
+
/** @brief Append a tuple of content into the sd_bus_message.
*
* @tparam Tuple - The tuple type to append.
diff --git a/sdbusplus/message/read.hpp b/sdbusplus/message/read.hpp
index 6291409..47e2392 100644
--- a/sdbusplus/message/read.hpp
+++ b/sdbusplus/message/read.hpp
@@ -56,6 +56,9 @@
// std::map needs a loop.
template<typename T1, typename T2>
struct can_read_multiple<std::map<T1,T2>> : std::false_type {};
+ // std::tuple needs to be broken down into components.
+template<typename ...Args>
+struct can_read_multiple<std::tuple<Args...>> : std::false_type {};
/** @struct read_single
* @brief Utility to read a single C++ element from a sd_bus_message.
@@ -178,6 +181,31 @@
}
};
+/** @brief Specialization of read_single for std::tuples. */
+template <typename ...Args> struct read_single<std::tuple<Args...>>
+{
+ template<typename S, std::size_t... I>
+ static void _op(sd_bus_message* m, S&& s,
+ std::integer_sequence<std::size_t, I...>)
+ {
+ sdbusplus::message::read(m, std::get<I>(s)...);
+ }
+
+ template<typename S>
+ static void op(sd_bus_message* m, S&& s)
+ {
+ constexpr auto dbusType = utility::tuple_to_array(std::tuple_cat(
+ types::type_id_nonull<Args...>(),
+ std::make_tuple('\0') /* null terminator for C-string */));
+
+ sd_bus_message_enter_container(
+ m, SD_BUS_TYPE_STRUCT, dbusType.data());
+ _op(m, std::forward<S>(s),
+ std::make_index_sequence<sizeof...(Args)>());
+ sd_bus_message_exit_container(m);
+
+ }
+};
/** @brief Read a tuple of content from the sd_bus_message.
*
diff --git a/sdbusplus/message/types.hpp b/sdbusplus/message/types.hpp
index 3e39aca..1876fa2 100644
--- a/sdbusplus/message/types.hpp
+++ b/sdbusplus/message/types.hpp
@@ -161,6 +161,14 @@
type_id<typename std::map<T1,T2>::value_type>::value);
};
+template <typename ...Args> struct type_id<std::tuple<Args...>>
+{
+ static constexpr auto value = std::tuple_cat(
+ tuple_type_id<SD_BUS_TYPE_STRUCT_BEGIN>::value,
+ type_id<type_id_downcast_t<Args>>::value...,
+ tuple_type_id<SD_BUS_TYPE_STRUCT_END>::value);
+};
+
template <typename T> constexpr auto& type_id_single()
{
static_assert(!std::is_base_of<undefined_type_id, type_id<T>>::value,
diff --git a/test/message/append.cpp b/test/message/append.cpp
index 4734815..03ab781 100644
--- a/test/message/append.cpp
+++ b/test/message/append.cpp
@@ -293,6 +293,45 @@
b.call_noreply(m);
}
+ // Test tuple.
+ {
+ auto m = newMethodCall__test(b);
+ std::tuple<int, double, std::string> a{ 3, 4.1, "asdf" };
+ m.append(1, a, 2);
+ verifyTypeString = "i(ids)i";
+
+ struct verify
+ {
+ static void op(sd_bus_message* m)
+ {
+ int32_t a = 0;
+ double b = 0;
+ const char* c = nullptr;
+
+ sd_bus_message_read(m, "i", &a);
+ assert(a == 1);
+
+ auto rc = sd_bus_message_enter_container(m,
+ SD_BUS_TYPE_STRUCT,
+ "ids");
+ assert(0 <= rc);
+
+ sd_bus_message_read(m, "ids", &a, &b, &c);
+ assert(a == 3);
+ assert(b == 4.1);
+ assert(0 == strcmp(c, "asdf"));
+
+ sd_bus_message_exit_container(m);
+
+ sd_bus_message_read(m, "i", &a);
+ assert(a == 2);
+ }
+ };
+ verifyCallback = &verify::op;
+
+ b.call_noreply(m);
+ }
+
// Shutdown server.
{
auto m = b.new_method_call(SERVICE, "/", INTERFACE, QUIT_METHOD);
diff --git a/test/message/read.cpp b/test/message/read.cpp
index f1dfc77..25ccdb5 100644
--- a/test/message/read.cpp
+++ b/test/message/read.cpp
@@ -247,7 +247,30 @@
b.call_noreply(m);
}
+ // Test tuple.
+ {
+ auto m = newMethodCall__test(b);
+ std::tuple<int, double, std::string> a{ 3, 4.1, "asdf" };
+ m.append(1, a, 2);
+ verifyTypeString = "i(ids)i";
+ struct verify
+ {
+ static void op(sdbusplus::message::message& m)
+ {
+ int32_t a = 0, b = 0;
+ std::tuple<int, double, std::string> c{};
+
+ m.read(a, c, b);
+ assert(a == 1);
+ assert(b == 2);
+ assert(c == std::make_tuple(3, 4.1, "asdf"s));
+ }
+ };
+ verifyCallback = &verify::op;
+
+ b.call_noreply(m);
+ }
// Shutdown server.
{