xref: /openbmc/sdbusplus/include/sdbusplus/async/stdexec/__detail/__transform_completion_signatures.hpp (revision 10d0b4b7d1498cfd5c3d37edea271a54d1984e41)
1 /*
2  * Copyright (c) 2021-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 these after __execution_fwd.hpp
21 #include "__completion_signatures.hpp"
22 #include "__concepts.hpp"
23 #include "__debug.hpp" // IWYU pragma: keep
24 #include "__senders_core.hpp"
25 #include "__meta.hpp"
26 
27 #include <exception>
28 #include <tuple>
29 #include <variant>
30 
31 namespace stdexec {
32 #if STDEXEC_ENABLE_EXTRA_TYPE_CHECKING()
33   // __checked_completion_signatures is for catching logic bugs in a sender's metadata. If sender<S>
34   // and sender_in<S, Ctx> are both true, then they had better report the same metadata. This
35   // completion signatures wrapper enforces that at compile time.
36   template <class _Sender, class... _Env>
__checked_completion_signatures(_Sender && __sndr,_Env &&...__env)37   auto __checked_completion_signatures(_Sender &&__sndr, _Env &&...__env) noexcept {
38     using __completions_t = __completion_signatures_of_t<_Sender, _Env...>;
39     stdexec::__debug_sender(static_cast<_Sender &&>(__sndr), __env...);
40     return __completions_t{};
41   }
42 
43   template <class _Sender, class... _Env>
44     requires sender_in<_Sender, _Env...>
45   using completion_signatures_of_t =
46     decltype(stdexec::__checked_completion_signatures(__declval<_Sender>(), __declval<_Env>()...));
47 #else
48   template <class _Sender, class... _Env>
49     requires sender_in<_Sender, _Env...>
50   using completion_signatures_of_t = __completion_signatures_of_t<_Sender, _Env...>;
51 #endif
52 
53   struct __not_a_variant {
54     __not_a_variant() = delete;
55   };
56 
57   template <class... _Ts>
58   using __std_variant = __minvoke_if_c<
59     sizeof...(_Ts) != 0,
60     __mtransform<__q1<__decay_t>, __munique<__qq<std::variant>>>,
61     __mconst<__not_a_variant>,
62     _Ts...
63   >;
64 
65   template <class... _Ts>
66   using __nullable_std_variant =
67     __mcall<__munique<__mbind_front<__qq<std::variant>, std::monostate>>, __decay_t<_Ts>...>;
68 
69   template <class... _Ts>
70   using __decayed_std_tuple = __meval<std::tuple, __decay_t<_Ts>...>;
71 
72   namespace __sigs {
73     // The following code is used to normalize completion signatures. "Normalization" means that
74     // that rvalue-references are stripped from the types in the completion signatures. For example,
75     // the completion signature `set_value_t(int &&)` would be normalized to `set_value_t(int)`,
76     // but `set_value_t(int)` and `set_value_t(int &)` would remain unchanged.
77     template <class _Tag, class... _Args>
78     auto __normalize_sig_impl(_Args &&...) -> _Tag (*)(_Args...);
79 
80     template <class _Tag, class... _Args>
81     auto __normalize_sig(_Tag (*)(_Args...))
82       -> decltype(__sigs::__normalize_sig_impl<_Tag>(__declval<_Args>()...));
83 
84     template <class... _Sigs>
85     auto __repack_completions(_Sigs *...) -> completion_signatures<_Sigs...>;
86 
87     template <class... _Sigs>
88     auto __normalize_completions(completion_signatures<_Sigs...> *)
89       -> decltype(__sigs::__repack_completions(
90         __sigs::__normalize_sig(static_cast<_Sigs *>(nullptr))...));
91 
92     template <class _Completions>
93     using __normalize_completions_t = decltype(__sigs::__normalize_completions(
94       static_cast<_Completions *>(nullptr)));
95   } // namespace __sigs
96 
97   template <class... _SigPtrs>
98   using __completion_signature_ptrs = decltype(__sigs::__repack_completions(
99     static_cast<_SigPtrs>(nullptr)...));
100 
101   template <class... _Sigs>
102   using __concat_completion_signatures =
103     __mconcat<__qq<completion_signatures>>::__f<__mconcat<__qq<__mmake_set>>::__f<_Sigs...>>;
104 
105   namespace __sigs {
106     //////////////////////////////////////////////////////////////////////////////////////////////////
107     template <template <class...> class _Tuple, class _Tag, class... _Args>
108     auto __for_each_sig(_Tag (*)(_Args...)) -> _Tuple<_Tag, _Args...>;
109 
110     template <class _Sig, template <class...> class _Tuple>
111     using __for_each_sig_t = decltype(__sigs::__for_each_sig<_Tuple>(static_cast<_Sig *>(nullptr)));
112 
113     template <
114       template <class...> class _Tuple,
115       template <class...> class _Variant,
116       class... _More,
117       class _What,
118       class... _With
119     >
120     auto
121       __for_each_completion_signature_fn(_ERROR_<_What, _With...> **) -> _ERROR_<_What, _With...>;
122 
123     template <
124       template <class...> class _Tuple,
125       template <class...> class _Variant,
126       class... _More,
127       class... _Sigs
128     >
129     auto __for_each_completion_signature_fn(completion_signatures<_Sigs...> **)
130       -> _Variant<__for_each_sig_t<_Sigs, _Tuple>..., _More...>;
131   } // namespace __sigs
132 
133   template <
134     class _Sigs,
135     template <class...> class _Tuple,
136     template <class...> class _Variant,
137     class... _More
138   >
139   using __for_each_completion_signature =
140     decltype(__sigs::__for_each_completion_signature_fn<_Tuple, _Variant, _More...>(
141       static_cast<_Sigs **>(nullptr)));
142 
143   namespace __sigs {
144     ////////////////////////////////////////////////////////////////////////////////////////////////
145     template <
146       template <class...> class _SetVal,
147       template <class...> class _SetErr,
148       class _SetStp,
149       class... _Values
150     >
151     auto __transform_sig(set_value_t (*)(_Values...)) -> _SetVal<_Values...>;
152 
153     template <
154       template <class...> class _SetVal,
155       template <class...> class _SetErr,
156       class _SetStp,
157       class _Error
158     >
159     auto __transform_sig(set_error_t (*)(_Error)) -> _SetErr<_Error>;
160 
161     template <template <class...> class _SetVal, template <class...> class _SetErr, class _SetStp>
162     auto __transform_sig(set_stopped_t (*)()) -> _SetStp;
163 
164     template <
165       class _Sig,
166       template <class...> class _SetVal,
167       template <class...> class _SetErr,
168       class _SetStp
169     >
170     using __transform_sig_t = decltype(__sigs::__transform_sig<_SetVal, _SetErr, _SetStp>(
171       static_cast<_Sig *>(nullptr)));
172 
173     template <
174       template <class...> class _SetVal,
175       template <class...> class _SetErr,
176       class _SetStp,
177       template <class...> class _Variant,
178       class... _More,
179       class _What,
180       class... _With
181     >
182     auto __transform_sigs_fn(_ERROR_<_What, _With...> **) -> _ERROR_<_What, _With...>;
183 
184     template <
185       template <class...> class _SetVal,
186       template <class...> class _SetErr,
187       class _SetStp,
188       template <class...> class _Variant,
189       class... _More,
190       class... _Sigs
191     >
192     auto __transform_sigs_fn(completion_signatures<_Sigs...> **)
193       -> _Variant<__transform_sig_t<_Sigs, _SetVal, _SetErr, _SetStp>..., _More...>;
194   } // namespace __sigs
195 
196   template <
197     class _Sigs,
198     template <class...> class _SetVal,
199     template <class...> class _SetErr,
200     class _SetStp,
201     template <class...> class _Variant,
202     class... _More
203   >
204   using __transform_completion_signatures =
205     decltype(__sigs::__transform_sigs_fn<_SetVal, _SetErr, _SetStp, _Variant, _More...>(
206       static_cast<_Sigs **>(nullptr)));
207 
208   namespace __sigs {
209     ////////////////////////////////////////////////////////////////////////////////////////////////
210     template <class _WantedTag>
211     struct __gather_sigs_fn;
212 
213     template <>
214     struct __gather_sigs_fn<set_value_t> {
215       template <
216         class _Sigs,
217         template <class...> class _Then,
218         template <class...> class _Else,
219         template <class...> class _Variant,
220         class... _More
221       >
222       using __f = __transform_completion_signatures<
223         _Sigs,
224         _Then,
225         __mbind_front_q<_Else, set_error_t>::template __f,
226         _Else<set_stopped_t>,
227         _Variant,
228         _More...
229       >;
230     };
231 
232     template <>
233     struct __gather_sigs_fn<set_error_t> {
234       template <
235         class _Sigs,
236         template <class...> class _Then,
237         template <class...> class _Else,
238         template <class...> class _Variant,
239         class... _More
240       >
241       using __f = __transform_completion_signatures<
242         _Sigs,
243         __mbind_front_q<_Else, set_value_t>::template __f,
244         _Then,
245         _Else<set_stopped_t>,
246         _Variant,
247         _More...
248       >;
249     };
250 
251     template <>
252     struct __gather_sigs_fn<set_stopped_t> {
253       template <
254         class _Sigs,
255         template <class...> class _Then,
256         template <class...> class _Else,
257         template <class...> class _Variant,
258         class... _More
259       >
260       using __f = __transform_completion_signatures<
261         _Sigs,
262         __mbind_front_q<_Else, set_value_t>::template __f,
263         __mbind_front_q<_Else, set_error_t>::template __f,
264         _Then<>,
265         _Variant,
266         _More...
267       >;
268     };
269 
270     template <class... _Values>
271     using __default_set_value = completion_signatures<set_value_t(_Values...)>;
272 
273     template <class... _Error>
274     using __default_set_error = completion_signatures<set_error_t(_Error...)>;
275 
276     template <class _Tag, class... _Args>
277     using __default_completion = completion_signatures<_Tag(_Args...)>;
278   } // namespace __sigs
279 
280   template <
281     class _Sigs,
282     class _WantedTag,
283     template <class...> class _Then,
284     template <class...> class _Else,
285     template <class...> class _Variant,
286     class... _More
287   >
288   using __gather_completion_signatures =
289     __sigs::__gather_sigs_fn<_WantedTag>::template __f<_Sigs, _Then, _Else, _Variant, _More...>;
290 
291   /////////////////////////////////////////////////////////////////////////////
292   // transform_completion_signatures
293   // ==========================
294 
295   // `transform_completion_signatures` takes a sender, and environment, and a bunch of other
296   // template arguments for munging the completion signatures of a sender in interesting ways.
297 
298   //  ```c++
299   //  template <class... Args>
300   //    using __default_set_value = completion_signatures<set_value_t(Args...)>;
301 
302   //  template <class Err>
303   //    using __default_set_error = completion_signatures<set_error_t(Err)>;
304 
305   //  template <
306   //    class Completions,
307   //    class AdditionalSigs = completion_signatures<>,
308   //    template <class...> class SetValue = __default_set_value,
309   //    template <class> class SetError = __default_set_error,
310   //    class SetStopped = completion_signatures<set_stopped_t()>>
311   //  using transform_completion_signatures =
312   //    completion_signatures< ... >;
313   //  ```
314 
315   //  * `SetValue` : an alias template that accepts a set of value types and returns an instance of
316   //    `completion_signatures`.
317 
318   //  * `SetError` : an alias template that accepts an error types and returns a an instance of
319   //    `completion_signatures`.
320 
321   //  * `SetStopped` : an instantiation of `completion_signatures` with a list of completion
322   //    signatures `Sigs...` to the added to the list if the sender can complete with a stopped
323   //    signal.
324 
325   //  * `AdditionalSigs` : an instantiation of `completion_signatures` with a list of completion
326   //    signatures `Sigs...` to the added to the list unconditionally.
327 
328   //  `transform_completion_signatures` does the following:
329 
330   //  * Let `VCs...` be a pack of the `completion_signatures` types in the `__typelist` named by
331   //    `value_types_of_t<Sndr, Env, SetValue, __typelist>`, and let `Vs...` be the concatenation of
332   //    the packs that are template arguments to each `completion_signature` in `VCs...`.
333 
334   //  * Let `ECs...` be a pack of the `completion_signatures` types in the `__typelist` named by
335   //    `error_types_of_t<Sndr, Env, __errorlist>`, where `__errorlist` is an alias template such
336   //    that `__errorlist<Ts...>` names `__typelist<SetError<Ts>...>`, and let `Es...` be the
337   //    concatenation of the packs that are the template arguments to each `completion_signature` in
338   //    `ECs...`.
339 
340   //  * Let `Ss...` be an empty pack if `sends_stopped<Sndr, Env>` is `false`; otherwise, a pack
341   //    containing the template arguments of the `completion_signatures` instantiation named by
342   //    `SetStopped`.
343 
344   //  * Let `MoreSigs...` be a pack of the template arguments of the `completion_signatures`
345   //    instantiation named by `AdditionalSigs`.
346 
347   //  Then `transform_completion_signatures<Completions, AdditionalSigs, SetValue, SetError,
348   //  SendsStopped>` names the type `completion_signatures< Sigs... >` where `Sigs...` is the unique
349   //  set of types in `[Vs..., Es..., Ss..., MoreSigs...]`.
350 
351   //  If any of the above type computations are ill-formed, `transform_completion_signatures<Sndr,
352   //  Env, AdditionalSigs, SetValue, SetError, SendsStopped>` is ill-formed.
353   template <
354     class _Sigs,
355     class _MoreSigs = completion_signatures<>,
356     template <class...> class _ValueTransform = __sigs::__default_set_value,
357     template <class...> class _ErrorTransform = __sigs::__default_set_error,
358     class _StoppedSigs = completion_signatures<set_stopped_t()>
359   >
360   using transform_completion_signatures = __transform_completion_signatures<
361     _Sigs,
362     _ValueTransform,
363     _ErrorTransform,
364     _StoppedSigs,
365     __mtry_q<__concat_completion_signatures>::__f,
366     _MoreSigs
367   >;
368 
369   template <
370     class _Sndr,
371     class _Env = env<>,
372     class _MoreSigs = completion_signatures<>,
373     template <class...> class _ValueTransform = __sigs::__default_set_value,
374     template <class...> class _ErrorTransform = __sigs::__default_set_error,
375     class _StoppedSigs = completion_signatures<set_stopped_t()>
376   >
377   using transform_completion_signatures_of = transform_completion_signatures<
378     completion_signatures_of_t<_Sndr, _Env>,
379     _MoreSigs,
380     _ValueTransform,
381     _ErrorTransform,
382     _StoppedSigs
383   >;
384 
385   using __eptr_completion = completion_signatures<set_error_t(std::exception_ptr)>;
386 
387   template <class _NoExcept>
388   using __eptr_completion_if_t = __if<_NoExcept, completion_signatures<>, __eptr_completion>;
389 
390   template <bool _NoExcept>
391   using __eptr_completion_if = __eptr_completion_if_t<__mbool<_NoExcept>>;
392 
393   template <
394     class _Sender,
395     class _Env = env<>,
396     class _More = completion_signatures<>,
397     class _SetValue = __qq<__sigs::__default_set_value>,
398     class _SetError = __qq<__sigs::__default_set_error>,
399     class _SetStopped = completion_signatures<set_stopped_t()>
400   >
401   using __try_make_completion_signatures = __transform_completion_signatures<
402     __completion_signatures_of_t<_Sender, _Env>,
403     _SetValue::template __f,
404     _SetError::template __f,
405     _SetStopped,
406     __mtry_q<__concat_completion_signatures>::__f,
407     _More
408   >;
409 
410   template <class _SetTag, class _Completions, class _Tuple, class _Variant>
411   using __gather_completions = __gather_completion_signatures<
412     _Completions,
413     _SetTag,
414     __mcompose_q<__types, _Tuple::template __f>::template __f,
415     __mconst<__types<>>::__f,
416     __mconcat<_Variant>::template __f
417   >;
418 
419   template <class _SetTag, class _Sender, class _Env, class _Tuple, class _Variant>
420   using __gather_completions_of =
421     __gather_completions<_SetTag, __completion_signatures_of_t<_Sender, _Env>, _Tuple, _Variant>;
422 
423   template <
424     class _Sender,
425     class _Env = env<>,
426     class _Sigs = completion_signatures<>,
427     template <class...> class _SetValue = __sigs::__default_set_value,
428     template <class...> class _SetError = __sigs::__default_set_error,
429     class _SetStopped = completion_signatures<set_stopped_t()>
430   >
431   using make_completion_signatures =
432     transform_completion_signatures_of<_Sender, _Env, _Sigs, _SetValue, _SetError, _SetStopped>;
433 
434   template <
435     class _Sigs,
436     class _Tuple = __q<__decayed_std_tuple>,
437     class _Variant = __q<__std_variant>
438   >
439   using __value_types_t = __gather_completions<set_value_t, _Sigs, _Tuple, _Variant>;
440 
441   template <
442     class _Sender,
443     class _Env = env<>,
444     class _Tuple = __q<__decayed_std_tuple>,
445     class _Variant = __q<__std_variant>
446   >
447   using __value_types_of_t =
448     __value_types_t<__completion_signatures_of_t<_Sender, _Env>, _Tuple, _Variant>;
449 
450   template <class _Sigs, class _Variant = __q<__std_variant>>
451   using __error_types_t = __gather_completions<set_error_t, _Sigs, __q<__midentity>, _Variant>;
452 
453   template <class _Sender, class _Env = env<>, class _Variant = __q<__std_variant>>
454   using __error_types_of_t = __error_types_t<__completion_signatures_of_t<_Sender, _Env>, _Variant>;
455 
456   template <
457     class _Sender,
458     class _Env = env<>,
459     template <class...> class _Tuple = __decayed_std_tuple,
460     template <class...> class _Variant = __std_variant
461   >
462   using value_types_of_t = __value_types_of_t<_Sender, _Env, __q<_Tuple>, __q<_Variant>>;
463 
464   template <class _Sender, class _Env = env<>, template <class...> class _Variant = __std_variant>
465   using error_types_of_t = __error_types_of_t<_Sender, _Env, __q<_Variant>>;
466 
467   template <class _Tag, class _Sender, class... _Env>
468   using __count_of = __gather_completion_signatures<
469     __completion_signatures_of_t<_Sender, _Env...>,
470     _Tag,
471     __mconst<__msize_t<1>>::__f,
472     __mconst<__msize_t<0>>::__f,
473     __mplus_t
474   >;
475 
476   template <class _Tag, class _Sender, class... _Env>
477     requires sender_in<_Sender, _Env...>
478   inline constexpr bool __sends = __v<__gather_completion_signatures<
479     __completion_signatures_of_t<_Sender, _Env...>,
480     _Tag,
481     __mconst<__mtrue>::__f,
482     __mconst<__mfalse>::__f,
483     __mor_t
484   >>;
485 
486   template <class _Sender, class... _Env>
487   concept sends_stopped = sender_in<_Sender, _Env...> && __sends<set_stopped_t, _Sender, _Env...>;
488 
489   template <class _Sender, class... _Env>
490   using __single_sender_value_t =
491     __value_types_t<__completion_signatures_of_t<_Sender, _Env...>, __q<__msingle>, __q<__msingle>>;
492 
493   template <class _Sender, class... _Env>
494   concept __single_value_sender = sender_in<_Sender, _Env...>
495                                && requires { typename __single_sender_value_t<_Sender, _Env...>; };
496 
497   template <class _Sender, class... _Env>
498   using __single_value_variant_sender_t =
499     __value_types_t<__completion_signatures_of_t<_Sender, _Env...>, __qq<__types>, __q<__msingle>>;
500 
501   template <class _Sender, class... _Env>
502   concept __single_value_variant_sender = sender_in<_Sender, _Env...> && requires {
503     typename __single_value_variant_sender_t<_Sender, _Env...>;
504   };
505 
506   // The following utilities are needed fairly often:
507   template <class _Fun, class... _Args>
508     requires __invocable<_Fun, _Args...>
509   using __nothrow_invocable_t = __mbool<__nothrow_invocable<_Fun, _Args...>>;
510 
511   template <class _Catch, class _Tag, class _Fun, class _Sender, class... _Env>
512   using __with_error_invoke_t = __if<
513     __gather_completion_signatures<
514       __completion_signatures_of_t<_Sender, _Env...>,
515       _Tag,
516       __mbind_front<__mtry_catch_q<__nothrow_invocable_t, _Catch>, _Fun>::template __f,
517       __mconst<__mbool<true>>::__f,
518       __mand
519     >,
520     completion_signatures<>,
521     __eptr_completion
522   >;
523 
524   template <class _Fun, class... _Args>
525     requires __invocable<_Fun, _Args...>
526   using __set_value_invoke_t = completion_signatures<
527     __minvoke<__mremove<void, __qf<set_value_t>>, __invoke_result_t<_Fun, _Args...>>
528   >;
529 
530   template <class _Completions>
531   using __decay_copyable_results_t =
532     __for_each_completion_signature<_Completions, __decay_copyable_t, __mand_t>;
533 
534   template <class _Completions>
535   using __nothrow_decay_copyable_results_t =
536     __for_each_completion_signature<_Completions, __nothrow_decay_copyable_t, __mand_t>;
537 } // namespace stdexec
538