std::vector support for append/read
Change-Id: I1820ee2213feb37fab10a491b1099032fd48c18d
Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
diff --git a/sdbusplus/message/append.hpp b/sdbusplus/message/append.hpp
index 7ce429b..2fda860 100644
--- a/sdbusplus/message/append.hpp
+++ b/sdbusplus/message/append.hpp
@@ -47,6 +47,9 @@
template<typename T> struct can_append_multiple : std::true_type {};
// std::string needs a c_str() call.
template<> struct can_append_multiple<std::string> : std::false_type {};
+ // std::vector needs a loop.
+template<typename T>
+struct can_append_multiple<std::vector<T>> : std::false_type {};
/** @struct append_single
* @brief Utility to append a single C++ element into a sd_bus_message.
@@ -104,6 +107,20 @@
}
};
+/** @brief Specialization of append_single for std::vectors. */
+template <typename T> struct append_single<std::vector<T>>
+{
+ template<typename S>
+ static void op(sd_bus_message* m, S&& s)
+ {
+ constexpr auto dbusType = utility::tuple_to_array(types::type_id<T>());
+
+ sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, dbusType.data());
+ for(auto& i : s) { sdbusplus::message::append(m, i); }
+ 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 ea7ccd1..9b28421 100644
--- a/sdbusplus/message/read.hpp
+++ b/sdbusplus/message/read.hpp
@@ -47,6 +47,9 @@
template<typename T> struct can_read_multiple : std::true_type {};
// std::string needs a c_str() call.
template<> struct can_read_multiple<std::string> : std::false_type {};
+ // std::vector needs a loop.
+template<typename T>
+struct can_read_multiple<std::vector<T>> : std::false_type {};
/** @struct read_single
* @brief Utility to read a single C++ element from a sd_bus_message.
@@ -106,6 +109,28 @@
}
};
+/** @brief Specialization of read_single for std::vectors. */
+template <typename T> struct read_single<std::vector<T>>
+{
+ template<typename S>
+ static void op(sd_bus_message* m, S&& s)
+ {
+ s.clear();
+
+ constexpr auto dbusType = utility::tuple_to_array(types::type_id<T>());
+ sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, dbusType.data());
+
+ while(!sd_bus_message_at_end(m, false))
+ {
+ std::remove_const_t<T> t{};
+ sdbusplus::message::read(m, t);
+ s.push_back(std::move(t));
+ }
+
+ sd_bus_message_exit_container(m);
+ }
+};
+
/** @brief Read a tuple of content from the sd_bus_message.
*
* @tparam Tuple - The tuple type to read.
diff --git a/sdbusplus/message/types.hpp b/sdbusplus/message/types.hpp
index cd0fff2..026c3cf 100644
--- a/sdbusplus/message/types.hpp
+++ b/sdbusplus/message/types.hpp
@@ -34,6 +34,24 @@
namespace details
{
+/** @brief Convert some C++ types to others for 'type_id' conversion purposes.
+ *
+ * Similar C++ types have the same dbus type-id, so 'downcast' those to limit
+ * duplication in type_id template specializations.
+ *
+ * 1. Remove references.
+ * 2. Remove 'const' and 'volatile'.
+ * 3. Convert 'char[N]' to 'char*'.
+ */
+template <typename T> struct type_id_downcast
+{
+ using type = typename utility::array_to_ptr_t<
+ char, std::remove_cv_t<std::remove_reference_t<T>>>;
+};
+
+template <typename T> using type_id_downcast_t =
+ typename type_id_downcast<T>::type;
+
/** @struct undefined_type_id
* @brief Special type indicating no dbus-type_id is defined for a C++ type.
*/
@@ -112,6 +130,13 @@
template <> struct type_id<char*> : tuple_type_id<'s'> {};
template <> struct type_id<std::string> : tuple_type_id<'s'> {};
+template <typename T> struct type_id<std::vector<T>>
+{
+ static constexpr auto value = std::tuple_cat(
+ tuple_type_id<'a'>::value,
+ type_id<type_id_downcast_t<T>>::value);
+};
+
template <typename T> constexpr auto& type_id_single()
{
static_assert(!std::is_base_of<undefined_type_id, type_id<T>>::value,
@@ -125,24 +150,6 @@
type_id_single<Args>()...);
}
-/** @brief Convert some C++ types to others for 'type_id' conversion purposes.
- *
- * Similar C++ types have the same dbus type-id, so 'downcast' those to limit
- * duplication in type_id template specializations.
- *
- * 1. Remove references.
- * 2. Remove 'const' and 'vector'.
- * 3. Convert 'char[N]' to 'char*'.
- */
-template <typename T> struct type_id_downcast
-{
- using type = typename utility::array_to_ptr_t<
- char, std::remove_cv_t<std::remove_reference_t<T>>>;
-};
-
-template <typename T> using type_id_downcast_t =
- typename type_id_downcast<T>::type;
-
} // namespace details
template <typename ...Args> constexpr auto type_id()
diff --git a/test/message/append.cpp b/test/message/append.cpp
index 4413910..87d8fc5 100644
--- a/test/message/append.cpp
+++ b/test/message/append.cpp
@@ -192,6 +192,48 @@
b.call_noreply(m);
}
+ // Test vector.
+ {
+ auto m = newMethodCall__test(b);
+ std::vector<std::string> s{ "1", "2", "3"};
+ m.append(1, s, 2);
+ verifyTypeString = "iasi";
+
+ struct verify
+ {
+ static void op(sd_bus_message* m)
+ {
+ int32_t a = 0;
+ sd_bus_message_read(m, "i", &a);
+ assert(a == 1);
+
+ auto rc = sd_bus_message_enter_container(m,
+ SD_BUS_TYPE_ARRAY,
+ "s");
+ assert(0 <= rc);
+
+ const char* s = nullptr;
+ sd_bus_message_read_basic(m, 's', &s);
+ assert(0 == strcmp("1", s));
+ sd_bus_message_read_basic(m, 's', &s);
+ assert(0 == strcmp("2", s));
+ sd_bus_message_read_basic(m, 's', &s);
+ assert(0 == strcmp("3", s));
+ assert(1 == sd_bus_message_at_end(m, false));
+
+ 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 48c445e..1021175 100644
--- a/test/message/read.cpp
+++ b/test/message/read.cpp
@@ -193,6 +193,33 @@
b.call_noreply(m);
}
+ // Test vector.
+ {
+ auto m = newMethodCall__test(b);
+ std::vector<std::string> s{ "1", "2", "3"};
+ m.append(1, s, 2);
+ verifyTypeString = "iasi";
+
+ struct verify
+ {
+ static void op(sdbusplus::message::message& m)
+ {
+ int32_t a = 0;
+ std::vector<std::string> s;
+ m.read(a, s);
+ assert(a == 1);
+ assert(s[0] == "1");
+ assert(s[1] == "2");
+ assert(s[2] == "3");
+ decltype(s) s2 = { "1" , "2" , "3" };
+ assert(s == s2);
+ }
+ };
+ verifyCallback = &verify::op;
+
+ b.call_noreply(m);
+ }
+
// Shutdown server.
{
auto m = b.new_method_call(SERVICE, "/", INTERFACE, QUIT_METHOD);