xref: /openbmc/sdbusplus/include/sdbusplus/async/stdexec/__detail/__receiver_ref.hpp (revision 10d0b4b7d1498cfd5c3d37edea271a54d1984e41)
1 /*
2  * Copyright (c) 2025 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 "__concepts.hpp"
19 #include "__config.hpp"
20 #include "__execution_fwd.hpp"
21 #include "__operation_states.hpp"
22 #include "__receivers.hpp"
23 
24 #include <memory>
25 
26 namespace stdexec {
27   template <class _Rcvr, class _Env = env_of_t<_Rcvr>>
28   struct __rcvr_ref {
29     using receiver_concept = receiver_t;
30 
STDEXEC_ATTRIBUTEstdexec::__rcvr_ref31     STDEXEC_ATTRIBUTE(host, device)
32     explicit constexpr __rcvr_ref(_Rcvr& __rcvr) noexcept
33       : __rcvr_{std::addressof(__rcvr)} {
34     }
35 
36     template <class... _As>
STDEXEC_ATTRIBUTEstdexec::__rcvr_ref37     STDEXEC_ATTRIBUTE(host, device)
38     void set_value(_As&&... __as) noexcept {
39       stdexec::set_value(static_cast<_Rcvr&&>(*__rcvr_), static_cast<_As&&>(__as)...);
40     }
41 
42     template <class _Error>
STDEXEC_ATTRIBUTEstdexec::__rcvr_ref43     STDEXEC_ATTRIBUTE(host, device)
44     void set_error(_Error&& __err) noexcept {
45       stdexec::set_error(static_cast<_Rcvr&&>(*__rcvr_), static_cast<_Error&&>(__err));
46     }
47 
STDEXEC_ATTRIBUTEstdexec::__rcvr_ref48     STDEXEC_ATTRIBUTE(host, device) void set_stopped() noexcept {
49       stdexec::set_stopped(static_cast<_Rcvr&&>(*__rcvr_));
50     }
51 
52     [[nodiscard]]
STDEXEC_ATTRIBUTEstdexec::__rcvr_ref53     STDEXEC_ATTRIBUTE(host, device) auto get_env() const noexcept -> _Env {
54       static_assert(
55         std::is_same_v<_Env, env_of_t<_Rcvr>>,
56         "get_env() must return the same type as env_of_t<_Rcvr>");
57       return stdexec::get_env(*__rcvr_);
58     }
59 
60    private:
61     _Rcvr* __rcvr_;
62   };
63 
64   namespace __detail {
65     template <class _Rcvr, size_t = sizeof(_Rcvr)>
STDEXEC_ATTRIBUTE(host,device)66     STDEXEC_ATTRIBUTE(host, device)
67     constexpr auto __is_type_complete(int) noexcept {
68       return true;
69     }
70 
71     template <class _Rcvr>
STDEXEC_ATTRIBUTE(host,device)72     STDEXEC_ATTRIBUTE(host, device)
73     constexpr auto __is_type_complete(long) noexcept {
74       return false;
75     }
76   } // namespace __detail
77 
78   // The __ref_rcvr function and its helpers are used to avoid wrapping a receiver in a
79   // __rcvr_ref when that is possible. The logic goes as follows:
80 
81   // 1. If the receiver is an instance of __rcvr_ref, return it.
82   // 2. If the type is incomplete or an operation state, return a __rcvr_ref wrapping the
83   //    receiver.
84   // 3. If the receiver is nothrow copy constructible, return it.
85   // 4. Otherwise, return a __rcvr_ref wrapping the receiver.
86   template <class _Env = void, class _Rcvr>
STDEXEC_ATTRIBUTE(nodiscard,host,device)87   STDEXEC_ATTRIBUTE(nodiscard, host, device)
88   constexpr auto __ref_rcvr(_Rcvr& __rcvr) noexcept {
89     if constexpr (std::is_same_v<_Env, void>) {
90       return stdexec::__ref_rcvr<env_of_t<_Rcvr>>(__rcvr);
91     } else if constexpr (__is_instance_of<_Rcvr, __rcvr_ref>) {
92       return __rcvr;
93     } else if constexpr (!__detail::__is_type_complete<_Rcvr>(0)) {
94       return __rcvr_ref<_Rcvr, _Env>{__rcvr};
95     } else if constexpr (operation_state<_Rcvr>) {
96       return __rcvr_ref<_Rcvr, _Env>{__rcvr};
97     } else if constexpr (__nothrow_constructible_from<_Rcvr, const _Rcvr&>) {
98       return const_cast<const _Rcvr&>(__rcvr);
99     } else {
100       return __rcvr_ref{__rcvr};
101     }
102     STDEXEC_UNREACHABLE();
103   }
104 
105   template <class _Rcvr, class _Env = env_of_t<_Rcvr>>
106   using __rcvr_ref_t = decltype(stdexec::__ref_rcvr<_Env>(stdexec::__declval<_Rcvr&>()));
107 } // namespace stdexec
108