xref: /openbmc/sdbusplus/include/sdbusplus/async/stdexec/__detail/__senders_core.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 "__awaitable.hpp"
22 #include "__completion_signatures.hpp"
23 #include "__concepts.hpp"
24 #include "__diagnostics.hpp"
25 #include "__domain.hpp"
26 #include "__env.hpp"
27 #include "__receivers.hpp"
28 #include "__type_traits.hpp"
29 
30 namespace stdexec {
31   /////////////////////////////////////////////////////////////////////////////
32   // [execution.senders]
33   struct sender_t {
34     using sender_concept = sender_t;
35   };
36 
37   namespace __detail {
38     template <class _Sender>
39     concept __enable_sender = derived_from<typename _Sender::sender_concept, sender_t>
40                            || requires { typename _Sender::is_sender; } // NOT TO SPEC back compat
41                            || __awaitable<_Sender, __env::__promise<env<>>>;
42   } // namespace __detail
43 
44   template <class _Sender>
45   inline constexpr bool enable_sender = __detail::__enable_sender<_Sender>;
46 
47   template <class _Sender>
48   concept sender = enable_sender<__decay_t<_Sender>> && environment_provider<__cref_t<_Sender>>
49                 && __detail::__consistent_completion_domains<_Sender>
50                 && move_constructible<__decay_t<_Sender>>
51                 && constructible_from<__decay_t<_Sender>, _Sender>;
52 
53   template <class _Sender, class... _Env>
54   concept sender_in =
55     (sizeof...(_Env) <= 1) && sender<_Sender> && requires(_Sender &&__sndr, _Env &&...__env) {
56       {
57         get_completion_signatures(static_cast<_Sender &&>(__sndr), static_cast<_Env &&>(__env)...)
58       } -> __valid_completion_signatures;
59     };
60 
61   /////////////////////////////////////////////////////////////////////////////
62   // [exec.snd]
63   template <class _Sender, class _Receiver>
64   concept sender_to = receiver<_Receiver> && sender_in<_Sender, env_of_t<_Receiver>>
65                    && __receiver_from<_Receiver, _Sender>
66                    && requires(_Sender &&__sndr, _Receiver &&__rcvr) {
67                         connect(static_cast<_Sender &&>(__sndr), static_cast<_Receiver &&>(__rcvr));
68                       };
69 
70   template <class _Sender, class _Receiver>
71   using connect_result_t = __call_result_t<connect_t, _Sender, _Receiver>;
72 
73   // Used to report a meaningful error message when the sender_in<Sndr, Env>
74   // concept check fails.
75   template <class _Sender, class... _Env>
__diagnose_sender_concept_failure()76   auto __diagnose_sender_concept_failure() {
77     if constexpr (!enable_sender<__decay_t<_Sender>>) {
78       static_assert(enable_sender<_Sender>, STDEXEC_ERROR_ENABLE_SENDER_IS_FALSE);
79     } else if constexpr (!__detail::__consistent_completion_domains<_Sender>) {
80       static_assert(
81         __detail::__consistent_completion_domains<_Sender>,
82         "The completion schedulers of the sender do not have "
83         "consistent domains. This is likely a "
84         "bug in the sender implementation.");
85     } else if constexpr (!move_constructible<__decay_t<_Sender>>) {
86       static_assert(
87         move_constructible<__decay_t<_Sender>>, "The sender type is not move-constructible.");
88     } else if constexpr (!constructible_from<__decay_t<_Sender>, _Sender>) {
89       static_assert(
90         constructible_from<__decay_t<_Sender>, _Sender>,
91         "The sender cannot be decay-copied. Did you forget a std::move?");
92     } else {
93       using _Completions = __completion_signatures_of_t<_Sender, _Env...>;
94       if constexpr (__same_as<_Completions, __unrecognized_sender_error<_Sender, _Env...>>) {
95         static_assert(__mnever<_Completions>, STDEXEC_ERROR_CANNOT_COMPUTE_COMPLETION_SIGNATURES);
96       } else if constexpr (__merror<_Completions>) {
97         static_assert(
98           !__merror<_Completions>, STDEXEC_ERROR_GET_COMPLETION_SIGNATURES_RETURNED_AN_ERROR);
99       } else {
100         static_assert(
101           __valid_completion_signatures<_Completions>,
102           STDEXEC_ERROR_GET_COMPLETION_SIGNATURES_HAS_INVALID_RETURN_TYPE);
103       }
104 #if STDEXEC_MSVC() || STDEXEC_NVHPC()
105       // MSVC and NVHPC need more encouragement to print the type of the
106       // error.
107       _Completions __what = 0;
108 #endif
109     }
110   }
111 } // namespace stdexec
112