xref: /openbmc/sdbusplus/include/sdbusplus/async/stdexec/__detail/__receivers.hpp (revision 10d0b4b7d1498cfd5c3d37edea271a54d1984e41)
1 /*
2  * Copyright (c) 2022-2024 NVIDIA Corporation
3  *
4  * Licensed under the Apache License Version 2.0 with LLVM Exceptions
5  * (the "License"); you may not use this file except in compliance with
6  * the License. You may obtain a copy of the License at
7  *
8  *   https://llvm.org/LICENSE.txt
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 
18 #include "__execution_fwd.hpp"
19 
20 #include "__concepts.hpp"
21 #include "__diagnostics.hpp"
22 #include "__env.hpp"
23 #include "__tag_invoke.hpp"
24 
25 #include "../functional.hpp"
26 
27 #include <exception>
28 
29 namespace stdexec {
30   /////////////////////////////////////////////////////////////////////////////
31   // [execution.receivers]
32   namespace __rcvrs {
33     template <class _Receiver, class... _As>
34     concept __set_value_member = requires(_Receiver &&__rcvr, _As &&...__args) {
35       static_cast<_Receiver &&>(__rcvr).set_value(static_cast<_As &&>(__args)...);
36     };
37 
38     struct set_value_t {
39       template <class _Fn, class... _As>
40       using __f = __minvoke<_Fn, _As...>;
41 
42       template <class _Receiver, class... _As>
43         requires __set_value_member<_Receiver, _As...>
STDEXEC_ATTRIBUTEstdexec::__rcvrs::set_value_t44       STDEXEC_ATTRIBUTE(host, device, always_inline)
45       void operator()(_Receiver &&__rcvr, _As &&...__as) const noexcept {
46         static_assert(
47           noexcept(static_cast<_Receiver &&>(__rcvr).set_value(static_cast<_As &&>(__as)...)),
48           "set_value member functions must be noexcept");
49         static_assert(
50           __same_as<
51             decltype(static_cast<_Receiver &&>(__rcvr).set_value(static_cast<_As &&>(__as)...)),
52             void
53           >,
54           "set_value member functions must return void");
55         static_cast<_Receiver &&>(__rcvr).set_value(static_cast<_As &&>(__as)...);
56       }
57 
58       template <class _Receiver, class... _As>
59         requires(!__set_value_member<_Receiver, _As...>)
60              && tag_invocable<set_value_t, _Receiver, _As...>
STDEXEC_ATTRIBUTEstdexec::__rcvrs::set_value_t61       STDEXEC_ATTRIBUTE(host, device, always_inline)
62       void operator()(_Receiver &&__rcvr, _As &&...__as) const noexcept {
63         static_assert(nothrow_tag_invocable<set_value_t, _Receiver, _As...>);
64         (void) tag_invoke(*this, static_cast<_Receiver &&>(__rcvr), static_cast<_As &&>(__as)...);
65       }
66     };
67 
68     template <class _Receiver, class _Error>
69     concept __set_error_member = requires(_Receiver &&__rcvr, _Error &&__err) {
70       static_cast<_Receiver &&>(__rcvr).set_error(static_cast<_Error &&>(__err));
71     };
72 
73     struct set_error_t {
74       template <class _Fn, class... _Args>
75         requires(sizeof...(_Args) == 1)
76       using __f = __minvoke<_Fn, _Args...>;
77 
78       template <class _Receiver, class _Error>
79         requires __set_error_member<_Receiver, _Error>
STDEXEC_ATTRIBUTEstdexec::__rcvrs::set_error_t80       STDEXEC_ATTRIBUTE(host, device, always_inline)
81       void operator()(_Receiver &&__rcvr, _Error &&__err) const noexcept {
82         static_assert(
83           noexcept(static_cast<_Receiver &&>(__rcvr).set_error(static_cast<_Error &&>(__err))),
84           "set_error member functions must be noexcept");
85         static_assert(
86           __same_as<
87             decltype(static_cast<_Receiver &&>(__rcvr).set_error(static_cast<_Error &&>(__err))),
88             void
89           >,
90           "set_error member functions must return void");
91         static_cast<_Receiver &&>(__rcvr).set_error(static_cast<_Error &&>(__err));
92       }
93 
94       template <class _Receiver, class _Error>
95         requires(!__set_error_member<_Receiver, _Error>)
96              && tag_invocable<set_error_t, _Receiver, _Error>
STDEXEC_ATTRIBUTEstdexec::__rcvrs::set_error_t97       STDEXEC_ATTRIBUTE(host, device, always_inline)
98       void operator()(_Receiver &&__rcvr, _Error &&__err) const noexcept {
99         static_assert(nothrow_tag_invocable<set_error_t, _Receiver, _Error>);
100         (void) tag_invoke(*this, static_cast<_Receiver &&>(__rcvr), static_cast<_Error &&>(__err));
101       }
102     };
103 
104     template <class _Receiver>
105     concept __set_stopped_member = requires(_Receiver &&__rcvr) {
106       static_cast<_Receiver &&>(__rcvr).set_stopped();
107     };
108 
109     struct set_stopped_t {
110       template <class _Fn, class... _Args>
111         requires(sizeof...(_Args) == 0)
112       using __f = __minvoke<_Fn, _Args...>;
113 
114       template <class _Receiver>
115         requires __set_stopped_member<_Receiver>
STDEXEC_ATTRIBUTEstdexec::__rcvrs::set_stopped_t116       STDEXEC_ATTRIBUTE(host, device, always_inline)
117       void operator()(_Receiver &&__rcvr) const noexcept {
118         static_assert(
119           noexcept(static_cast<_Receiver &&>(__rcvr).set_stopped()),
120           "set_stopped member functions must be noexcept");
121         static_assert(
122           __same_as<decltype(static_cast<_Receiver &&>(__rcvr).set_stopped()), void>,
123           "set_stopped member functions must return void");
124         static_cast<_Receiver &&>(__rcvr).set_stopped();
125       }
126 
127       template <class _Receiver>
128         requires(!__set_stopped_member<_Receiver>) && tag_invocable<set_stopped_t, _Receiver>
STDEXEC_ATTRIBUTEstdexec::__rcvrs::set_stopped_t129       STDEXEC_ATTRIBUTE(host, device, always_inline)
130       void operator()(_Receiver &&__rcvr) const noexcept {
131         static_assert(nothrow_tag_invocable<set_stopped_t, _Receiver>);
132         (void) tag_invoke(*this, static_cast<_Receiver &&>(__rcvr));
133       }
134     };
135   } // namespace __rcvrs
136 
137   using __rcvrs::set_value_t;
138   using __rcvrs::set_error_t;
139   using __rcvrs::set_stopped_t;
140   inline constexpr set_value_t set_value{};
141   inline constexpr set_error_t set_error{};
142   inline constexpr set_stopped_t set_stopped{};
143 
144   struct receiver_t {
145     using receiver_concept = receiver_t; // NOT TO SPEC
146   };
147 
148   namespace __detail {
149     template <class _Receiver>
150     concept __enable_receiver =
151       (STDEXEC_WHEN(
152         STDEXEC_EDG(),
153         requires { typename _Receiver::receiver_concept; } &&)
154          derived_from<typename _Receiver::receiver_concept, receiver_t>)
155       || requires { typename _Receiver::is_receiver; } // back-compat, NOT TO SPEC
156       || STDEXEC_IS_BASE_OF(receiver_t, _Receiver);    // NOT TO SPEC, for receiver_adaptor
157   } // namespace __detail
158 
159   template <class _Receiver>
160   inline constexpr bool enable_receiver = __detail::__enable_receiver<_Receiver>; // NOT TO SPEC
161 
162   template <class _Receiver>
163   concept receiver = enable_receiver<__decay_t<_Receiver>>
164                   && environment_provider<__cref_t<_Receiver>>
165                   && move_constructible<__decay_t<_Receiver>>
166                   && constructible_from<__decay_t<_Receiver>, _Receiver>;
167 
168   namespace __detail {
169     template <class _Receiver, class _Tag, class... _Args>
170     auto __try_completion(_Tag (*)(_Args...))
171       -> __mexception<_MISSING_COMPLETION_SIGNAL_<_Tag(_Args...)>, _WITH_RECEIVER_<_Receiver>>;
172 
173     template <class _Receiver, class _Tag, class... _Args>
174       requires __callable<_Tag, _Receiver, _Args...>
175     auto __try_completion(_Tag (*)(_Args...)) -> __msuccess;
176 
177     template <class _Receiver, class... _Sigs>
178     auto __try_completions(completion_signatures<_Sigs...> *) -> decltype((
179       __msuccess(),
180       ...,
181       __detail::__try_completion<__decay_t<_Receiver>>(static_cast<_Sigs *>(nullptr))));
182   } // namespace __detail
183 
184   template <class _Receiver, class _Completions>
185   concept receiver_of = receiver<_Receiver> && requires(_Completions *__completions) {
186     { __detail::__try_completions<_Receiver>(__completions) } -> __ok;
187   };
188 
189   template <class _Receiver, class _Sender>
190   concept __receiver_from =
191     receiver_of<_Receiver, __completion_signatures_of_t<_Sender, env_of_t<_Receiver>>>;
192 
193   /// A utility for calling set_value with the result of a function invocation:
194   template <class _Receiver, class _Fun, class... _As>
STDEXEC_ATTRIBUTE(host,device)195   STDEXEC_ATTRIBUTE(host, device)
196   void __set_value_invoke(_Receiver &&__rcvr, _Fun &&__fun, _As &&...__as) noexcept {
197     STDEXEC_TRY {
198       if constexpr (same_as<void, __invoke_result_t<_Fun, _As...>>) {
199         __invoke(static_cast<_Fun &&>(__fun), static_cast<_As &&>(__as)...);
200         stdexec::set_value(static_cast<_Receiver &&>(__rcvr));
201       } else {
202         stdexec::set_value(
203           static_cast<_Receiver &&>(__rcvr),
204           __invoke(static_cast<_Fun &&>(__fun), static_cast<_As &&>(__as)...));
205       }
206     }
207     STDEXEC_CATCH_ALL {
208       if constexpr (!__nothrow_invocable<_Fun, _As...>) {
209         stdexec::set_error(static_cast<_Receiver &&>(__rcvr), std::current_exception());
210       }
211     }
212   }
213 
214   template <class _Tag, class _Receiver>
__mk_completion_fn(_Tag,_Receiver & __rcvr)215   auto __mk_completion_fn(_Tag, _Receiver &__rcvr) noexcept {
216     return [&]<class... _Args>(_Args &&...__args) noexcept {
217       _Tag()(static_cast<_Receiver &&>(__rcvr), static_cast<_Args &&>(__args)...);
218     };
219   }
220 } // namespace stdexec
221