xref: /openbmc/sdbusplus/include/sdbusplus/async/stdexec/__detail/__read_env.hpp (revision f083bc1a64e1f94c99fc270b7c0856810f4be638)
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 "__basic_sender.hpp"
22 #include "__completion_signatures.hpp"
23 #include "__concepts.hpp"
24 #include "__diagnostics.hpp"
25 #include "__env.hpp"
26 #include "__meta.hpp"
27 #include "__optional.hpp"
28 #include "__receivers.hpp"
29 #include "__tag_invoke.hpp"
30 
31 #include <exception>
32 
33 namespace stdexec
34 {
35 namespace __read
36 {
37 template <class _Tag, class _ReceiverId>
38 using __result_t = __call_result_t<_Tag, env_of_t<stdexec::__t<_ReceiverId>>>;
39 
40 template <class _Tag, class _ReceiverId>
41 concept __nothrow_t =
42     __nothrow_callable<_Tag, env_of_t<stdexec::__t<_ReceiverId>>>;
43 
44 inline constexpr __mstring __query_failed_diag =
45     "The current execution environment doesn't have a value for the given query."_mstr;
46 
47 template <class _Tag, class _Env>
48 using __query_failed_error = //
49     __mexception<            //
50         _NOT_CALLABLE_<"In stdexec::read()..."_mstr, __query_failed_diag>,
51         _WITH_QUERY_<_Tag>, _WITH_ENVIRONMENT_<_Env>>;
52 
53 template <class _Tag, class _Env>
54     requires __callable<_Tag, _Env>
55 using __completions_t = //
56     __if_c<__nothrow_callable<_Tag, _Env>,
57            completion_signatures<set_value_t(__call_result_t<_Tag, _Env>)>,
58            completion_signatures<set_value_t(__call_result_t<_Tag, _Env>),
59                                  set_error_t(std::exception_ptr)>>;
60 
61 template <class _Tag, class _Ty>
62 struct __state
63 {
64     using __query = _Tag;
65     using __result = _Ty;
66     __optional<_Ty> __result_;
67 };
68 
69 template <class _Tag, class _Ty>
70     requires __same_as<_Ty, _Ty&&>
71 struct __state<_Tag, _Ty>
72 {
73     using __query = _Tag;
74     using __result = _Ty;
75 };
76 
77 struct __read_env_t
78 {
79     template <class _Tag>
operator ()stdexec::__read::__read_env_t80     constexpr auto operator()(_Tag) const noexcept
81     {
82         return __make_sexpr<__read_env_t>(_Tag());
83     }
84 };
85 
86 struct __read_env_impl : __sexpr_defaults
87 {
88     template <class _Tag, class _Env>
89     using __completions_t = __minvoke<
90         __mtry_catch_q<__read::__completions_t, __q<__query_failed_error>>,
91         _Tag, _Env>;
92 
93     static constexpr auto get_completion_signatures = //
94         []<class _Self, class _Env>(const _Self&, _Env&&) noexcept
95         -> __completions_t<__data_of<_Self>, _Env> { return {}; };
96 
97     static constexpr auto get_state = //
98         []<class _Self, class _Receiver>(const _Self&, _Receiver&) noexcept {
99             using __query = __data_of<_Self>;
100             using __result = __call_result_t<__query, env_of_t<_Receiver>>;
101             return __state<__query, __result>();
102         };
103 
104     static constexpr auto start = //
105         []<class _State, class _Receiver>(_State& __state,
106                                           _Receiver& __rcvr) noexcept -> void {
107         using __query = typename _State::__query;
108         using __result = typename _State::__result;
109         if constexpr (__same_as<__result, __result&&>)
110         {
111             // The query returns a reference type; pass it straight through to
112             // the receiver.
113             stdexec::__set_value_invoke(static_cast<_Receiver&&>(__rcvr),
114                                         __query(), stdexec::get_env(__rcvr));
115         }
116         else
117         {
118             constexpr bool _Nothrow =
119                 __nothrow_callable<__query, env_of_t<_Receiver>>;
__anona47160310102stdexec::__read::__read_env_impl120             auto __query_fn = [&]() noexcept(_Nothrow) -> __result&& {
121                 __state.__result_.emplace(
122                     __emplace_from{[&]() noexcept(_Nothrow) {
123                         return __query()(stdexec::get_env(__rcvr));
124                     }});
125                 return static_cast<__result&&>(*__state.__result_);
126             };
127             stdexec::__set_value_invoke(static_cast<_Receiver&&>(__rcvr),
128                                         __query_fn);
129         }
130     };
131 };
132 } // namespace __read
133 
134 inline constexpr __read::__read_env_t read{};
135 inline constexpr __read::__read_env_t read_env{};
136 
137 template <>
138 struct __sexpr_impl<__read::__read_env_t> : __read::__read_env_impl
139 {};
140 
141 namespace __queries
142 {
143 template <class _Tag>
operator ()() const144 inline auto get_scheduler_t::operator()() const noexcept
145 {
146     return read_env(get_scheduler);
147 }
148 
149 template <class _Tag>
operator ()() const150 inline auto get_delegation_scheduler_t::operator()() const noexcept
151 {
152     return read_env(get_delegation_scheduler);
153 }
154 
155 template <class _Tag>
operator ()() const156 inline auto get_allocator_t::operator()() const noexcept
157 {
158     return read_env(get_allocator);
159 }
160 
161 template <class _Tag>
operator ()() const162 inline auto get_stop_token_t::operator()() const noexcept
163 {
164     return read_env(get_stop_token);
165 }
166 } // namespace __queries
167 } // namespace stdexec
168