xref: /openbmc/sdbusplus/include/sdbusplus/async/stdexec/__detail/__diagnostics.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 "__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