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