sdbus-c++ 2.3.0
High-level C++ D-Bus library based on systemd D-Bus implementation
Loading...
Searching...
No Matches
Types.h
Go to the documentation of this file.
1
26
27#ifndef SDBUS_CXX_TYPES_H_
28#define SDBUS_CXX_TYPES_H_
29
30#include <sdbus-c++/Message.h>
32
33#include <cstring>
34#include <cstddef>
35#include <memory>
36#include <string>
37#include <tuple>
38#include <type_traits>
39#include <utility>
40
41namespace sdbus {
42
43 /********************************************/
55 class Variant
56 {
57 public:
58 Variant();
59
60 template <typename ValueType>
61 explicit Variant(const ValueType& value) : Variant()
62 {
63 msg_.openVariant<ValueType>();
64 msg_ << value;
65 msg_.closeVariant();
66 msg_.seal();
67 }
68
69 Variant(const Variant& value, embed_variant_t) : Variant()
70 {
71 msg_.openVariant<Variant>();
72 msg_ << value;
73 msg_.closeVariant();
74 msg_.seal();
75 }
76
77 template <typename Struct>
78 explicit Variant(const as_dictionary<Struct>& value) : Variant()
79 {
80 msg_.openVariant<std::map<std::string, Variant>>();
81 msg_ << as_dictionary(value.m_struct);
82 msg_.closeVariant();
83 msg_.seal();
84 }
85
86 template <typename... Elements>
87 Variant(const std::variant<Elements...>& value) // NOLINT(google-explicit-constructor,hicpp-explicit-conversions): implicit conversion intentional
88 : Variant()
89 {
90 msg_ << value;
91 msg_.seal();
92 }
93
94 template <typename ValueType>
95 ValueType get() const
96 {
97 msg_.rewind(false);
98
99 msg_.enterVariant<ValueType>();
100 ValueType val;
101 msg_ >> val;
102 msg_.exitVariant();
103 return val;
104 }
105
106 [[nodiscard]] std::string dumpToString() const
107 {
108 msg_.rewind(false);
109
110 return msg_.dumpToString(Message::DumpFlags::SubtreeOnly);
111 }
112
113 // Only allow conversion operator for true D-Bus type representations in C++
114 // NOLINTNEXTLINE(modernize-use-constraints): TODO for future: Use `requires signature_of<_ValueType>::is_valid` (when we stop supporting C++17 in public API)
115 template <typename ValueType, typename = std::enable_if_t<signature_of<ValueType>::is_valid>>
116 explicit operator ValueType() const
117 {
118 return get<ValueType>();
119 }
120
121 template <typename... Elements>
122 operator std::variant<Elements...>() const // NOLINT(google-explicit-constructor,hicpp-explicit-conversions): implicit conversion intentional
123 {
124 std::variant<Elements...> result;
125 msg_.rewind(false);
126 msg_ >> result;
127 return result;
128 }
129
130 template <typename Type>
131 bool containsValueOfType() const
132 {
133 constexpr auto signature = as_null_terminated(signature_of_v<Type>);
134 return std::strcmp(signature.data(), peekValueType()) == 0;
135 }
136
137 bool isEmpty() const;
138
139 void serializeTo(Message& msg) const;
140 void deserializeFrom(Message& msg);
141 const char* peekValueType() const;
142
143 private:
144 mutable PlainMessage msg_;
145 };
146
147 /********************************************/
157 template <typename... ValueTypes>
158 class Struct
159 : public std::tuple<ValueTypes...>
160 {
161 public:
162 using std::tuple<ValueTypes...>::tuple;
163
164 Struct() = default;
165
166 explicit Struct(const std::tuple<ValueTypes...>& tuple)
167 : std::tuple<ValueTypes...>(tuple)
168 {
169 }
170
171 template <std::size_t I>
172 [[nodiscard]] auto& get()
173 {
174 return std::get<I>(*this);
175 }
176
177 template <std::size_t I>
178 [[nodiscard]] const auto& get() const
179 {
180 return std::get<I>(*this);
181 }
182 };
183
184 template <typename... Elements>
185 Struct(Elements...) -> Struct<Elements...>;
186
187 template <typename... Elements>
188 Struct(const std::tuple<Elements...>&) -> Struct<Elements...>;
189
190 template <typename... Elements>
191 Struct(std::tuple<Elements...>&&) -> Struct<Elements...>;
192
193 template<typename... Elements>
195 make_struct(Elements&&... args)
196 {
197 using result_type = Struct<std::decay_t<Elements>...>;
198 return result_type(std::forward<Elements>(args)...);
199 }
200
201 /********************************************/
207 class ObjectPath : public std::string
208 {
209 public:
210 ObjectPath() = default;
211 explicit ObjectPath(std::string value)
212 : std::string(std::move(value))
213 {}
214 explicit ObjectPath(const char* value)
215 : std::string(value)
216 {}
217
218 using std::string::operator=;
219 };
220
221 /********************************************/
227 class BusName : public std::string
228 {
229 public:
230 BusName() = default;
231 explicit BusName(std::string value)
232 : std::string(std::move(value))
233 {}
234 explicit BusName(const char* value)
235 : std::string(value)
236 {}
237
238 using std::string::operator=;
239 };
240
241 using ServiceName = BusName;
242 using ConnectionName = BusName;
243
244 /********************************************/
250 class InterfaceName : public std::string
251 {
252 public:
253 InterfaceName() = default;
254 explicit InterfaceName(std::string value)
255 : std::string(std::move(value))
256 {}
257 explicit InterfaceName(const char* value)
258 : std::string(value)
259 {}
260
261 using std::string::operator=;
262 };
263
264 /********************************************/
270 class MemberName : public std::string
271 {
272 public:
273 MemberName() = default;
274 explicit MemberName(std::string value)
275 : std::string(std::move(value))
276 {}
277 explicit MemberName(const char* value)
278 : std::string(value)
279 {}
280
281 using std::string::operator=;
282 };
283
284 using MethodName = MemberName;
285 using SignalName = MemberName;
286 using PropertyName = MemberName;
287
288 /********************************************/
294 class Signature : public std::string
295 {
296 public:
297 Signature() = default;
298 explicit Signature(std::string value)
299 : std::string(std::move(value))
300 {}
301 explicit Signature(const char* value)
302 : std::string(value)
303 {}
304
305 using std::string::operator=;
306 };
307
308 /********************************************/
319 class UnixFd
320 {
321 public:
322 UnixFd() = default;
323
324 explicit UnixFd(int fd)
325 : fd_(checkedDup(fd))
326 {
327 }
328
329 UnixFd(int fd, adopt_fd_t)
330 : fd_(fd)
331 {
332 }
333
334 UnixFd(const UnixFd& other)
335 {
336 *this = other;
337 }
338
339 UnixFd& operator=(const UnixFd& other)
340 {
341 if (this == &other)
342 {
343 return *this;
344 }
345 close();
346 fd_ = checkedDup(other.fd_);
347 return *this;
348 }
349
350 UnixFd(UnixFd&& other) noexcept
351 {
352 *this = std::move(other);
353 }
354
355 UnixFd& operator=(UnixFd&& other) noexcept
356 {
357 if (this == &other)
358 {
359 return *this;
360 }
361 close();
362 fd_ = std::exchange(other.fd_, -1);
363 return *this;
364 }
365
366 ~UnixFd()
367 {
368 close();
369 }
370
371 [[nodiscard]] int get() const
372 {
373 return fd_;
374 }
375
376 void reset(int fd = -1)
377 {
378 *this = UnixFd{fd};
379 }
380
381 void reset(int fd, adopt_fd_t)
382 {
383 *this = UnixFd{fd, adopt_fd};
384 }
385
386 int release()
387 {
388 return std::exchange(fd_, -1);
389 }
390
391 [[nodiscard]] bool isValid() const
392 {
393 return fd_ >= 0;
394 }
395
396 private:
398 void close();
399
402 static int checkedDup(int fd);
403
404 int fd_ = -1;
405 };
406
407 /********************************************/
414 template<typename T1, typename T2>
415 using DictEntry = std::pair<T1, T2>;
416
417} // namespace sdbus
418
419// Making sdbus::Struct implement the tuple-protocol, i.e. be a tuple-like type
420template <size_t I, typename... ValueTypes>
421struct std::tuple_element<I, sdbus::Struct<ValueTypes...>> // NOLINT(cert-dcl58-cpp): specialization in std namespace allowed in this case
422 : std::tuple_element<I, std::tuple<ValueTypes...>>
423{};
424template <typename... ValueTypes>
425struct std::tuple_size<sdbus::Struct<ValueTypes...>> // NOLINT(cert-dcl58-cpp): specialization in std namespace allowed in this case
426 : std::tuple_size<std::tuple<ValueTypes...>>
427{};
428
429// NOLINTBEGIN(cppcoreguidelines-macro-usage)
430
431/********************************************/
468#define SDBUSCPP_REGISTER_STRUCT(STRUCT, ...) \
469 namespace sdbus { \
470 static_assert(SDBUSCPP_PP_NARG(__VA_ARGS__) <= 16, \
471 "Not more than 16 struct members are supported, please open an issue if you need more"); \
472 \
473 template <> \
474 struct signature_of<STRUCT> \
475 : signature_of<Struct<SDBUSCPP_STRUCT_MEMBER_TYPES(STRUCT, __VA_ARGS__)>> \
476 {}; \
477 \
478 inline auto as_dictionary_if_struct(const STRUCT& object) \
479 { \
480 return as_dictionary<STRUCT>(object); \
481 } \
482 \
483 inline Message& operator<<(Message& msg, const STRUCT& items) \
484 { \
485 return msg << Struct{std::forward_as_tuple(SDBUSCPP_STRUCT_MEMBERS(items, __VA_ARGS__))}; \
486 } \
487 \
488 inline Message& operator<<(Message& msg, const as_dictionary<STRUCT>& s) \
489 { \
490 if constexpr (!nested_struct_as_dict_serialization_v<STRUCT>) \
491 return msg.serializeDictionary<std::string, Variant>({SDBUSCPP_STRUCT_MEMBERS_AS_DICT_ENTRIES(s.m_struct, __VA_ARGS__)}); \
492 else \
493 return msg.serializeDictionary<std::string, Variant>({SDBUSCPP_STRUCT_MEMBERS_AS_NESTED_DICT_ENTRIES(s.m_struct, __VA_ARGS__)}); \
494 } \
495 \
496 inline Message& operator>>(Message& msg, STRUCT& s) \
497 { \
498 /* First, try to deserialize as a struct */ \
499 if (msg.peekType().first == signature_of<STRUCT>::type_value) \
500 { \
501 Struct sdbusStruct{std::forward_as_tuple(SDBUSCPP_STRUCT_MEMBERS(s, __VA_ARGS__))}; \
502 return msg >> sdbusStruct; \
503 } \
504 \
505 /* Otherwise try to deserialize as a dictionary of strings to variants */ \
506 \
507 return msg.deserializeDictionary<std::string, Variant>([&s](const auto& dictEntry) \
508 { \
509 const std::string& key = dictEntry.first; /* Intentionally not using structured bindings */ \
510 const Variant& value = dictEntry.second; \
511 \
512 using namespace std::string_literals; \
513 /* This also handles members which are structs serialized as dict of strings to variants, recursively */ \
514 SDBUSCPP_FIND_AND_DESERIALIZE_STRUCT_MEMBERS(s, __VA_ARGS__) \
515 SDBUS_THROW_ERROR_IF( strict_dict_as_struct_deserialization_v<STRUCT> \
516 , ("Failed to deserialize struct from a dictionary: could not find field '"s += key) += "' in struct 'my::Struct'" \
517 , EINVAL ); \
518 }); \
519 } \
520 } \
521 /**/
522
523/********************************************/
535#define SDBUSCPP_ENABLE_RELAXED_DICT2STRUCT_DESERIALIZATION(STRUCT) \
536 template <> \
537 constexpr auto sdbus::strict_dict_as_struct_deserialization_v<STRUCT> = false; \
538 /**/
539
540/********************************************/
552#define SDBUSCPP_ENABLE_NESTED_STRUCT2DICT_SERIALIZATION(STRUCT) \
553 template <> \
554 constexpr auto sdbus::nested_struct_as_dict_serialization_v<STRUCT> = true \
555 /**/
556
562#define SDBUSCPP_STRUCT_MEMBERS(STRUCT, ...) \
563 SDBUSCPP_PP_CAT(SDBUSCPP_FOR_EACH_, SDBUSCPP_PP_NARG(__VA_ARGS__))(SDBUSCPP_STRUCT_MEMBER, SDBUSCPP_PP_COMMA, STRUCT, __VA_ARGS__) \
564 /**/
565#define SDBUSCPP_STRUCT_MEMBER(STRUCT, MEMBER) STRUCT.MEMBER
566
567#define SDBUSCPP_STRUCT_MEMBER_TYPES(STRUCT, ...) \
568 SDBUSCPP_PP_CAT(SDBUSCPP_FOR_EACH_, SDBUSCPP_PP_NARG(__VA_ARGS__))(SDBUSCPP_STRUCT_MEMBER_TYPE, SDBUSCPP_PP_COMMA, STRUCT, __VA_ARGS__) \
569 /**/
570#define SDBUSCPP_STRUCT_MEMBER_TYPE(STRUCT, MEMBER) decltype(STRUCT::MEMBER)
571
572#define SDBUSCPP_STRUCT_MEMBERS_AS_DICT_ENTRIES(STRUCT, ...) \
573 SDBUSCPP_PP_CAT(SDBUSCPP_FOR_EACH_, SDBUSCPP_PP_NARG(__VA_ARGS__))(SDBUSCPP_STRUCT_MEMBER_AS_DICT_ENTRY, SDBUSCPP_PP_COMMA, STRUCT, __VA_ARGS__) \
574 /**/
575#define SDBUSCPP_STRUCT_MEMBER_AS_DICT_ENTRY(STRUCT, MEMBER) {#MEMBER, Variant{STRUCT.MEMBER}}
576
577#define SDBUSCPP_STRUCT_MEMBERS_AS_NESTED_DICT_ENTRIES(STRUCT, ...) \
578 SDBUSCPP_PP_CAT(SDBUSCPP_FOR_EACH_, SDBUSCPP_PP_NARG(__VA_ARGS__))(SDBUSCPP_STRUCT_MEMBER_AS_NESTED_DICT_ENTRY, SDBUSCPP_PP_COMMA, STRUCT, __VA_ARGS__) \
579 /**/
580#define SDBUSCPP_STRUCT_MEMBER_AS_NESTED_DICT_ENTRY(STRUCT, MEMBER) {#MEMBER, Variant{as_dictionary_if_struct(STRUCT.MEMBER)}}
581
582#define SDBUSCPP_FIND_AND_DESERIALIZE_STRUCT_MEMBERS(STRUCT, ...) \
583 SDBUSCPP_PP_CAT(SDBUSCPP_FOR_EACH_, SDBUSCPP_PP_NARG(__VA_ARGS__))(SDBUSCPP_FIND_AND_DESERIALIZE_STRUCT_MEMBER, SDBUSCPP_PP_SPACE, STRUCT, __VA_ARGS__) \
584 /**/
585#define SDBUSCPP_FIND_AND_DESERIALIZE_STRUCT_MEMBER(STRUCT, MEMBER) if (key == #MEMBER) STRUCT.MEMBER = value.get<decltype(STRUCT.MEMBER)>(); else
586
587#define SDBUSCPP_FOR_EACH_1(M, D, S, M1) M(S, M1)
588#define SDBUSCPP_FOR_EACH_2(M, D, S, M1, M2) M(S, M1) D M(S, M2)
589#define SDBUSCPP_FOR_EACH_3(M, D, S, M1, M2, M3) M(S, M1) D M(S, M2) D M(S, M3)
590#define SDBUSCPP_FOR_EACH_4(M, D, S, M1, M2, M3, M4) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4)
591#define SDBUSCPP_FOR_EACH_5(M, D, S, M1, M2, M3, M4, M5) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5)
592#define SDBUSCPP_FOR_EACH_6(M, D, S, M1, M2, M3, M4, M5, M6) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6)
593#define SDBUSCPP_FOR_EACH_7(M, D, S, M1, M2, M3, M4, M5, M6, M7) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7)
594#define SDBUSCPP_FOR_EACH_8(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8)
595#define SDBUSCPP_FOR_EACH_9(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8, M9) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) D M(S, M9)
596#define SDBUSCPP_FOR_EACH_10(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) D M(S, M9) D M(S, M10)
597#define SDBUSCPP_FOR_EACH_11(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) D M(S, M9) D M(S, M10) D M(S, M11)
598#define SDBUSCPP_FOR_EACH_12(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) D M(S, M9) D M(S, M10) D M(S, M11) D M(S, M12)
599#define SDBUSCPP_FOR_EACH_13(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) D M(S, M9) D M(S, M10) D M(S, M11) D M(S, M12) D M(S, M13)
600#define SDBUSCPP_FOR_EACH_14(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13, M14) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) D M(S, M9) D M(S, M10) D M(S, M11) D M(S, M12) D M(S, M13) D M(S, M14)
601#define SDBUSCPP_FOR_EACH_15(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13, M14, M15) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) D M(S, M9) D M(S, M10) D M(S, M11) D M(S, M12) D M(S, M13) D M(S, M14) D M(S, M15)
602#define SDBUSCPP_FOR_EACH_16(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13, M14, M15, M16) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) D M(S, M9) D M(S, M10) D M(S, M11) D M(S, M12) D M(S, M13) D M(S, M14) D M(S, M15) D M(S, M16)
603
604#define SDBUSCPP_PP_CAT(X, Y) SDBUSCPP_PP_CAT_IMPL(X, Y)
605#define SDBUSCPP_PP_CAT_IMPL(X, Y) X##Y
606#define SDBUSCPP_PP_NARG(...) SDBUSCPP_PP_NARG_IMPL(__VA_ARGS__, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
607#define SDBUSCPP_PP_NARG_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _N, ...) _N
608
609#define SDBUSCPP_PP_COMMA ,
610#define SDBUSCPP_PP_SPACE
611
612// NOLINTEND(cppcoreguidelines-macro-usage)
613
614#endif /* SDBUS_CXX_TYPES_H_ */
std::pair< T1, T2 > DictEntry
Definition Types.h:415
Definition Types.h:228
Definition Types.h:271
Definition Message.h:81
Definition Message.h:345
Definition Types.h:160
Definition TypeTraits.h:97
Definition TypeTraits.h:609
Definition TypeTraits.h:110