TLA Line data Source code
1 : //
2 : // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
3 : // Copyright (c) 2026 Michael Vandeberg
4 : //
5 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 : //
8 : // Official repository: https://github.com/cppalliance/capy
9 : //
10 :
11 : #ifndef BOOST_CAPY_EX_IMMEDIATE_HPP
12 : #define BOOST_CAPY_EX_IMMEDIATE_HPP
13 :
14 : #include <boost/capy/detail/config.hpp>
15 : #include <boost/capy/ex/io_env.hpp>
16 : #include <boost/capy/io_result.hpp>
17 :
18 : #include <coroutine>
19 : #include <stop_token>
20 : #include <utility>
21 :
22 : namespace boost {
23 : namespace capy {
24 :
25 : /** An awaitable that completes immediately with a value.
26 :
27 : This awaitable wraps a synchronous result so it can be used in
28 : contexts that require an awaitable type. It never suspends -
29 : `await_ready()` always returns `true`, so the coroutine machinery
30 : is optimized away by the compiler.
31 :
32 : Use this to adapt synchronous operations to satisfy async concepts
33 : like @ref IoAwaitable without the overhead of a full coroutine frame.
34 :
35 : @tparam T The result type to wrap.
36 :
37 : @par Example
38 : @code
39 : // Wrap a sync operation as an awaitable
40 : immediate<int> get_value()
41 : {
42 : return {42};
43 : }
44 :
45 : task<void> example()
46 : {
47 : int x = co_await get_value(); // No suspension, returns 42
48 : }
49 : @endcode
50 :
51 : @par Building synchronous I/O operations
52 : @code
53 : struct my_sync_sink
54 : {
55 : template<ConstBufferSequence CB>
56 : immediate<io_result<std::size_t>>
57 : write(CB buffers)
58 : {
59 : auto n = process_sync(buffers);
60 : return {{{}, n}};
61 : }
62 :
63 : immediate<io_result<>>
64 : write_eof()
65 : {
66 : return {{}};
67 : }
68 : };
69 : @endcode
70 :
71 : @see ready, io_result
72 : */
73 : template<class T>
74 : struct immediate
75 : {
76 : /** The wrapped value. */
77 : T value_;
78 :
79 : /** Always returns true - this awaitable never suspends.
80 :
81 : @return Always `true`, so the awaiting coroutine does not suspend
82 : and `await_suspend` is never called.
83 : */
84 : constexpr bool
85 HIT 21 : await_ready() const noexcept
86 : {
87 21 : return true;
88 : }
89 :
90 : /** IoAwaitable protocol overload.
91 :
92 : This overload allows `immediate` to satisfy the @ref IoAwaitable
93 : concept. Since the result is already available, the environment
94 : is unused.
95 :
96 : @param h The coroutine handle (unused).
97 : @param env The execution environment (unused).
98 :
99 : @return `std::noop_coroutine()` to indicate no suspension.
100 : */
101 : std::coroutine_handle<>
102 1 : await_suspend(
103 : std::coroutine_handle<> h,
104 : io_env const* env) const noexcept
105 : {
106 : (void)h;
107 : (void)env;
108 1 : return std::noop_coroutine();
109 : }
110 :
111 : /** Returns the wrapped value.
112 :
113 : @return The stored value, moved if non-const.
114 : */
115 : constexpr T
116 24 : await_resume() noexcept
117 : {
118 24 : return std::move(value_);
119 : }
120 :
121 : /** Returns the wrapped value (const overload).
122 :
123 : @return A reference to the stored value. Nothing is moved, so the
124 : reference is valid only while the `immediate` is alive.
125 : */
126 : constexpr T const&
127 : await_resume() const noexcept
128 : {
129 : return value_;
130 : }
131 : };
132 :
133 : /** Create an immediate awaitable for a successful io_result.
134 :
135 : This helper creates an @ref immediate wrapping an @ref io_result
136 : with no error and the provided values.
137 :
138 : @par Example
139 : @code
140 : immediate<io_result<std::size_t>>
141 : write(const_buffer buf)
142 : {
143 : auto n = write_sync(buf);
144 : return ready(n); // success with n bytes
145 : }
146 :
147 : immediate<io_result<>>
148 : connect()
149 : {
150 : connect_sync();
151 : return ready(); // void success
152 : }
153 : @endcode
154 :
155 : @return An immediate awaitable containing a successful io_result.
156 :
157 : @see immediate, io_result
158 : */
159 : inline
160 : immediate<io_result<>>
161 3 : ready() noexcept
162 : {
163 3 : return {{}};
164 : }
165 :
166 : /** Create an immediate awaitable for a successful io_result with one value.
167 :
168 : @param t1 The result value.
169 :
170 : @return An immediate awaitable containing `io_result<T1>{{}, t1}`.
171 : */
172 : template<class T1>
173 : immediate<io_result<T1>>
174 4 : ready(T1 t1)
175 : {
176 4 : return {{{}, std::move(t1)}};
177 : }
178 :
179 : /** Create an immediate awaitable for a successful io_result with two values.
180 :
181 : @param t1 The first result value.
182 : @param t2 The second result value.
183 :
184 : @return An immediate awaitable containing `io_result<T1,T2>{{}, t1, t2}`.
185 : */
186 : template<class T1, class T2>
187 : immediate<io_result<T1, T2>>
188 2 : ready(T1 t1, T2 t2)
189 : {
190 2 : return {{{}, std::move(t1), std::move(t2)}};
191 : }
192 :
193 : /** Create an immediate awaitable for a successful io_result with three values.
194 :
195 : @param t1 The first result value.
196 : @param t2 The second result value.
197 : @param t3 The third result value.
198 :
199 : @return An immediate awaitable containing `io_result<T1,T2,T3>{{}, t1, t2, t3}`.
200 : */
201 : template<class T1, class T2, class T3>
202 : immediate<io_result<T1, T2, T3>>
203 2 : ready(T1 t1, T2 t2, T3 t3)
204 : {
205 2 : return {{{}, std::move(t1), std::move(t2), std::move(t3)}};
206 : }
207 :
208 : /** Create an immediate awaitable for a failed io_result.
209 :
210 : This helper creates an @ref immediate wrapping an @ref io_result
211 : with an error code.
212 :
213 : @par Example
214 : @code
215 : immediate<io_result<std::size_t>>
216 : write(const_buffer buf)
217 : {
218 : auto ec = write_sync(buf);
219 : if(ec)
220 : return ready(ec, std::size_t{0});
221 : return ready(buffer_size(buf));
222 : }
223 : @endcode
224 :
225 : @param ec The error code.
226 :
227 : @return An immediate awaitable containing a failed io_result.
228 :
229 : @see immediate, io_result
230 : */
231 : inline
232 : immediate<io_result<>>
233 1 : ready(std::error_code ec) noexcept
234 : {
235 1 : return {{ec}};
236 : }
237 :
238 : /** Create an immediate awaitable for an io_result with error and one value.
239 :
240 : @param ec The error code.
241 : @param t1 The result value.
242 :
243 : @return An immediate awaitable containing `io_result<T1>{ec, t1}`.
244 : */
245 : template<class T1>
246 : immediate<io_result<T1>>
247 2 : ready(std::error_code ec, T1 t1)
248 : {
249 2 : return {{ec, std::move(t1)}};
250 : }
251 :
252 : /** Create an immediate awaitable for an io_result with error and two values.
253 :
254 : @param ec The error code.
255 : @param t1 The first result value.
256 : @param t2 The second result value.
257 :
258 : @return An immediate awaitable containing `io_result<T1,T2>{ec, t1, t2}`.
259 : */
260 : template<class T1, class T2>
261 : immediate<io_result<T1, T2>>
262 1 : ready(std::error_code ec, T1 t1, T2 t2)
263 : {
264 1 : return {{ec, std::move(t1), std::move(t2)}};
265 : }
266 :
267 : /** Create an immediate awaitable for an io_result with error and three values.
268 :
269 : @param ec The error code.
270 : @param t1 The first result value.
271 : @param t2 The second result value.
272 : @param t3 The third result value.
273 :
274 : @return An immediate awaitable containing `io_result<T1,T2,T3>{ec, t1, t2, t3}`.
275 : */
276 : template<class T1, class T2, class T3>
277 : immediate<io_result<T1, T2, T3>>
278 1 : ready(std::error_code ec, T1 t1, T2 t2, T3 t3)
279 : {
280 1 : return {{ec, std::move(t1), std::move(t2), std::move(t3)}};
281 : }
282 :
283 : } // namespace capy
284 : } // namespace boost
285 :
286 : #endif
|