diff options
| author | Patrick Williams <patrick@stwcx.xyz> | 2016-09-10 08:57:03 -0500 |
|---|---|---|
| committer | Patrick Williams <patrick@stwcx.xyz> | 2016-09-12 21:54:52 -0500 |
| commit | bbe0e436373e7df317f4240859b43ab205f6d32d (patch) | |
| tree | 9e11475a0e289537936ae76e4f613cd4a457fb8c | |
| parent | 90b4f3ce3e46d4f6d153b7086b1d51cf9b4ea64c (diff) | |
| download | sdbusplus-bbe0e436373e7df317f4240859b43ab205f6d32d.tar.gz sdbusplus-bbe0e436373e7df317f4240859b43ab205f6d32d.zip | |
std::map support for append/read
Change-Id: I3b5510b8ba400cf4d3f936f01708cb17aa009e62
Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
| -rw-r--r-- | sdbusplus/message/append.hpp | 38 | ||||
| -rw-r--r-- | sdbusplus/message/read.hpp | 48 | ||||
| -rw-r--r-- | sdbusplus/message/types.hpp | 28 | ||||
| -rw-r--r-- | test/message/append.cpp | 59 | ||||
| -rw-r--r-- | test/message/read.cpp | 29 |
5 files changed, 202 insertions, 0 deletions
diff --git a/sdbusplus/message/append.hpp b/sdbusplus/message/append.hpp index 2fda860..da8dc1a 100644 --- a/sdbusplus/message/append.hpp +++ b/sdbusplus/message/append.hpp @@ -50,6 +50,12 @@ 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 {}; + // std::pair needs to be broken down into components. +template<typename T1, typename T2> +struct can_append_multiple<std::pair<T1,T2>> : std::false_type {}; + // std::map needs a loop. +template<typename T1, typename T2> +struct can_append_multiple<std::map<T1,T2>> : std::false_type {}; /** @struct append_single * @brief Utility to append a single C++ element into a sd_bus_message. @@ -121,6 +127,38 @@ template <typename T> struct append_single<std::vector<T>> } }; +/** @brief Specialization of append_single for std::pairs. */ +template <typename T1, typename T2> struct append_single<std::pair<T1, T2>> +{ + 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<T1>(), + types::type_id<T2>())); + + sd_bus_message_open_container( + m, SD_BUS_TYPE_DICT_ENTRY, dbusType.data()); + sdbusplus::message::append(m, s.first, s.second); + sd_bus_message_close_container(m); + } +}; + +/** @brief Specialization of append_single for std::maps. */ +template <typename T1, typename T2> struct append_single<std::map<T1, T2>> +{ + template<typename S> + static void op(sd_bus_message* m, S&& s) + { + constexpr auto dbusType = utility::tuple_to_array( + types::type_id<typename std::map<T1, T2>::value_type>()); + + 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 9b28421..6291409 100644 --- a/sdbusplus/message/read.hpp +++ b/sdbusplus/message/read.hpp @@ -50,6 +50,12 @@ 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 {}; + // std::pair needs to be broken down into components. +template<typename T1, typename T2> +struct can_read_multiple<std::pair<T1,T2>> : std::false_type {}; + // std::map needs a loop. +template<typename T1, typename T2> +struct can_read_multiple<std::map<T1,T2>> : std::false_type {}; /** @struct read_single * @brief Utility to read a single C++ element from a sd_bus_message. @@ -131,6 +137,48 @@ template <typename T> struct read_single<std::vector<T>> } }; +/** @brief Specialization of read_single for std::pairs. */ +template <typename T1, typename T2> struct read_single<std::pair<T1, T2>> +{ + 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<T1>(), + types::type_id<T2>())); + + sd_bus_message_enter_container( + m, SD_BUS_TYPE_DICT_ENTRY, dbusType.data()); + sdbusplus::message::read(m, s.first, s.second); + sd_bus_message_exit_container(m); + } +}; + +/** @brief Specialization of read_single for std::maps. */ +template <typename T1, typename T2> struct read_single<std::map<T1, T2>> +{ + template<typename S> + static void op(sd_bus_message* m, S&& s) + { + s.clear(); + + constexpr auto dbusType = utility::tuple_to_array( + types::type_id<typename std::map<T1, T2>::value_type>()); + + sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, dbusType.data()); + + while(!sd_bus_message_at_end(m, false)) + { + std::pair<std::remove_const_t<T1>, std::remove_const_t<T2>> p{}; + sdbusplus::message::read(m, p); + s.insert(std::move(p)); + } + + 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 403b4f1..3e39aca 100644 --- a/sdbusplus/message/types.hpp +++ b/sdbusplus/message/types.hpp @@ -3,6 +3,7 @@ #include <tuple> #include <string> #include <vector> +#include <map> #include <systemd/sd-bus.h> #include <sdbusplus/utility/type_traits.hpp> @@ -31,6 +32,12 @@ namespace types * the cost of hard-coded type string constants. */ template <typename ...Args> constexpr auto type_id(); +/** @fn type_id_nonull() + * @brief A non-null-terminated version of type_id. + * + * This is useful when type-ids may need to be concatenated. + */ +template <typename ...Args> constexpr auto type_id_nonull(); namespace details { @@ -138,6 +145,22 @@ template <typename T> struct type_id<std::vector<T>> type_id<type_id_downcast_t<T>>::value); }; +template <typename T1, typename T2> struct type_id<std::pair<T1, T2>> +{ + static constexpr auto value = std::tuple_cat( + tuple_type_id<SD_BUS_TYPE_DICT_ENTRY_BEGIN>::value, + type_id<type_id_downcast_t<T1>>::value, + type_id<type_id_downcast_t<T2>>::value, + tuple_type_id<SD_BUS_TYPE_DICT_ENTRY_END>::value); +}; + +template <typename T1, typename T2> struct type_id<std::map<T1, T2>> +{ + static constexpr auto value = std::tuple_cat( + tuple_type_id<SD_BUS_TYPE_ARRAY>::value, + type_id<typename std::map<T1,T2>::value_type>::value); +}; + template <typename T> constexpr auto& type_id_single() { static_assert(!std::is_base_of<undefined_type_id, type_id<T>>::value, @@ -160,6 +183,11 @@ template <typename ...Args> constexpr auto type_id() std::make_tuple('\0') /* null terminator for C-string */ ); } +template <typename ...Args> constexpr auto type_id_nonull() +{ + return details::type_id_multiple<details::type_id_downcast_t<Args>...>(); +} + } // namespace types } // namespace message diff --git a/test/message/append.cpp b/test/message/append.cpp index 87d8fc5..4734815 100644 --- a/test/message/append.cpp +++ b/test/message/append.cpp @@ -234,6 +234,65 @@ void runTests() b.call_noreply(m); } + // Test map. + { + auto m = newMethodCall__test(b); + std::map<std::string, int> s = { { "asdf", 3 }, { "jkl;", 4 } }; + m.append(1, s, 2); + verifyTypeString = "ia{si}i"; + + 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, + "{si}"); + assert(0 <= rc); + + rc = sd_bus_message_enter_container(m, + SD_BUS_TYPE_DICT_ENTRY, + "si"); + assert(0 <= rc); + + const char* s = nullptr; + sd_bus_message_read_basic(m, 's', &s); + assert(0 == strcmp("asdf", s)); + sd_bus_message_read_basic(m, 'i', &a); + assert(a == 3); + + assert(1 == sd_bus_message_at_end(m, false)); + sd_bus_message_exit_container(m); + + rc = sd_bus_message_enter_container(m, + SD_BUS_TYPE_DICT_ENTRY, + "si"); + assert(0 <= rc); + + sd_bus_message_read_basic(m, 's', &s); + assert(0 == strcmp("jkl;", s)); + sd_bus_message_read_basic(m, 'i', &a); + assert(a == 4); + + assert(1 == sd_bus_message_at_end(m, false)); + sd_bus_message_exit_container(m); + + 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 1021175..f1dfc77 100644 --- a/test/message/read.cpp +++ b/test/message/read.cpp @@ -220,6 +220,35 @@ void runTests() b.call_noreply(m); } + // Test map. + { + auto m = newMethodCall__test(b); + std::map<std::string, int> s = { { "asdf", 3 }, { "jkl;", 4 } }; + m.append(1, s, 2); + verifyTypeString = "ia{si}i"; + + struct verify + { + static void op(sdbusplus::message::message& m) + { + int32_t a = 0, b = 0; + std::map<std::string, int> s{}; + + m.read(a, s, b); + assert(a == 1); + assert(s.size() == 2); + assert(s["asdf"] == 3); + assert(s["jkl;"] == 4); + assert(b == 2); + } + }; + verifyCallback = &verify::op; + + b.call_noreply(m); + } + + + // Shutdown server. { auto m = b.new_method_call(SERVICE, "/", INTERFACE, QUIT_METHOD); |

