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 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 : //----------------------------------------------------------
125 :
126 : /** Create an immediate awaitable for a successful io_result.
127 :
128 : This helper creates an @ref immediate wrapping an @ref io_result
129 : with no error and the provided values.
130 :
131 : @par Example
132 : @code
133 : immediate<io_result<std::size_t>>
134 : write(const_buffer buf)
135 : {
136 : auto n = write_sync(buf);
137 : return ready(n); // success with n bytes
138 : }
139 :
140 : immediate<io_result<>>
141 : connect()
142 : {
143 : connect_sync();
144 : return ready(); // void success
145 : }
146 : @endcode
147 :
148 : @return An immediate awaitable containing a successful io_result.
149 :
150 : @see immediate, io_result
151 : */
152 : inline
153 : immediate<io_result<>>
154 3 : ready() noexcept
155 : {
156 3 : return {{}};
157 : }
158 :
159 : /** Create an immediate awaitable for a successful io_result with one value.
160 :
161 : @param t1 The result value.
162 :
163 : @return An immediate awaitable containing `io_result<T1>{{}, t1}`.
164 : */
165 : template<class T1>
166 : immediate<io_result<T1>>
167 4 : ready(T1 t1)
168 : {
169 4 : return {{{}, std::move(t1)}};
170 : }
171 :
172 : /** Create an immediate awaitable for a successful io_result with two values.
173 :
174 : @param t1 The first result value.
175 : @param t2 The second result value.
176 :
177 : @return An immediate awaitable containing `io_result<T1,T2>{{}, t1, t2}`.
178 : */
179 : template<class T1, class T2>
180 : immediate<io_result<T1, T2>>
181 2 : ready(T1 t1, T2 t2)
182 : {
183 2 : return {{{}, std::move(t1), std::move(t2)}};
184 : }
185 :
186 : /** Create an immediate awaitable for a successful io_result with three values.
187 :
188 : @param t1 The first result value.
189 : @param t2 The second result value.
190 : @param t3 The third result value.
191 :
192 : @return An immediate awaitable containing `io_result<T1,T2,T3>{{}, t1, t2, t3}`.
193 : */
194 : template<class T1, class T2, class T3>
195 : immediate<io_result<T1, T2, T3>>
196 2 : ready(T1 t1, T2 t2, T3 t3)
197 : {
198 2 : return {{{}, std::move(t1), std::move(t2), std::move(t3)}};
199 : }
200 :
201 : //----------------------------------------------------------
202 :
203 : /** Create an immediate awaitable for a failed io_result.
204 :
205 : This helper creates an @ref immediate wrapping an @ref io_result
206 : with an error code.
207 :
208 : @par Example
209 : @code
210 : immediate<io_result<std::size_t>>
211 : write(const_buffer buf)
212 : {
213 : auto ec = write_sync(buf);
214 : if(ec)
215 : return ready(ec, std::size_t{0});
216 : return ready(buffer_size(buf));
217 : }
218 : @endcode
219 :
220 : @param ec The error code.
221 :
222 : @return An immediate awaitable containing a failed io_result.
223 :
224 : @see immediate, io_result
225 : */
226 : inline
227 : immediate<io_result<>>
228 1 : ready(std::error_code ec) noexcept
229 : {
230 1 : return {{ec}};
231 : }
232 :
233 : /** Create an immediate awaitable for an io_result with error and one value.
234 :
235 : @param ec The error code.
236 : @param t1 The result value.
237 :
238 : @return An immediate awaitable containing `io_result<T1>{ec, t1}`.
239 : */
240 : template<class T1>
241 : immediate<io_result<T1>>
242 2 : ready(std::error_code ec, T1 t1)
243 : {
244 2 : return {{ec, std::move(t1)}};
245 : }
246 :
247 : /** Create an immediate awaitable for an io_result with error and two values.
248 :
249 : @param ec The error code.
250 : @param t1 The first result value.
251 : @param t2 The second result value.
252 :
253 : @return An immediate awaitable containing `io_result<T1,T2>{ec, t1, t2}`.
254 : */
255 : template<class T1, class T2>
256 : immediate<io_result<T1, T2>>
257 1 : ready(std::error_code ec, T1 t1, T2 t2)
258 : {
259 1 : return {{ec, std::move(t1), std::move(t2)}};
260 : }
261 :
262 : /** Create an immediate awaitable for an io_result with error and three values.
263 :
264 : @param ec The error code.
265 : @param t1 The first result value.
266 : @param t2 The second result value.
267 : @param t3 The third result value.
268 :
269 : @return An immediate awaitable containing `io_result<T1,T2,T3>{ec, t1, t2, t3}`.
270 : */
271 : template<class T1, class T2, class T3>
272 : immediate<io_result<T1, T2, T3>>
273 1 : ready(std::error_code ec, T1 t1, T2 t2, T3 t3)
274 : {
275 1 : return {{ec, std::move(t1), std::move(t2), std::move(t3)}};
276 : }
277 :
278 : } // namespace capy
279 : } // namespace boost
280 :
281 : #endif
|