xref: /openbmc/sdbusplus/include/sdbusplus/async/stdexec/__detail/__completion_behavior.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 <compare>
19 #include <type_traits>
20 #include <initializer_list>
21 
22 #include "__config.hpp"
23 #include "__concepts.hpp"
24 #include "__query.hpp"
25 #include "__meta.hpp"
26 #include "__execution_fwd.hpp"
27 #include "__type_traits.hpp"
28 
29 namespace stdexec {
30   //////////////////////////////////////////////////////////////////////////////////////////
31   // get_completion_behavior
32   namespace __completion_behavior {
33     enum class completion_behavior : int {
34       unknown, ///< The completion behavior is unknown.
35       asynchronous, ///< The operation's completion will not happen on the calling thread before `start()`
36                     ///< returns.
37       synchronous, ///< The operation's completion happens-before the return of `start()`.
38       inline_completion ///< The operation completes synchronously within `start()` on the same thread that called
39                         ///< `start()`.
40     };
41 
42     STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device)
43     constexpr auto operator<=>(completion_behavior __a, completion_behavior __b) noexcept
44       -> std::strong_ordering {
45       return static_cast<int>(__a) <=> static_cast<int>(__b);
46     }
47 
48     template <completion_behavior _CB>
49     using __constant_t = std::integral_constant<completion_behavior, _CB>;
50 
51     using __unknown_t = __constant_t<completion_behavior::unknown>;
52     using __asynchronous_t = __constant_t<completion_behavior::asynchronous>;
53     using __synchronous_t = __constant_t<completion_behavior::synchronous>;
54     using __inline_completion_t = __constant_t<completion_behavior::inline_completion>;
55   } // namespace __completion_behavior
56 
57   struct min_t;
58 
59   struct completion_behavior {
60    private:
61     template <__completion_behavior::completion_behavior _CB>
62     using __constant_t = std::integral_constant<__completion_behavior::completion_behavior, _CB>;
63 
64     friend struct min_t;
65 
66    public:
67     struct unknown_t : __completion_behavior::__unknown_t { };
68     struct asynchronous_t : __completion_behavior::__asynchronous_t { };
69     struct synchronous_t : __completion_behavior::__synchronous_t { };
70     struct inline_completion_t : __completion_behavior::__inline_completion_t { };
71 
72     static constexpr unknown_t unknown{};
73     static constexpr asynchronous_t asynchronous{};
74     static constexpr synchronous_t synchronous{};
75     static constexpr inline_completion_t inline_completion{};
76   };
77 
78   //////////////////////////////////////////////////////////////////////////////////////////
79   // get_completion_behavior: A sender can define this attribute to describe the sender's
80   // completion behavior
81   struct get_completion_behavior_t
82     : __query<get_completion_behavior_t, completion_behavior::unknown, __q1<__decay_t>> {
83     template <class _Attrs, class... _Env>
STDEXEC_ATTRIBUTEstdexec::get_completion_behavior_t84     STDEXEC_ATTRIBUTE(always_inline, host, device)
85     static constexpr void __validate() noexcept {
86       static_assert(
87         __nothrow_queryable_with<_Attrs, get_completion_behavior_t, _Env...>,
88         "The get_completion_behavior query must be noexcept.");
89       static_assert(
90         convertible_to<
91           __query_result_t<_Attrs, get_completion_behavior_t, _Env...>,
92           __completion_behavior::completion_behavior
93         >,
94         "The get_completion_behavior query must return one of the static member variables in "
95         "execution::completion_behavior.");
96     }
97 
STDEXEC_ATTRIBUTEstdexec::get_completion_behavior_t98     STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device)
99     static constexpr auto query(forwarding_query_t) noexcept -> bool {
100       return true;
101     }
102   };
103 
104   struct min_t {
105     using __completion_behavior_t = __completion_behavior::completion_behavior;
106 
STDEXEC_ATTRIBUTEstdexec::min_t107     STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device)
108     static constexpr auto __minimum(std::initializer_list<__completion_behavior_t> __cbs) noexcept
109       -> __completion_behavior_t {
110       auto __result = __completion_behavior::completion_behavior::inline_completion;
111       for (auto __cb: __cbs) {
112         if (__cb < __result) {
113           __result = __cb;
114         }
115       }
116       return __result;
117     }
118 
119     template <__completion_behavior_t... _CBs>
STDEXEC_ATTRIBUTEstdexec::min_t120     STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device)
121     constexpr auto operator()(completion_behavior::__constant_t<_CBs>...) const noexcept {
122       constexpr auto __behavior = __minimum({_CBs...});
123 
124       if constexpr (__behavior == completion_behavior::unknown) {
125         return completion_behavior::unknown;
126       } else if constexpr (__behavior == completion_behavior::asynchronous) {
127         return completion_behavior::asynchronous;
128       } else if constexpr (__behavior == completion_behavior::synchronous) {
129         return completion_behavior::synchronous;
130       } else if constexpr (__behavior == completion_behavior::inline_completion) {
131         return completion_behavior::inline_completion;
132       }
133       STDEXEC_UNREACHABLE();
134     }
135   };
136 
137   constexpr min_t min{};
138 
139   template <class _Attrs, class... _Env>
140   concept __completes_inline =
141     (__call_result_t<get_completion_behavior_t, const _Attrs&, const _Env&...>{}
142      == completion_behavior::inline_completion);
143 
144   template <class _Sndr, class... _Env>
STDEXEC_ATTRIBUTE(nodiscard,always_inline,host,device)145   STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device)
146   consteval auto get_completion_behavior() noexcept {
147     using __behavior_t =
148       __call_result_t<get_completion_behavior_t, env_of_t<_Sndr>, const _Env&...>;
149     return __behavior_t{};
150   }
151 
152 } // namespace stdexec
153