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