xref: /openbmc/sdbusplus/include/sdbusplus/async/stdexec/env.hpp (revision 5cee91570368554a7fcbbd9418f65efda449fa70)
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 "../stdexec/execution.hpp"
19  
20  STDEXEC_PRAGMA_PUSH()
21  STDEXEC_PRAGMA_IGNORE_EDG(1302)
22  
23  namespace exec
24  {
25  template <class _Tag, class _Value>
26  using with_t = stdexec::prop<_Tag, _Value>;
27  
28  namespace __envs
29  {
30  struct __with_t
31  {
32      template <class _Tag, class _Value>
operator ()exec::__envs::__with_t33      auto operator()(_Tag, _Value&& __val) const
34      {
35          return stdexec::prop{_Tag(), static_cast<_Value&&>(__val)};
36      }
37  };
38  
39  struct __without_t
40  {
41      template <class _Env, class _Tag>
operator ()exec::__envs::__without_t42      auto operator()(_Env&& __env, _Tag) const -> decltype(auto)
43      {
44          return stdexec::__env::__without(static_cast<_Env&&>(__env), _Tag());
45      }
46  };
47  
48  // For making an environment from key/value pairs and optionally
49  // another environment.
50  struct __make_env_t
51  {
52      template <stdexec::__nothrow_move_constructible _Base,
53                stdexec::__nothrow_move_constructible _Env>
operator ()exec::__envs::__make_env_t54      auto operator()(_Base&& __base, _Env&& __env) const noexcept
55          -> stdexec::__env::__join_t<_Env, _Base>
56      {
57          return stdexec::__env::__join(static_cast<_Env&&>(__env),
58                                        static_cast<_Base&&>(__base));
59      }
60  
61      template <stdexec::__nothrow_move_constructible _Env>
operator ()exec::__envs::__make_env_t62      auto operator()(_Env&& __env) const noexcept -> _Env
63      {
64          return static_cast<_Env&&>(__env);
65      }
66  };
67  } // namespace __envs
68  
69  inline constexpr __envs::__with_t with{};
70  inline constexpr __envs::__without_t without{};
71  inline constexpr __envs::__make_env_t make_env{};
72  
73  template <class... _Ts>
74  using make_env_t = stdexec::__result_of<make_env, _Ts...>;
75  
76  namespace __read_with_default
77  {
78  using namespace stdexec;
79  
80  struct read_with_default_t;
81  
82  template <class _Tag, class _DefaultId, class _ReceiverId>
83  struct __operation
84  {
85      using _Default = stdexec::__t<_DefaultId>;
86      using _Receiver = stdexec::__t<_ReceiverId>;
87  
88      struct __t : __immovable
89      {
90          using __id = __operation;
91  
92          STDEXEC_ATTRIBUTE((no_unique_address))
93          _Default __default_;
94          _Receiver __rcvr_;
95  
startexec::__read_with_default::__operation::__t96          void start() & noexcept
97          {
98              try
99              {
100                  if constexpr (__callable<_Tag, env_of_t<_Receiver>>)
101                  {
102                      const auto& __env = get_env(__rcvr_);
103                      stdexec::set_value(std::move(__rcvr_), _Tag{}(__env));
104                  }
105                  else
106                  {
107                      stdexec::set_value(std::move(__rcvr_),
108                                         std::move(__default_));
109                  }
110              }
111              catch (...)
112              {
113                  stdexec::set_error(std::move(__rcvr_),
114                                     std::current_exception());
115              }
116          }
117      };
118  };
119  
120  template <class _Tag, class _Default, class _Receiver>
121  using __operation_t = __t<__operation<_Tag, __id<_Default>, __id<_Receiver>>>;
122  
123  template <class _Tag, class _Default>
124  struct __sender
125  {
126      using __id = __sender;
127      using __t = __sender;
128      using sender_concept = stdexec::sender_t;
129      STDEXEC_ATTRIBUTE((no_unique_address))
130      _Default __default_;
131  
132      template <class _Env>
133      using __value_t = __minvoke<
134          __with_default<__mbind_back_q<__call_result_t, _Env>, _Default>, _Tag>;
135      template <class _Env>
136      using __default_t = __if_c<__callable<_Tag, _Env>, __ignore, _Default>;
137  
138      template <class _Env>
139      using __completions_t =
140          completion_signatures<set_value_t(__value_t<_Env>),
141                                set_error_t(std::exception_ptr)>;
142  
143      template <__decays_to<__sender> _Self, class _Receiver>
144          requires receiver_of<_Receiver, __completions_t<env_of_t<_Receiver>>>
connectexec::__read_with_default::__sender145      static auto connect(_Self&& __self, _Receiver __rcvr) //
146          noexcept(std::is_nothrow_move_constructible_v<_Receiver>)
147              -> __operation_t<_Tag, __default_t<env_of_t<_Receiver>>, _Receiver>
148      {
149          return {{},
150                  static_cast<_Self&&>(__self).__default_,
151                  static_cast<_Receiver&&>(__rcvr)};
152      }
153  
154      template <class _Env>
get_completion_signaturesexec::__read_with_default::__sender155      auto get_completion_signatures(_Env&&) -> __completions_t<_Env>
156      {
157          return {};
158      }
159  };
160  
161  struct __read_with_default_t
162  {
163      template <class _Tag, class _Default>
operator ()exec::__read_with_default::__read_with_default_t164      constexpr auto operator()(_Tag, _Default&& __default) const
165          -> __sender<_Tag, __decay_t<_Default>>
166      {
167          return {static_cast<_Default&&>(__default)};
168      }
169  };
170  } // namespace __read_with_default
171  
172  inline constexpr __read_with_default::__read_with_default_t read_with_default{};
173  
174  inline constexpr stdexec::__write_::__write_env_t write{};
175  inline constexpr stdexec::__write_::__write_env_t write_env{};
176  } // namespace exec
177  
178  STDEXEC_PRAGMA_POP()
179