1 // Copyright (c) Benjamin Kietzman (github.com/bkietz) 2 // 3 // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 6 #ifndef DBUS_ELEMENT_HPP 7 #define DBUS_ELEMENT_HPP 8 9 #include <dbus/dbus.h> 10 #include <string> 11 #include <vector> 12 #include <boost/cstdint.hpp> 13 #include <boost/variant.hpp> 14 15 namespace dbus { 16 17 /// Message elements 18 /** 19 * D-Bus Messages are composed of simple elements of one of these types 20 */ 21 // bool // is this simply valid? It might pack wrong... 22 // http://maemo.org/api_refs/5.0/5.0-final/dbus/api/group__DBusTypes.html 23 typedef boost::uint8_t byte; 24 25 typedef boost::int16_t int16; 26 typedef boost::uint16_t uint16; 27 typedef boost::int32_t int32; 28 typedef boost::uint32_t uint32; 29 30 typedef boost::int64_t int64; 31 typedef boost::uint64_t uint64; 32 // double 33 // unix_fd 34 35 typedef std::string string; 36 37 typedef boost::variant<std::string, bool, byte, int16, uint16, int32, uint32, 38 int64, uint64, double> 39 dbus_variant; 40 41 struct object_path { 42 string value; 43 bool operator<(const object_path& b) const { return value < b.value; } 44 }; 45 struct signature { 46 string value; 47 }; 48 49 /** 50 * D-Bus Message elements are identified by unique integer type codes. 51 */ 52 53 template <typename InvalidType> 54 struct element { 55 static constexpr int code = DBUS_TYPE_INVALID; 56 }; 57 58 template <> 59 struct element<bool> { 60 static constexpr int code = DBUS_TYPE_BOOLEAN; 61 }; 62 63 template <> 64 struct element<byte> { 65 static constexpr int code = DBUS_TYPE_BYTE; 66 }; 67 68 template <> 69 struct element<int16> { 70 static constexpr int code = DBUS_TYPE_INT16; 71 }; 72 73 template <> 74 struct element<uint16> { 75 static constexpr int code = DBUS_TYPE_UINT16; 76 }; 77 78 template <> 79 struct element<int32> { 80 static constexpr int code = DBUS_TYPE_INT32; 81 }; 82 83 template <> 84 struct element<uint32> { 85 static constexpr int code = DBUS_TYPE_UINT32; 86 }; 87 88 template <> 89 struct element<int64> { 90 static constexpr int code = DBUS_TYPE_INT64; 91 }; 92 93 template <> 94 struct element<uint64> { 95 static constexpr int code = DBUS_TYPE_UINT64; 96 }; 97 98 template <> 99 struct element<double> { 100 static constexpr int code = DBUS_TYPE_DOUBLE; 101 }; 102 103 template <> 104 struct element<string> { 105 static constexpr int code = DBUS_TYPE_STRING; 106 }; 107 108 template <> 109 struct element<dbus_variant> { 110 static constexpr int code = DBUS_TYPE_VARIANT; 111 }; 112 113 template <> 114 struct element<object_path> { 115 static constexpr int code = DBUS_TYPE_OBJECT_PATH; 116 }; 117 118 template <> 119 struct element<signature> { 120 static constexpr int code = DBUS_TYPE_SIGNATURE; 121 }; 122 123 template <typename Element> 124 struct element<std::vector<Element>> { 125 static constexpr int code = DBUS_TYPE_ARRAY; 126 }; 127 128 template <typename InvalidType> 129 struct is_fixed_type : std::false_type {}; 130 131 template <> 132 struct is_fixed_type<bool> : std::true_type {}; 133 134 template <> 135 struct is_fixed_type<byte> : std::true_type {}; 136 137 template <> 138 struct is_fixed_type<int16> : std::true_type {}; 139 140 template <> 141 struct is_fixed_type<uint16> : std::true_type {}; 142 143 template <> 144 struct is_fixed_type<int32> : std::true_type {}; 145 146 template <> 147 struct is_fixed_type<uint32> : std::true_type {}; 148 149 template <> 150 struct is_fixed_type<int64> : std::true_type {}; 151 152 template <> 153 struct is_fixed_type<uint64> : std::true_type {}; 154 155 template <> 156 struct is_fixed_type<double> : std::true_type {}; 157 158 template <typename InvalidType> 159 struct is_string_type : std::false_type {}; 160 161 template <> 162 struct is_string_type<string> : std::true_type {}; 163 164 template <> 165 struct is_string_type<object_path> : std::true_type {}; 166 167 template <> 168 struct is_string_type<signature> : std::true_type {}; 169 170 template <std::size_t... Is> 171 struct seq {}; 172 173 template <std::size_t N, std::size_t... Is> 174 struct gen_seq : gen_seq<N - 1, N - 1, Is...> {}; 175 176 template <std::size_t... Is> 177 struct gen_seq<0, Is...> : seq<Is...> {}; 178 179 template <std::size_t N1, std::size_t... I1, std::size_t N2, std::size_t... I2> 180 constexpr std::array<char, N1 + N2 - 1> concat_helper( 181 const std::array<char, N1>& a1, const std::array<char, N2>& a2, seq<I1...>, 182 seq<I2...>) { 183 return {{a1[I1]..., a2[I2]...}}; 184 } 185 186 template <std::size_t N1, std::size_t N2> 187 // Initializer for the recursion 188 constexpr const std::array<char, N1 + N2 - 1> concat( 189 const std::array<char, N1>& a1, const std::array<char, N2>& a2) { 190 // note, this function expects both character arrays to be null 191 // terminated. The -1 below drops the null terminator on the first string 192 return concat_helper(a1, a2, gen_seq<N1 - 1>{}, gen_seq<N2>{}); 193 } 194 195 // Base case for types that should never be asserted 196 template <typename Element, class Enable = void> 197 struct element_signature {}; 198 199 // Element signature for building raw c_strings of known element_codes 200 201 // Case for fixed "final" types (double, float ect) that have their own code by 202 // default., This includes strings and variants. 203 // Put another way, this is the catch for everything that is not a container 204 template <typename Element> 205 struct element_signature< 206 Element, 207 typename std::enable_if<is_fixed_type<Element>::value || 208 is_string_type<Element>::value || 209 std::is_same<Element, dbus_variant>::value>::type> { 210 static auto constexpr code = std::array<char, 2>{{element<Element>::code, 0}}; 211 }; 212 213 template <typename Element> 214 struct element_signature< 215 Element, typename std::enable_if<std::is_pointer<Element>::value>::type> { 216 static auto const constexpr code = 217 218 element_signature<typename std::remove_pointer<Element>::type>::code; 219 }; 220 221 template <typename T> 222 struct has_const_iterator { 223 private: 224 typedef char yes; 225 typedef struct { char array[2]; } no; 226 227 template <typename C> 228 static yes test(typename C::const_iterator*); 229 template <typename C> 230 static no test(...); 231 232 public: 233 static constexpr bool value = sizeof(test<T>(0)) == sizeof(yes); 234 }; 235 236 // Specialization for "container" types. Containers are defined as anything 237 // that can be iterated through. This allows running any iterable type, so long 238 // as its value_type is a known dbus type (which could also be a container) 239 // Note: technically std::string is an iterable container, so it needs to be 240 // explicitly excluded from this specialization 241 template <typename Container> 242 struct element_signature< 243 Container, 244 typename std::enable_if<has_const_iterator<Container>::value && 245 !is_string_type<Container>::value>::type> { 246 static auto const constexpr code = 247 concat(std::array<char, 2>{{DBUS_TYPE_ARRAY, 0}}, 248 element_signature<typename Container::value_type>::code); 249 }; 250 251 // Specialization for std::pair type. Std::pair is treated as a "dict entry" 252 // element. In dbus, dictionarys are represented as arrays of dict entries, so 253 // this specialization builds type codes based on anything that produces a 254 // std::pair and constructs the signature for the dict entry, for example {si} 255 // would be a string of ints 256 template <typename Key, typename Value> 257 struct element_signature<std::pair<Key, Value>> { 258 static auto const constexpr code = 259 concat(std::array<char, 2>{{'{', 0}}, 260 concat(element_signature<Key>::code, 261 concat(element_signature<Value>::code, 262 std::array<char, 2>{{'}', 0}}))); 263 }; 264 265 } // namespace dbus 266 267 #endif // DBUS_ELEMENT_HPP 268