1 #pragma once
2 
3 #include <sdbusplus/async/proxy.hpp>
4 
5 namespace sdbusplus::async
6 {
7 
8 namespace client
9 {
10 
11 namespace details
12 {
13 struct client_context_friend;
14 }
15 
16 /** An aggregation class of sdbusplus::async::proxy-based client types.
17  *
18  *  The resulting class acts as a union of all Types from the template
19  *  arguments.
20  *
21  *  Like a `proxy`, the class only becomes functional once the service and
22  *  path are populated.
23  */
24 template <bool S, bool P, bool Preserved,
25           template <typename, typename> typename... Types>
26 class client :
27     public context_ref,
28     public Types<client<S, P, Preserved, Types...>,
29                  sdbusplus::async::proxy_ns::proxy<S, P, false, Preserved>>...
30 {
31   public:
32     using Self = client<S, P, Preserved, Types...>;
33     using Proxy = sdbusplus::async::proxy_ns::proxy<S, P, false, Preserved>;
34     friend details::client_context_friend;
35 
36   private:
37     Proxy proxy{};
38 
39   public:
40     constexpr client() = delete;
41     /* Delete default constructor if Service or Path have been provided. */
42     explicit client(sdbusplus::async::context& ctx)
43         requires(S || P)
44     = delete;
45     /* Default (empty) constructor only when Service and Path are missing. */
46     explicit client(sdbusplus::async::context& ctx)
47         requires(!S && !P)
48         : context_ref(ctx), Types<Self, Proxy>(Proxy{})...
49     {}
50 
51     /* Conversion constructor for a non-empty (Service and/or Path) proxy. */
52     explicit client(sdbusplus::async::context& ctx, Proxy p)
53         requires(S || P)
54         : context_ref(ctx), Types<Self, Proxy>(p)..., proxy(p)
55     {}
56 
57     /* Convert a non-Service instance to a Service instance. */
58     auto service(auto& s) const noexcept
59         requires(!S)
60     {
61         return client<true, P, Preserved, Types...>(ctx, proxy.service(s));
62     }
63 
64     /* Convert a non-Path instance to a Path instance. */
65     auto path(auto& p) const noexcept
66         requires(!P)
67     {
68         return client<S, true, Preserved, Types...>(ctx, proxy.path(p));
69     }
70 };
71 
72 } // namespace client
73 
74 /** A non-Preserved client alias.
75  *
76  *  This holds Service/Path in string-views, which must exist longer than
77  *  the lifetime of this client_t.
78  */
79 template <template <typename, typename> typename... Types>
80 using client_t = client::client<false, false, false, Types...>;
81 /** A Preserved client alias.
82  *
83  *  This holds Service/Path in strings, which thus have lifetimes that are
84  *  the same as the client itself.
85  */
86 template <template <typename, typename> typename... Types>
87 using client_preserved_t = client::client<false, false, false, Types...>;
88 
89 namespace client::details
90 {
91 /* Indirect so that the generated Types can access the client_t's context.
92  *
93  * If P2893 gets into C++26 we could eliminate this because we can set all
94  * the Types as friends directly.
95  */
96 struct client_context_friend
97 {
98     template <typename T>
99     sdbusplus::async::context& context()
100     {
101         return static_cast<T*>(this)->ctx;
102     }
103 };
104 } // namespace client::details
105 
106 } // namespace sdbusplus::async
107