sdbus-c++ 2.0.0
High-level C++ D-Bus library based on systemd D-Bus implementation
Loading...
Searching...
No Matches
TypeTraits.h
Go to the documentation of this file.
1
27#ifndef SDBUS_CXX_TYPETRAITS_H_
28#define SDBUS_CXX_TYPETRAITS_H_
29
30#include <sdbus-c++/Error.h>
31
32#include <array>
33#include <cstdint>
34#include <functional>
35#include <map>
36#include <memory>
37#include <optional>
38#ifdef __has_include
39# if __has_include(<span>)
40# include <span>
41# endif
42#endif
43#include <string>
44#include <string_view>
45#include <tuple>
46#include <type_traits>
47#include <unordered_map>
48#include <utility>
49#include <variant>
50#include <vector>
51
52// Forward declarations
53namespace sdbus {
54 class Variant;
55 template <typename... _ValueTypes> class Struct;
56 class ObjectPath;
57 class Signature;
58 class UnixFd;
59 template<typename _T1, typename _T2> using DictEntry = std::pair<_T1, _T2>;
60 class BusName;
61 class InterfaceName;
62 class MemberName;
63 class MethodCall;
64 class MethodReply;
65 class Signal;
66 class Message;
67 class PropertySetCall;
68 class PropertyGetReply;
69 template <typename... _Results> class Result;
70 class Error;
71 template <typename _T, typename _Enable = void> struct signature_of;
72}
73
74namespace sdbus {
75
76 // Callbacks from sdbus-c++
77 using method_callback = std::function<void(MethodCall msg)>;
78 using async_reply_handler = std::function<void(MethodReply reply, std::optional<Error> error)>;
79 using signal_handler = std::function<void(Signal signal)>;
80 using message_handler = std::function<void(Message msg)>;
81 using property_set_callback = std::function<void(PropertySetCall msg)>;
82 using property_get_callback = std::function<void(PropertyGetReply& reply)>;
83
84 // Type-erased RAII-style handle to callbacks/subscriptions registered to sdbus-c++
85 using Slot = std::unique_ptr<void, std::function<void(void*)>>;
86
87 // Tag specifying that an owning handle (so-called slot) of the logical resource shall be provided to the client
88 struct return_slot_t { explicit return_slot_t() = default; };
89 inline constexpr return_slot_t return_slot{};
90 // Tag specifying that the library shall own the slot resulting from the call of the function (so-called floating slot)
91 struct floating_slot_t { explicit floating_slot_t() = default; };
92 inline constexpr floating_slot_t floating_slot{};
93 // Tag denoting the assumption that the caller has already obtained message ownership
94 struct adopt_message_t { explicit adopt_message_t() = default; };
95 inline constexpr adopt_message_t adopt_message{};
96 // Tag denoting the assumption that the caller has already obtained fd ownership
97 struct adopt_fd_t { explicit adopt_fd_t() = default; };
98 inline constexpr adopt_fd_t adopt_fd{};
99 // Tag specifying that the proxy shall not run an event loop thread on its D-Bus connection.
100 // Such proxies are typically created to carry out a simple synchronous D-Bus call(s) and then are destroyed.
102 inline constexpr dont_run_event_loop_thread_t dont_run_event_loop_thread{};
103 // Tag denoting an asynchronous call that returns std::future as a handle
104 struct with_future_t { explicit with_future_t() = default; };
105 inline constexpr with_future_t with_future{};
106 // Tag denoting a call where the reply shouldn't be waited for
107 struct dont_expect_reply_t { explicit dont_expect_reply_t() = default; };
108 inline constexpr dont_expect_reply_t dont_expect_reply{};
109
110 // Helper for static assert
111 template <class... _T> constexpr bool always_false = false;
112
113 // Helper operator+ for concatenation of `std::array`s
114 template <typename _T, std::size_t _N1, std::size_t _N2>
115 constexpr std::array<_T, _N1 + _N2> operator+(std::array<_T, _N1> lhs, std::array<_T, _N2> rhs);
116
117 // Template specializations for getting D-Bus signatures from C++ types
118 template <typename _T>
119 constexpr auto signature_of_v = signature_of<_T>::value;
120
121 template <typename _T, typename _Enable>
123 {
124 static constexpr bool is_valid = false;
125 static constexpr bool is_trivial_dbus_type = false;
126
127 static constexpr void* value = []
128 {
129 // See using-sdbus-c++.md, section "Extending sdbus-c++ type system",
130 // on how to teach sdbus-c++ about your custom types
131 static_assert(always_false<_T>, "Unsupported D-Bus type (specialize `signature_of` for your custom types)");
132 };
133 };
134
135 template <typename _T>
136 struct signature_of<const _T> : signature_of<_T>
137 {};
138
139 template <typename _T>
140 struct signature_of<volatile _T> : signature_of<_T>
141 {};
142
143 template <typename _T>
144 struct signature_of<const volatile _T> : signature_of<_T>
145 {};
146
147 template <typename _T>
149 {};
150
151 template <>
152 struct signature_of<void>
153 {
154 static constexpr std::array<char, 0> value{};
155 static constexpr bool is_valid = true;
156 static constexpr bool is_trivial_dbus_type = false;
157 };
158
159 template <>
160 struct signature_of<bool>
161 {
162 static constexpr std::array value{'b'};
163 static constexpr bool is_valid = true;
164 static constexpr bool is_trivial_dbus_type = true;
165 };
166
167 template <>
168 struct signature_of<uint8_t>
169 {
170 static constexpr std::array value{'y'};
171 static constexpr bool is_valid = true;
172 static constexpr bool is_trivial_dbus_type = true;
173 };
174
175 template <>
176 struct signature_of<int16_t>
177 {
178 static constexpr std::array value{'n'};
179 static constexpr bool is_valid = true;
180 static constexpr bool is_trivial_dbus_type = true;
181 };
182
183 template <>
184 struct signature_of<uint16_t>
185 {
186 static constexpr std::array value{'q'};
187 static constexpr bool is_valid = true;
188 static constexpr bool is_trivial_dbus_type = true;
189 };
190
191 template <>
192 struct signature_of<int32_t>
193 {
194 static constexpr std::array value{'i'};
195 static constexpr bool is_valid = true;
196 static constexpr bool is_trivial_dbus_type = true;
197 };
198
199 template <>
200 struct signature_of<uint32_t>
201 {
202 static constexpr std::array value{'u'};
203 static constexpr bool is_valid = true;
204 static constexpr bool is_trivial_dbus_type = true;
205 };
206
207 template <>
208 struct signature_of<int64_t>
209 {
210 static constexpr std::array value{'x'};
211 static constexpr bool is_valid = true;
212 static constexpr bool is_trivial_dbus_type = true;
213 };
214
215 template <>
216 struct signature_of<uint64_t>
217 {
218 static constexpr std::array value{'t'};
219 static constexpr bool is_valid = true;
220 static constexpr bool is_trivial_dbus_type = true;
221 };
222
223 template <>
224 struct signature_of<double>
225 {
226 static constexpr std::array value{'d'};
227 static constexpr bool is_valid = true;
228 static constexpr bool is_trivial_dbus_type = true;
229 };
230
231 template <>
232 struct signature_of<std::string>
233 {
234 static constexpr std::array value{'s'};
235 static constexpr bool is_valid = true;
236 static constexpr bool is_trivial_dbus_type = false;
237 };
238
239 template <>
240 struct signature_of<std::string_view> : signature_of<std::string>
241 {};
242
243 template <>
245 {};
246
247 template <>
249 {};
250
251 template <std::size_t _N>
252 struct signature_of<char[_N]> : signature_of<std::string>
253 {};
254
255 template <std::size_t _N>
256 struct signature_of<const char[_N]> : signature_of<std::string>
257 {};
258
259 template <>
260 struct signature_of<BusName> : signature_of<std::string>
261 {};
262
263 template <>
265 {};
266
267 template <>
268 struct signature_of<MemberName> : signature_of<std::string>
269 {};
270
271 template <typename... _ValueTypes>
272 struct signature_of<Struct<_ValueTypes...>>
273 {
274 static constexpr std::array contents = (signature_of_v<_ValueTypes> + ...);
275 static constexpr std::array value = std::array{'('} + contents + std::array{')'};
276 static constexpr bool is_valid = true;
277 static constexpr bool is_trivial_dbus_type = false;
278 };
279
280 template <>
282 {
283 static constexpr std::array value{'v'};
284 static constexpr bool is_valid = true;
285 static constexpr bool is_trivial_dbus_type = false;
286 };
287
288 template <typename... Elements>
289 struct signature_of<std::variant<Elements...>> : signature_of<Variant>
290 {};
291
292 template <>
294 {
295 static constexpr std::array value{'o'};
296 static constexpr bool is_valid = true;
297 static constexpr bool is_trivial_dbus_type = false;
298 };
299
300 template <>
302 {
303 static constexpr std::array value{'g'};
304 static constexpr bool is_valid = true;
305 static constexpr bool is_trivial_dbus_type = false;
306 };
307
308 template <>
310 {
311 static constexpr std::array value{'h'};
312 static constexpr bool is_valid = true;
313 static constexpr bool is_trivial_dbus_type = false;
314 };
315
316 template <typename _T1, typename _T2>
317 struct signature_of<DictEntry<_T1, _T2>>
318 {
319 static constexpr std::array value = std::array{'{'} + signature_of_v<std::tuple<_T1, _T2>> + std::array{'}'};
320 static constexpr bool is_valid = true;
321 static constexpr bool is_trivial_dbus_type = false;
322 };
323
324 template <typename _Element, typename _Allocator>
325 struct signature_of<std::vector<_Element, _Allocator>>
326 {
327 static constexpr std::array value = std::array{'a'} + signature_of_v<_Element>;
328 static constexpr bool is_valid = true;
329 static constexpr bool is_trivial_dbus_type = false;
330 };
331
332 template <typename _Element, std::size_t _Size>
333 struct signature_of<std::array<_Element, _Size>> : signature_of<std::vector<_Element>>
334 {
335 };
336
337#ifdef __cpp_lib_span
338 template <typename _Element, std::size_t _Extent>
339 struct signature_of<std::span<_Element, _Extent>> : signature_of<std::vector<_Element>>
340 {
341 };
342#endif
343
344 template <typename _Enum> // is_const_v and is_volatile_v to avoid ambiguity conflicts with const and volatile specializations of signature_of
345 struct signature_of<_Enum, typename std::enable_if_t<std::is_enum_v<_Enum> && !std::is_const_v<_Enum> && !std::is_volatile_v<_Enum>>>
346 : signature_of<std::underlying_type_t<_Enum>>
347 {};
348
349 template <typename _Key, typename _Value, typename _Compare, typename _Allocator>
350 struct signature_of<std::map<_Key, _Value, _Compare, _Allocator>>
351 {
352 static constexpr std::array contents = signature_of_v<std::tuple<_Key, _Value>>;
353 static constexpr std::array dict_entry = std::array{'{'} + contents + std::array{'}'};
354 static constexpr std::array value = std::array{'a'} + dict_entry;
355 static constexpr bool is_valid = true;
356 static constexpr bool is_trivial_dbus_type = false;
357 };
358
359 template <typename _Key, typename _Value, typename _Hash, typename _KeyEqual, typename _Allocator>
360 struct signature_of<std::unordered_map<_Key, _Value, _Hash, _KeyEqual, _Allocator>>
361 : signature_of<std::map<_Key, _Value>>
362 {
363 };
364
365 template <typename... _Types>
366 struct signature_of<std::tuple<_Types...>> // A simple concatenation of signatures of _Types
367 {
368 static constexpr std::array value = (std::array<char, 0>{} + ... + signature_of_v<_Types>);
369 static constexpr bool is_valid = false;
370 static constexpr bool is_trivial_dbus_type = false;
371 };
372
373 // To simplify conversions of arrays to C strings
374 template <typename _T, std::size_t _N>
375 constexpr auto as_null_terminated(std::array<_T, _N> arr)
376 {
377 return arr + std::array<_T, 1>{0};
378 }
379
380 // Function traits implementation inspired by (c) kennytm,
381 // https://github.com/kennytm/utils/blob/master/traits.hpp
382 template <typename _Type>
383 struct function_traits : function_traits<decltype(&_Type::operator())>
384 {};
385
386 template <typename _Type>
387 struct function_traits<const _Type> : function_traits<_Type>
388 {};
389
390 template <typename _Type>
392 {};
393
394 template <typename _ReturnType, typename... _Args>
396 {
397 typedef _ReturnType result_type;
398 typedef std::tuple<_Args...> arguments_type;
399 typedef std::tuple<std::decay_t<_Args>...> decayed_arguments_type;
400
401 typedef _ReturnType function_type(_Args...);
402
403 static constexpr std::size_t arity = sizeof...(_Args);
404
405// template <size_t _Idx, typename _Enabled = void>
406// struct arg;
407//
408// template <size_t _Idx>
409// struct arg<_Idx, std::enable_if_t<(_Idx < arity)>>
410// {
411// typedef std::tuple_element_t<_Idx, arguments_type> type;
412// };
413//
414// template <size_t _Idx>
415// struct arg<_Idx, std::enable_if_t<!(_Idx < arity)>>
416// {
417// typedef void type;
418// };
419
420 template <size_t _Idx>
421 struct arg
422 {
423 typedef std::tuple_element_t<_Idx, std::tuple<_Args...>> type;
424 };
425
426 template <size_t _Idx>
427 using arg_t = typename arg<_Idx>::type;
428 };
429
430 template <typename _ReturnType, typename... _Args>
431 struct function_traits<_ReturnType(_Args...)> : function_traits_base<_ReturnType, _Args...>
432 {
433 static constexpr bool is_async = false;
434 static constexpr bool has_error_param = false;
435 };
436
437 template <typename... _Args>
438 struct function_traits<void(std::optional<Error>, _Args...)> : function_traits_base<void, _Args...>
439 {
440 static constexpr bool has_error_param = true;
441 };
442
443 template <typename... _Args, typename... _Results>
444 struct function_traits<void(Result<_Results...>, _Args...)> : function_traits_base<std::tuple<_Results...>, _Args...>
445 {
446 static constexpr bool is_async = true;
447 using async_result_t = Result<_Results...>;
448 };
449
450 template <typename... _Args, typename... _Results>
451 struct function_traits<void(Result<_Results...>&&, _Args...)> : function_traits_base<std::tuple<_Results...>, _Args...>
452 {
453 static constexpr bool is_async = true;
454 using async_result_t = Result<_Results...>;
455 };
456
457 template <typename _ReturnType, typename... _Args>
458 struct function_traits<_ReturnType(*)(_Args...)> : function_traits<_ReturnType(_Args...)>
459 {};
460
461 template <typename _ClassType, typename _ReturnType, typename... _Args>
462 struct function_traits<_ReturnType(_ClassType::*)(_Args...)> : function_traits<_ReturnType(_Args...)>
463 {
464 typedef _ClassType& owner_type;
465 };
466
467 template <typename _ClassType, typename _ReturnType, typename... _Args>
468 struct function_traits<_ReturnType(_ClassType::*)(_Args...) const> : function_traits<_ReturnType(_Args...)>
469 {
470 typedef const _ClassType& owner_type;
471 };
472
473 template <typename _ClassType, typename _ReturnType, typename... _Args>
474 struct function_traits<_ReturnType(_ClassType::*)(_Args...) volatile> : function_traits<_ReturnType(_Args...)>
475 {
476 typedef volatile _ClassType& owner_type;
477 };
478
479 template <typename _ClassType, typename _ReturnType, typename... _Args>
480 struct function_traits<_ReturnType(_ClassType::*)(_Args...) const volatile> : function_traits<_ReturnType(_Args...)>
481 {
482 typedef const volatile _ClassType& owner_type;
483 };
484
485 template <typename FunctionType>
486 struct function_traits<std::function<FunctionType>> : function_traits<FunctionType>
487 {};
488
489 template <class _Function>
490 constexpr auto is_async_method_v = function_traits<_Function>::is_async;
491
492 template <class _Function>
493 constexpr auto has_error_param_v = function_traits<_Function>::has_error_param;
494
495 template <typename _FunctionType>
496 using function_arguments_t = typename function_traits<_FunctionType>::arguments_type;
497
498 template <typename _FunctionType, size_t _Idx>
499 using function_argument_t = typename function_traits<_FunctionType>::template arg_t<_Idx>;
500
501 template <typename _FunctionType>
502 constexpr auto function_argument_count_v = function_traits<_FunctionType>::arity;
503
504 template <typename _FunctionType>
505 using function_result_t = typename function_traits<_FunctionType>::result_type;
506
507 template <typename _Function>
509 {
511 };
512
513 template <typename _Function>
514 using tuple_of_function_input_arg_types_t = typename tuple_of_function_input_arg_types<_Function>::type;
515
516 template <typename _Function>
518 {
519 typedef typename function_traits<_Function>::result_type type;
520 };
521
522 template <typename _Function>
523 using tuple_of_function_output_arg_types_t = typename tuple_of_function_output_arg_types<_Function>::type;
524
525 template <typename _Function>
526 struct signature_of_function_input_arguments : signature_of<tuple_of_function_input_arg_types_t<_Function>>
527 {
528 static std::string value_as_string()
529 {
530 constexpr auto signature = as_null_terminated(signature_of_v<tuple_of_function_input_arg_types_t<_Function>>);
531 return signature.data();
532 }
533 };
534
535 template <typename _Function>
536 inline auto signature_of_function_input_arguments_v = signature_of_function_input_arguments<_Function>::value_as_string();
537
538 template <typename _Function>
539 struct signature_of_function_output_arguments : signature_of<tuple_of_function_output_arg_types_t<_Function>>
540 {
541 static std::string value_as_string()
542 {
543 constexpr auto signature = as_null_terminated(signature_of_v<tuple_of_function_output_arg_types_t<_Function>>);
544 return signature.data();
545 }
546 };
547
548 template <typename _Function>
549 inline auto signature_of_function_output_arguments_v = signature_of_function_output_arguments<_Function>::value_as_string();
550
551 // std::future stuff for return values of async calls
552 template <typename... _Args> struct future_return
553 {
554 typedef std::tuple<_Args...> type;
555 };
556
557 template <> struct future_return<>
558 {
559 typedef void type;
560 };
561
562 template <typename _Type> struct future_return<_Type>
563 {
564 typedef _Type type;
565 };
566
567 template <typename... _Args>
568 using future_return_t = typename future_return<_Args...>::type;
569
570 // Credit: Piotr Skotnicki (https://stackoverflow.com/a/57639506)
571 template <typename, typename>
572 constexpr bool is_one_of_variants_types = false;
573
574 template <typename... _VariantTypes, typename _QueriedType>
575 constexpr bool is_one_of_variants_types<std::variant<_VariantTypes...>, _QueriedType>
576 = (std::is_same_v<_QueriedType, _VariantTypes> || ...);
577
578 namespace detail
579 {
580 template <class _Function, class _Tuple, typename... _Args, std::size_t... _I>
581 constexpr decltype(auto) apply_impl( _Function&& f
582 , Result<_Args...>&& r
583 , _Tuple&& t
584 , std::index_sequence<_I...> )
585 {
586 return std::forward<_Function>(f)(std::move(r), std::get<_I>(std::forward<_Tuple>(t))...);
587 }
588
589 template <class _Function, class _Tuple, std::size_t... _I>
590 decltype(auto) apply_impl( _Function&& f
591 , std::optional<Error> e
592 , _Tuple&& t
593 , std::index_sequence<_I...> )
594 {
595 return std::forward<_Function>(f)(std::move(e), std::get<_I>(std::forward<_Tuple>(t))...);
596 }
597
598 // For non-void returning functions, apply_impl simply returns function return value (a tuple of values).
599 // For void-returning functions, apply_impl returns an empty tuple.
600 template <class _Function, class _Tuple, std::size_t... _I>
601 constexpr decltype(auto) apply_impl( _Function&& f
602 , _Tuple&& t
603 , std::index_sequence<_I...> )
604 {
605 if constexpr (!std::is_void_v<function_result_t<_Function>>)
606 return std::forward<_Function>(f)(std::get<_I>(std::forward<_Tuple>(t))...);
607 else
608 return std::forward<_Function>(f)(std::get<_I>(std::forward<_Tuple>(t))...), std::tuple<>{};
609 }
610 }
611
612 // Convert tuple `t' of values into a list of arguments
613 // and invoke function `f' with those arguments.
614 template <class _Function, class _Tuple>
615 constexpr decltype(auto) apply(_Function&& f, _Tuple&& t)
616 {
617 return detail::apply_impl( std::forward<_Function>(f)
618 , std::forward<_Tuple>(t)
619 , std::make_index_sequence<std::tuple_size<std::decay_t<_Tuple>>::value>{} );
620 }
621
622 // Convert tuple `t' of values into a list of arguments
623 // and invoke function `f' with those arguments.
624 template <class _Function, class _Tuple, typename... _Args>
625 constexpr decltype(auto) apply(_Function&& f, Result<_Args...>&& r, _Tuple&& t)
626 {
627 return detail::apply_impl( std::forward<_Function>(f)
628 , std::move(r)
629 , std::forward<_Tuple>(t)
630 , std::make_index_sequence<std::tuple_size<std::decay_t<_Tuple>>::value>{} );
631 }
632
633 // Convert tuple `t' of values into a list of arguments
634 // and invoke function `f' with those arguments.
635 template <class _Function, class _Tuple>
636 decltype(auto) apply(_Function&& f, std::optional<Error> e, _Tuple&& t)
637 {
638 return detail::apply_impl( std::forward<_Function>(f)
639 , std::move(e)
640 , std::forward<_Tuple>(t)
641 , std::make_index_sequence<std::tuple_size<std::decay_t<_Tuple>>::value>{} );
642 }
643
644 // Convenient concatenation of arrays
645 template <typename _T, std::size_t _N1, std::size_t _N2>
646 constexpr std::array<_T, _N1 + _N2> operator+(std::array<_T, _N1> lhs, std::array<_T, _N2> rhs)
647 {
648 std::array<_T, _N1 + _N2> result{};
649 std::size_t index = 0;
650
651 for (auto& el : lhs) {
652 result[index] = std::move(el);
653 ++index;
654 }
655 for (auto& el : rhs) {
656 result[index] = std::move(el);
657 ++index;
658 }
659
660 return result;
661 }
662
663}
664
665#endif /* SDBUS_CXX_TYPETRAITS_H_ */
std::pair< _T1, _T2 > DictEntry
Definition Types.h:384
Definition Types.h:197
Definition Types.h:220
Definition Types.h:240
Definition Types.h:177
Definition MethodResult.h:51
Definition Types.h:264
Definition Types.h:135
Definition Types.h:289
Definition Types.h:56
Definition TypeTraits.h:97
Definition TypeTraits.h:94
Definition TypeTraits.h:107
Definition TypeTraits.h:101
Definition TypeTraits.h:91
Definition TypeTraits.h:422
Definition TypeTraits.h:396
Definition TypeTraits.h:384
Definition TypeTraits.h:553
Definition TypeTraits.h:88
Definition TypeTraits.h:123
Definition TypeTraits.h:509
Definition TypeTraits.h:104