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;
operator <dbus::object_path43 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>
concat_helper(const std::array<char,N1> & a1,const std::array<char,N2> & a2,seq<I1...>,seq<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
concat(const std::array<char,N1> & a1,const std::array<char,N2> & a2)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