xref: /openbmc/boost-dbus/include/dbus/element.hpp (revision 165e3f02)
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