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