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 "__meta.hpp" 19 20 namespace stdexec { 21 namespace __detail { 22 template <class _Ty> 23 extern __q<__midentity> __name_of_v; 24 25 template <class _Ty> 26 using __name_of_fn = decltype(__name_of_v<_Ty>); 27 28 template <class _Ty> 29 using __name_of = __minvoke<__name_of_fn<_Ty>, _Ty>; 30 } // namespace __detail 31 32 // A utility for pretty-printing type names in diagnostics 33 template <class _Ty> 34 using __name_of = __detail::__name_of<_Ty>; 35 36 namespace __errs { 37 inline constexpr __mstring __unrecognized_sender_type_diagnostic = 38 "The given type cannot be used as a sender with the given environment " 39 "because the attempt to compute the completion signatures failed."_mstr; 40 41 template <class _Sender> 42 struct _WITH_SENDER_; 43 44 template <class... _Senders> 45 struct _WITH_SENDERS_; 46 } // namespace __errs 47 48 struct _WHERE_; 49 50 struct _IN_ALGORITHM_; 51 52 template <__mstring _Diagnostic = __errs::__unrecognized_sender_type_diagnostic> 53 struct _UNRECOGNIZED_SENDER_TYPE_; 54 55 template <class _Sender> 56 using _WITH_SENDER_ = __errs::_WITH_SENDER_<__name_of<_Sender>>; 57 58 template <class... _Senders> 59 using _WITH_SENDERS_ = __errs::_WITH_SENDERS_<__name_of<_Senders>...>; 60 61 template <class _Env> 62 struct _WITH_ENVIRONMENT_; 63 64 template <class _Ty> 65 struct _WITH_TYPE_; 66 67 template <class _Receiver> 68 struct _WITH_RECEIVER_; 69 70 template <class _Sig> 71 struct _MISSING_COMPLETION_SIGNAL_; 72 73 template <class _Sig> 74 struct _WITH_COMPLETION_SIGNATURE_; 75 76 template <class _Fun> 77 struct _WITH_FUNCTION_; 78 79 template <class... _Args> 80 struct _WITH_ARGUMENTS_; 81 82 template <class _Tag> 83 struct _WITH_QUERY_; 84 85 struct _SENDER_TYPE_IS_NOT_COPYABLE_; 86 87 inline constexpr __mstring __not_callable_diag = 88 "The specified function is not callable with the arguments provided."_mstr; 89 90 template <__mstring _Context, __mstring _Diagnostic = __not_callable_diag> 91 struct _NOT_CALLABLE_; 92 93 template <auto _Reason = "You cannot pipe one sender into another."_mstr> 94 struct _CANNOT_PIPE_INTO_A_SENDER_ { }; 95 96 template <class _Sender> 97 using __bad_pipe_sink_t = __mexception<_CANNOT_PIPE_INTO_A_SENDER_<>, _WITH_SENDER_<_Sender>>; 98 99 template <__mstring _Context> 100 struct __callable_error { 101 template <class _Fun, class... _Args> 102 using __f = 103 __mexception<_NOT_CALLABLE_<_Context>, _WITH_FUNCTION_<_Fun>, _WITH_ARGUMENTS_<_Args...>>; 104 }; 105 } // namespace stdexec 106 107 //////////////////////////////////////////////////////////////////////////////// 108 #define STDEXEC_ERROR_ENABLE_SENDER_IS_FALSE \ 109 "\n" \ 110 "\n" \ 111 "The given type is not a sender because stdexec::enable_sender<Sender> is false. Either:\n" \ 112 "\n" \ 113 "1. Give the type a nested `::sender_concept` type that is an alias for `stdexec::sender_t`,\n" \ 114 " as in:\n" \ 115 "\n" \ 116 " class MySender\n" \ 117 " {\n" \ 118 " public:\n" \ 119 " using sender_concept = stdexec::sender_t;\n" \ 120 " ...\n" \ 121 " };\n" \ 122 "\n" \ 123 " or,\n" \ 124 "\n" \ 125 "2. Specialize the `stdexec::enable_sender` boolean trait for this type to true, as follows:\n" \ 126 "\n" \ 127 " class MySender\n" \ 128 " {\n" \ 129 " ...\n" \ 130 " };\n" \ 131 "\n" \ 132 " template <>\n" \ 133 " inline constexpr bool stdexec::enable_sender<MySender> = true;\n" 134 135 //////////////////////////////////////////////////////////////////////////////// 136 #define STDEXEC_ERROR_CANNOT_COMPUTE_COMPLETION_SIGNATURES \ 137 "\n" \ 138 "\n" \ 139 "The sender type was not able to report its completion signatures when asked.\n" \ 140 "This is either because it lacks the necessary member function, or because the\n" \ 141 "member function was ill-formed.\n" \ 142 "\n" \ 143 "A sender can declare its completion signatures in one of two ways:\n" \ 144 "\n" \ 145 "1. By defining a nested type alias named `completion_signatures` that is a\n" \ 146 " specialization of `stdexec::completion_signatures<...>`, as follows:\n" \ 147 "\n" \ 148 " class MySender\n" \ 149 " {\n" \ 150 " public:\n" \ 151 " using sender_concept = stdexec::sender_t;\n" \ 152 " using completion_signatures = stdexec::completion_signatures<\n" \ 153 " // This sender can complete successfully with an int and a float...\n" \ 154 " stdexec::set_value_t(int, float),\n" \ 155 " // ... or in error with an exception_ptr\n" \ 156 " stdexec::set_error_t(std::exception_ptr)>;\n" \ 157 " ...\n" \ 158 " };\n" \ 159 "\n" \ 160 " or,\n" \ 161 "\n" \ 162 "2. By defining a member function named `get_completion_signatures` that returns\n" \ 163 " a specialization of `stdexec::completion_signatures<...>`, as follows:\n" \ 164 "\n" \ 165 " class MySender\n" \ 166 " {\n" \ 167 " public:\n" \ 168 " using sender_concept = stdexec::sender_t;\n" \ 169 "\n" \ 170 " template <class... _Env>\n" \ 171 " auto get_completion_signatures(_Env&&...) -> stdexec::completion_signatures<\n" \ 172 " // This sender can complete successfully with an int and a float...\n" \ 173 " stdexec::set_value_t(int, float),\n" \ 174 " // ... or in error with a std::exception_ptr.\n" \ 175 " stdexec::set_error_t(std::exception_ptr)>\n" \ 176 " {\n" \ 177 " return {};\n" \ 178 " }\n" \ 179 " ...\n" \ 180 " };\n" 181 182 //////////////////////////////////////////////////////////////////////////////// 183 #define STDEXEC_ERROR_GET_COMPLETION_SIGNATURES_RETURNED_AN_ERROR \ 184 "\n" \ 185 "\n" \ 186 "Trying to compute the sender's completion signatures resulted in an error. See\n" \ 187 "the rest of the compiler diagnostic for clues. Look for the string \"_ERROR_\".\n" 188 189 #define STDEXEC_ERROR_GET_COMPLETION_SIGNATURES_HAS_INVALID_RETURN_TYPE \ 190 "\n" \ 191 "\n" \ 192 "The member function `get_completion_signatures` of the sender returned an\n" \ 193 "invalid type.\n" \ 194 "\n" \ 195 "A sender's `get_completion_signatures` function must return a specialization of\n" \ 196 "`stdexec::completion_signatures<...>`, as follows:\n" \ 197 "\n" \ 198 " class MySender\n" \ 199 " {\n" \ 200 " public:\n" \ 201 " using sender_concept = stdexec::sender_t;\n" \ 202 "\n" \ 203 " template <class... _Env>\n" \ 204 " auto get_completion_signatures(_Env&&...) -> stdexec::completion_signatures<\n" \ 205 " // This sender can complete successfully with an int and a float...\n" \ 206 " stdexec::set_value_t(int, float),\n" \ 207 " // ... or in error with a std::exception_ptr.\n" \ 208 " stdexec::set_error_t(std::exception_ptr)>\n" \ 209 " {\n" \ 210 " return {};\n" \ 211 " }\n" \ 212 " ...\n" \ 213 " };\n" 214 215 //////////////////////////////////////////////////////////////////////////////// 216 #define STDEXEC_ERROR_CANNOT_CONNECT_SENDER_TO_RECEIVER \ 217 "\n" \ 218 "A sender must provide a `connect` member function that takes a receiver as an\n" \ 219 "argument and returns an object whose type satisfies `stdexec::operation_state`,\n" \ 220 "as shown below:\n" \ 221 "\n" \ 222 " class MySender\n" \ 223 " {\n" \ 224 " public:\n" \ 225 " using sender_concept = stdexec::sender_t;\n" \ 226 " using completion_signatures = stdexec::completion_signatures<stdexec::set_value_t()>;\n" \ 227 "\n" \ 228 " template <class Receiver>\n" \ 229 " struct MyOpState\n" \ 230 " {\n" \ 231 " using operation_state_concept = stdexec::operation_state_t;\n" \ 232 "\n" \ 233 " void start() noexcept\n" \ 234 " {\n" \ 235 " // Start the operation, which will eventually complete and send its\n" \ 236 " // result to rcvr_;\n" \ 237 " }\n" \ 238 "\n" \ 239 " Receiver rcvr_;\n" \ 240 " };\n" \ 241 "\n" \ 242 " template <stdexec::receiver Receiver>\n" \ 243 " auto connect(Receiver rcvr) -> MyOpState<Receiver>\n" \ 244 " {\n" \ 245 " return MyOpState<Receiver>{std::move(rcvr)};\n" \ 246 " }\n" \ 247 "\n" \ 248 " ...\n" \ 249 " };\n" 250 251 //////////////////////////////////////////////////////////////////////////////// 252 #define STDEXEC_ERROR_SYNC_WAIT_CANNOT_CONNECT_SENDER_TO_RECEIVER \ 253 "\n" \ 254 "\n" \ 255 "The sender passed to `stdexec::sync_wait()` does not have a `connect`\n" \ 256 "member function that accepts sync_wait's " \ 257 "receiver.\n" STDEXEC_ERROR_CANNOT_CONNECT_SENDER_TO_RECEIVER 258