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