86.63% Lines (149/172) 90.70% Functions (39/43)
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   // 3   //
4   // Distributed under the Boost Software License, Version 1.0. (See accompanying 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) 5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6   // 6   //
7   // Official repository: https://github.com/cppalliance/capy 7   // Official repository: https://github.com/cppalliance/capy
8   // 8   //
9   9  
10   #ifndef BOOST_CAPY_IO_ANY_BUFFER_SOURCE_HPP 10   #ifndef BOOST_CAPY_IO_ANY_BUFFER_SOURCE_HPP
11   #define BOOST_CAPY_IO_ANY_BUFFER_SOURCE_HPP 11   #define BOOST_CAPY_IO_ANY_BUFFER_SOURCE_HPP
12   12  
13   #include <boost/capy/detail/config.hpp> 13   #include <boost/capy/detail/config.hpp>
14   #include <boost/capy/detail/await_suspend_helper.hpp> 14   #include <boost/capy/detail/await_suspend_helper.hpp>
15   #include <boost/capy/buffers.hpp> 15   #include <boost/capy/buffers.hpp>
16   #include <boost/capy/buffers/buffer_copy.hpp> 16   #include <boost/capy/buffers/buffer_copy.hpp>
17 - #include <boost/capy/buffers/slice.hpp>  
18   #include <boost/capy/buffers/buffer_param.hpp> 17   #include <boost/capy/buffers/buffer_param.hpp>
19   #include <boost/capy/concept/buffer_source.hpp> 18   #include <boost/capy/concept/buffer_source.hpp>
20   #include <boost/capy/concept/io_awaitable.hpp> 19   #include <boost/capy/concept/io_awaitable.hpp>
21   #include <boost/capy/concept/read_source.hpp> 20   #include <boost/capy/concept/read_source.hpp>
22   #include <boost/capy/error.hpp> 21   #include <boost/capy/error.hpp>
23   #include <boost/capy/ex/io_env.hpp> 22   #include <boost/capy/ex/io_env.hpp>
24   #include <boost/capy/io_result.hpp> 23   #include <boost/capy/io_result.hpp>
25   #include <boost/capy/io_task.hpp> 24   #include <boost/capy/io_task.hpp>
26   25  
27   #include <concepts> 26   #include <concepts>
28   #include <coroutine> 27   #include <coroutine>
29   #include <cstddef> 28   #include <cstddef>
30   #include <exception> 29   #include <exception>
31   #include <new> 30   #include <new>
32   #include <span> 31   #include <span>
33   #include <stop_token> 32   #include <stop_token>
34   #include <system_error> 33   #include <system_error>
35   #include <utility> 34   #include <utility>
36   35  
37   namespace boost { 36   namespace boost {
38   namespace capy { 37   namespace capy {
39   38  
40   /** Type-erased wrapper for any BufferSource. 39   /** Type-erased wrapper for any BufferSource.
41   40  
42   This class provides type erasure for any type satisfying the 41   This class provides type erasure for any type satisfying the
43   @ref BufferSource concept, enabling runtime polymorphism for 42   @ref BufferSource concept, enabling runtime polymorphism for
44   buffer pull operations. It uses cached awaitable storage to achieve 43   buffer pull operations. It uses cached awaitable storage to achieve
45   zero steady-state allocation after construction. 44   zero steady-state allocation after construction.
46   45  
47   The wrapper also satisfies @ref ReadSource. When the wrapped type 46   The wrapper also satisfies @ref ReadSource. When the wrapped type
48   satisfies only @ref BufferSource, the read operations are 47   satisfies only @ref BufferSource, the read operations are
49   synthesized using @ref pull and @ref consume with an extra 48   synthesized using @ref pull and @ref consume with an extra
50   buffer copy. When the wrapped type satisfies both @ref BufferSource 49   buffer copy. When the wrapped type satisfies both @ref BufferSource
51   and @ref ReadSource, the native read operations are forwarded 50   and @ref ReadSource, the native read operations are forwarded
52   directly across the virtual boundary, avoiding the copy. 51   directly across the virtual boundary, avoiding the copy.
53   52  
54   The wrapper supports two construction modes: 53   The wrapper supports two construction modes:
55   - **Owning**: Pass by value to transfer ownership. The wrapper 54   - **Owning**: Pass by value to transfer ownership. The wrapper
56   allocates storage and owns the source. 55   allocates storage and owns the source.
57   - **Reference**: Pass a pointer to wrap without ownership. The 56   - **Reference**: Pass a pointer to wrap without ownership. The
58   pointed-to source must outlive this wrapper. 57   pointed-to source must outlive this wrapper.
59   58  
60   Within each mode, the vtable is populated at compile time based 59   Within each mode, the vtable is populated at compile time based
61   on whether the wrapped type also satisfies @ref ReadSource: 60   on whether the wrapped type also satisfies @ref ReadSource:
62   - **BufferSource only**: @ref read_some and @ref read are 61   - **BufferSource only**: @ref read_some and @ref read are
63   synthesized from @ref pull and @ref consume, incurring one 62   synthesized from @ref pull and @ref consume, incurring one
64   buffer copy per operation. 63   buffer copy per operation.
65   - **BufferSource + ReadSource**: All read operations are 64   - **BufferSource + ReadSource**: All read operations are
66   forwarded natively through the type-erased boundary with 65   forwarded natively through the type-erased boundary with
67   no extra copy. 66   no extra copy.
68   67  
69   @par Awaitable Preallocation 68   @par Awaitable Preallocation
70   The constructor preallocates storage for the type-erased awaitable. 69   The constructor preallocates storage for the type-erased awaitable.
71   This reserves all virtual address space at server startup 70   This reserves all virtual address space at server startup
72   so memory usage can be measured up front, rather than 71   so memory usage can be measured up front, rather than
73   allocating piecemeal as traffic arrives. 72   allocating piecemeal as traffic arrives.
74   73  
75   @par Thread Safety 74   @par Thread Safety
76   Not thread-safe. Concurrent operations on the same wrapper 75   Not thread-safe. Concurrent operations on the same wrapper
77   are undefined behavior. 76   are undefined behavior.
78   77  
79   @par Example 78   @par Example
80   @code 79   @code
81   // Owning - takes ownership of the source 80   // Owning - takes ownership of the source
82   any_buffer_source abs(some_buffer_source{args...}); 81   any_buffer_source abs(some_buffer_source{args...});
83   82  
84   // Reference - wraps without ownership 83   // Reference - wraps without ownership
85   some_buffer_source src; 84   some_buffer_source src;
86   any_buffer_source abs(&src); 85   any_buffer_source abs(&src);
87   86  
88   const_buffer arr[16]; 87   const_buffer arr[16];
89   auto [ec, bufs] = co_await abs.pull(arr); 88   auto [ec, bufs] = co_await abs.pull(arr);
90   89  
91   // ReadSource interface also available 90   // ReadSource interface also available
92   char buf[64]; 91   char buf[64];
93   auto [ec2, n] = co_await abs.read_some(mutable_buffer(buf, 64)); 92   auto [ec2, n] = co_await abs.read_some(mutable_buffer(buf, 64));
94   @endcode 93   @endcode
95   94  
96   @see any_buffer_sink, BufferSource, ReadSource 95   @see any_buffer_sink, BufferSource, ReadSource
97   */ 96   */
98   class any_buffer_source 97   class any_buffer_source
99   { 98   {
100   struct vtable; 99   struct vtable;
101   struct awaitable_ops; 100   struct awaitable_ops;
102   struct read_awaitable_ops; 101   struct read_awaitable_ops;
103   102  
104   template<BufferSource S> 103   template<BufferSource S>
105   struct vtable_for_impl; 104   struct vtable_for_impl;
106   105  
107   // hot-path members first for cache locality 106   // hot-path members first for cache locality
108   void* source_ = nullptr; 107   void* source_ = nullptr;
109   vtable const* vt_ = nullptr; 108   vtable const* vt_ = nullptr;
110   void* cached_awaitable_ = nullptr; 109   void* cached_awaitable_ = nullptr;
111   awaitable_ops const* active_ops_ = nullptr; 110   awaitable_ops const* active_ops_ = nullptr;
112   read_awaitable_ops const* active_read_ops_ = nullptr; 111   read_awaitable_ops const* active_read_ops_ = nullptr;
113   void* storage_ = nullptr; 112   void* storage_ = nullptr;
114   113  
115   public: 114   public:
116   /** Destructor. 115   /** Destructor.
117   116  
118   Destroys the owned source (if any) and releases the cached 117   Destroys the owned source (if any) and releases the cached
119   awaitable storage. 118   awaitable storage.
120   */ 119   */
121   ~any_buffer_source(); 120   ~any_buffer_source();
122   121  
123 - /** Default constructor. 122 + /** Construct a default instance.
124   123  
125   Constructs an empty wrapper. Operations on a default-constructed 124   Constructs an empty wrapper. Operations on a default-constructed
126   wrapper result in undefined behavior. 125   wrapper result in undefined behavior.
127   */ 126   */
128   any_buffer_source() = default; 127   any_buffer_source() = default;
129   128  
130   /** Non-copyable. 129   /** Non-copyable.
131   130  
132   The awaitable cache is per-instance and cannot be shared. 131   The awaitable cache is per-instance and cannot be shared.
133   */ 132   */
134   any_buffer_source(any_buffer_source const&) = delete; 133   any_buffer_source(any_buffer_source const&) = delete;
135   any_buffer_source& operator=(any_buffer_source const&) = delete; 134   any_buffer_source& operator=(any_buffer_source const&) = delete;
136   135  
137 - /** Move constructor. 136 + /** Construct by moving.
138   137  
139   Transfers ownership of the wrapped source (if owned) and 138   Transfers ownership of the wrapped source (if owned) and
140   cached awaitable storage from `other`. After the move, `other` is 139   cached awaitable storage from `other`. After the move, `other` is
141   in a default-constructed state. 140   in a default-constructed state.
142   141  
143   @param other The wrapper to move from. 142   @param other The wrapper to move from.
144   */ 143   */
HITCBC 145   2 any_buffer_source(any_buffer_source&& other) noexcept 144   2 any_buffer_source(any_buffer_source&& other) noexcept
HITCBC 146   2 : source_(std::exchange(other.source_, nullptr)) 145   2 : source_(std::exchange(other.source_, nullptr))
HITCBC 147   2 , vt_(std::exchange(other.vt_, nullptr)) 146   2 , vt_(std::exchange(other.vt_, nullptr))
HITCBC 148   2 , cached_awaitable_(std::exchange(other.cached_awaitable_, nullptr)) 147   2 , cached_awaitable_(std::exchange(other.cached_awaitable_, nullptr))
HITCBC 149   2 , active_ops_(std::exchange(other.active_ops_, nullptr)) 148   2 , active_ops_(std::exchange(other.active_ops_, nullptr))
HITCBC 150   2 , active_read_ops_(std::exchange(other.active_read_ops_, nullptr)) 149   2 , active_read_ops_(std::exchange(other.active_read_ops_, nullptr))
HITCBC 151   2 , storage_(std::exchange(other.storage_, nullptr)) 150   2 , storage_(std::exchange(other.storage_, nullptr))
152   { 151   {
HITCBC 153   2 } 152   2 }
154   153  
155 - /** Move assignment operator. 154 + /** Assign by moving.
156   155  
157   Destroys any owned source and releases existing resources, 156   Destroys any owned source and releases existing resources,
158   then transfers ownership from `other`. 157   then transfers ownership from `other`.
159   158  
160   @param other The wrapper to move from. 159   @param other The wrapper to move from.
161   @return Reference to this wrapper. 160   @return Reference to this wrapper.
162   */ 161   */
163   any_buffer_source& 162   any_buffer_source&
164   operator=(any_buffer_source&& other) noexcept; 163   operator=(any_buffer_source&& other) noexcept;
165   164  
166   /** Construct by taking ownership of a BufferSource. 165   /** Construct by taking ownership of a BufferSource.
167   166  
168   Allocates storage and moves the source into this wrapper. 167   Allocates storage and moves the source into this wrapper.
169   The wrapper owns the source and will destroy it. If `S` also 168   The wrapper owns the source and will destroy it. If `S` also
170   satisfies @ref ReadSource, native read operations are 169   satisfies @ref ReadSource, native read operations are
171   forwarded through the virtual boundary. 170   forwarded through the virtual boundary.
172   171  
173   @param s The source to take ownership of. 172   @param s The source to take ownership of.
174   */ 173   */
175   template<BufferSource S> 174   template<BufferSource S>
176   requires (!std::same_as<std::decay_t<S>, any_buffer_source>) 175   requires (!std::same_as<std::decay_t<S>, any_buffer_source>)
177   any_buffer_source(S s); 176   any_buffer_source(S s);
178   177  
179   /** Construct by wrapping a BufferSource without ownership. 178   /** Construct by wrapping a BufferSource without ownership.
180   179  
181   Wraps the given source by pointer. The source must remain 180   Wraps the given source by pointer. The source must remain
182   valid for the lifetime of this wrapper. If `S` also 181   valid for the lifetime of this wrapper. If `S` also
183   satisfies @ref ReadSource, native read operations are 182   satisfies @ref ReadSource, native read operations are
184   forwarded through the virtual boundary. 183   forwarded through the virtual boundary.
185   184  
186   @param s Pointer to the source to wrap. 185   @param s Pointer to the source to wrap.
187   */ 186   */
188   template<BufferSource S> 187   template<BufferSource S>
189   any_buffer_source(S* s); 188   any_buffer_source(S* s);
190   189  
191   /** Check if the wrapper contains a valid source. 190   /** Check if the wrapper contains a valid source.
192   191  
193   @return `true` if wrapping a source, `false` if default-constructed 192   @return `true` if wrapping a source, `false` if default-constructed
194   or moved-from. 193   or moved-from.
195   */ 194   */
196   bool 195   bool
HITCBC 197   16 has_value() const noexcept 196   16 has_value() const noexcept
198   { 197   {
HITCBC 199   16 return source_ != nullptr; 198   16 return source_ != nullptr;
200   } 199   }
201   200  
202   /** Check if the wrapper contains a valid source. 201   /** Check if the wrapper contains a valid source.
203   202  
204   @return `true` if wrapping a source, `false` if default-constructed 203   @return `true` if wrapping a source, `false` if default-constructed
205   or moved-from. 204   or moved-from.
206   */ 205   */
207   explicit 206   explicit
HITCBC 208   2 operator bool() const noexcept 207   2 operator bool() const noexcept
209   { 208   {
HITCBC 210   2 return has_value(); 209   2 return has_value();
211   } 210   }
212   211  
213   /** Consume bytes from the source. 212   /** Consume bytes from the source.
214   213  
215   Advances the internal read position of the underlying source 214   Advances the internal read position of the underlying source
216   by the specified number of bytes. The next call to @ref pull 215   by the specified number of bytes. The next call to @ref pull
217   returns data starting after the consumed bytes. 216   returns data starting after the consumed bytes.
218   217  
219   @param n The number of bytes to consume. Must not exceed the 218   @param n The number of bytes to consume. Must not exceed the
220   total size of buffers returned by the previous @ref pull. 219   total size of buffers returned by the previous @ref pull.
221   220  
222   @par Preconditions 221   @par Preconditions
223   The wrapper must contain a valid source (`has_value() == true`). 222   The wrapper must contain a valid source (`has_value() == true`).
224   */ 223   */
225   void 224   void
226   consume(std::size_t n) noexcept; 225   consume(std::size_t n) noexcept;
227   226  
228   /** Pull buffer data from the source. 227   /** Pull buffer data from the source.
229   228  
230   Fills the provided span with buffer descriptors from the 229   Fills the provided span with buffer descriptors from the
231   underlying source. The operation completes when data is 230   underlying source. The operation completes when data is
232   available, the source is exhausted, or an error occurs. 231   available, the source is exhausted, or an error occurs.
233   232  
234   @param dest Span of const_buffer to fill. 233   @param dest Span of const_buffer to fill.
235   234  
236 - @return An awaitable yielding `(error_code,std::span<const_buffer>)`. 235 + @return An awaitable that await-returns `(error_code,std::span<const_buffer>)`.
237   On success with data, a non-empty span of filled buffers. 236   On success with data, a non-empty span of filled buffers.
238   On EOF, `ec == cond::eof` and span is empty. 237   On EOF, `ec == cond::eof` and span is empty.
239   238  
240   @par Preconditions 239   @par Preconditions
241   The wrapper must contain a valid source (`has_value() == true`). 240   The wrapper must contain a valid source (`has_value() == true`).
242   The caller must not call this function again after a prior 241   The caller must not call this function again after a prior
243   call returned an error. 242   call returned an error.
244   */ 243   */
245   auto 244   auto
246   pull(std::span<const_buffer> dest); 245   pull(std::span<const_buffer> dest);
247   246  
248   /** Read some data into a mutable buffer sequence. 247   /** Read some data into a mutable buffer sequence.
249   248  
250 - Reads one or more bytes into the caller's buffers. May fill 249 + Attempt to read up to `buffer_size( buffers )` bytes into
251 - less than the full sequence. 250 + the caller's buffers. May fill less than the full sequence.
252   251  
253   When the wrapped type provides native @ref ReadSource support, 252   When the wrapped type provides native @ref ReadSource support,
254   the operation forwards directly. Otherwise it is synthesized 253   the operation forwards directly. Otherwise it is synthesized
255   from @ref pull, @ref buffer_copy, and @ref consume. 254   from @ref pull, @ref buffer_copy, and @ref consume.
256   255  
257   @param buffers The buffer sequence to fill. 256   @param buffers The buffer sequence to fill.
258   257  
259 - @return An awaitable yielding `(error_code,std::size_t)`. 258 + @return An awaitable that await-returns `(error_code,std::size_t)`.
260   259  
261   @par Preconditions 260   @par Preconditions
262   The wrapper must contain a valid source (`has_value() == true`). 261   The wrapper must contain a valid source (`has_value() == true`).
263   The caller must not call this function again after a prior 262   The caller must not call this function again after a prior
264   call returned an error (including EOF). 263   call returned an error (including EOF).
265   264  
266   @see pull, consume 265   @see pull, consume
267   */ 266   */
268   template<MutableBufferSequence MB> 267   template<MutableBufferSequence MB>
269   io_task<std::size_t> 268   io_task<std::size_t>
270   read_some(MB buffers); 269   read_some(MB buffers);
271   270  
272   /** Read data into a mutable buffer sequence. 271   /** Read data into a mutable buffer sequence.
273   272  
274   Fills the provided buffer sequence completely. When the 273   Fills the provided buffer sequence completely. When the
275   wrapped type provides native @ref ReadSource support, each 274   wrapped type provides native @ref ReadSource support, each
276   window is forwarded directly. Otherwise the data is 275   window is forwarded directly. Otherwise the data is
277   synthesized from @ref pull, @ref buffer_copy, and @ref consume. 276   synthesized from @ref pull, @ref buffer_copy, and @ref consume.
278   277  
279   @param buffers The buffer sequence to fill. 278   @param buffers The buffer sequence to fill.
280   279  
281 - @return An awaitable yielding `(error_code,std::size_t)`. 280 + @return An awaitable that await-returns `(error_code,std::size_t)`.
282   On success, `n == buffer_size(buffers)`. 281   On success, `n == buffer_size(buffers)`.
283   On EOF, `ec == error::eof` and `n` is bytes transferred. 282   On EOF, `ec == error::eof` and `n` is bytes transferred.
284   283  
285   @par Preconditions 284   @par Preconditions
286   The wrapper must contain a valid source (`has_value() == true`). 285   The wrapper must contain a valid source (`has_value() == true`).
287   The caller must not call this function again after a prior 286   The caller must not call this function again after a prior
288   call returned an error (including EOF). 287   call returned an error (including EOF).
289   288  
290   @see pull, consume 289   @see pull, consume
291   */ 290   */
292   template<MutableBufferSequence MB> 291   template<MutableBufferSequence MB>
293   io_task<std::size_t> 292   io_task<std::size_t>
294   read(MB buffers); 293   read(MB buffers);
295   294  
296   protected: 295   protected:
297   /** Rebind to a new source after move. 296   /** Rebind to a new source after move.
298   297  
299   Updates the internal pointer to reference a new source object. 298   Updates the internal pointer to reference a new source object.
300   Used by owning wrappers after move assignment when the owned 299   Used by owning wrappers after move assignment when the owned
301   object has moved to a new location. 300   object has moved to a new location.
302   301  
303   @param new_source The new source to bind to. Must be the same 302   @param new_source The new source to bind to. Must be the same
304   type as the original source. 303   type as the original source.
305   304  
306   @note Terminates if called with a source of different type 305   @note Terminates if called with a source of different type
307   than the original. 306   than the original.
308   */ 307   */
309   template<BufferSource S> 308   template<BufferSource S>
310   void 309   void
311   rebind(S& new_source) noexcept 310   rebind(S& new_source) noexcept
312   { 311   {
313   if(vt_ != &vtable_for_impl<S>::value) 312   if(vt_ != &vtable_for_impl<S>::value)
314   std::terminate(); 313   std::terminate();
315   source_ = &new_source; 314   source_ = &new_source;
316   } 315   }
317   316  
318   private: 317   private:
319   /** Forward a partial read through the vtable. 318   /** Forward a partial read through the vtable.
320   319  
321   Constructs the underlying `read_some` awaitable in 320   Constructs the underlying `read_some` awaitable in
322   cached storage and returns a type-erased awaitable. 321   cached storage and returns a type-erased awaitable.
323   */ 322   */
324   auto 323   auto
325   read_some_(std::span<mutable_buffer const> buffers); 324   read_some_(std::span<mutable_buffer const> buffers);
326   325  
327   /** Forward a complete read through the vtable. 326   /** Forward a complete read through the vtable.
328   327  
329   Constructs the underlying `read` awaitable in 328   Constructs the underlying `read` awaitable in
330   cached storage and returns a type-erased awaitable. 329   cached storage and returns a type-erased awaitable.
331   */ 330   */
332   auto 331   auto
333   read_(std::span<mutable_buffer const> buffers); 332   read_(std::span<mutable_buffer const> buffers);
334   }; 333   };
335   334  
336 - //---------------------------------------------------------- 335 + /** Type-erased ops for awaitables that await-return `io_result<std::span<const_buffer>>`. */
337 -  
338 - /** Type-erased ops for awaitables yielding `io_result<std::span<const_buffer>>`. */  
339   struct any_buffer_source::awaitable_ops 336   struct any_buffer_source::awaitable_ops
340   { 337   {
341   bool (*await_ready)(void*); 338   bool (*await_ready)(void*);
342   std::coroutine_handle<> (*await_suspend)(void*, std::coroutine_handle<>, io_env const*); 339   std::coroutine_handle<> (*await_suspend)(void*, std::coroutine_handle<>, io_env const*);
343   io_result<std::span<const_buffer>> (*await_resume)(void*); 340   io_result<std::span<const_buffer>> (*await_resume)(void*);
344   void (*destroy)(void*) noexcept; 341   void (*destroy)(void*) noexcept;
345   }; 342   };
346   343  
347 - /** Type-erased ops for awaitables yielding `io_result<std::size_t>`. */ 344 + /** Type-erased ops for awaitables that await-return `io_result<std::size_t>`. */
348   struct any_buffer_source::read_awaitable_ops 345   struct any_buffer_source::read_awaitable_ops
349   { 346   {
350   bool (*await_ready)(void*); 347   bool (*await_ready)(void*);
351   std::coroutine_handle<> (*await_suspend)(void*, std::coroutine_handle<>, io_env const*); 348   std::coroutine_handle<> (*await_suspend)(void*, std::coroutine_handle<>, io_env const*);
352   io_result<std::size_t> (*await_resume)(void*); 349   io_result<std::size_t> (*await_resume)(void*);
353   void (*destroy)(void*) noexcept; 350   void (*destroy)(void*) noexcept;
354   }; 351   };
355   352  
356   struct any_buffer_source::vtable 353   struct any_buffer_source::vtable
357   { 354   {
358   // BufferSource ops (always populated) 355   // BufferSource ops (always populated)
359   void (*destroy)(void*) noexcept; 356   void (*destroy)(void*) noexcept;
360   void (*do_consume)(void* source, std::size_t n) noexcept; 357   void (*do_consume)(void* source, std::size_t n) noexcept;
361   std::size_t awaitable_size; 358   std::size_t awaitable_size;
362   std::size_t awaitable_align; 359   std::size_t awaitable_align;
363   awaitable_ops const* (*construct_awaitable)( 360   awaitable_ops const* (*construct_awaitable)(
364   void* source, 361   void* source,
365   void* storage, 362   void* storage,
366   std::span<const_buffer> dest); 363   std::span<const_buffer> dest);
367   364  
368   // ReadSource forwarding (null when wrapped type is BufferSource-only) 365   // ReadSource forwarding (null when wrapped type is BufferSource-only)
369   read_awaitable_ops const* (*construct_read_some_awaitable)( 366   read_awaitable_ops const* (*construct_read_some_awaitable)(
370   void* source, 367   void* source,
371   void* storage, 368   void* storage,
372   std::span<mutable_buffer const> buffers); 369   std::span<mutable_buffer const> buffers);
373   read_awaitable_ops const* (*construct_read_awaitable)( 370   read_awaitable_ops const* (*construct_read_awaitable)(
374   void* source, 371   void* source,
375   void* storage, 372   void* storage,
376   std::span<mutable_buffer const> buffers); 373   std::span<mutable_buffer const> buffers);
377   }; 374   };
378   375  
379   template<BufferSource S> 376   template<BufferSource S>
380   struct any_buffer_source::vtable_for_impl 377   struct any_buffer_source::vtable_for_impl
381   { 378   {
382   using PullAwaitable = decltype(std::declval<S&>().pull( 379   using PullAwaitable = decltype(std::declval<S&>().pull(
383   std::declval<std::span<const_buffer>>())); 380   std::declval<std::span<const_buffer>>()));
384   381  
385   static void 382   static void
HITCBC 386   7 do_destroy_impl(void* source) noexcept 383   7 do_destroy_impl(void* source) noexcept
387   { 384   {
HITCBC 388   7 static_cast<S*>(source)->~S(); 385   7 static_cast<S*>(source)->~S();
HITCBC 389   7 } 386   7 }
390   387  
391   static void 388   static void
HITCBC 392   45 do_consume_impl(void* source, std::size_t n) noexcept 389   45 do_consume_impl(void* source, std::size_t n) noexcept
393   { 390   {
HITCBC 394   45 static_cast<S*>(source)->consume(n); 391   45 static_cast<S*>(source)->consume(n);
HITCBC 395   45 } 392   45 }
396   393  
397   static awaitable_ops const* 394   static awaitable_ops const*
HITCBC 398   110 construct_awaitable_impl( 395   110 construct_awaitable_impl(
399   void* source, 396   void* source,
400   void* storage, 397   void* storage,
401   std::span<const_buffer> dest) 398   std::span<const_buffer> dest)
402   { 399   {
HITCBC 403   110 auto& s = *static_cast<S*>(source); 400   110 auto& s = *static_cast<S*>(source);
HITCBC 404   110 ::new(storage) PullAwaitable(s.pull(dest)); 401   110 ::new(storage) PullAwaitable(s.pull(dest));
405   402  
406   static constexpr awaitable_ops ops = { 403   static constexpr awaitable_ops ops = {
HITCBC 407   110 +[](void* p) { 404   110 +[](void* p) {
HITCBC 408   110 return static_cast<PullAwaitable*>(p)->await_ready(); 405   110 return static_cast<PullAwaitable*>(p)->await_ready();
409   }, 406   },
MISUBC 410   +[](void* p, std::coroutine_handle<> h, io_env const* env) { 407   +[](void* p, std::coroutine_handle<> h, io_env const* env) {
MISUBC 411   return detail::call_await_suspend( 408   return detail::call_await_suspend(
MISUBC 412   static_cast<PullAwaitable*>(p), h, env); 409   static_cast<PullAwaitable*>(p), h, env);
413   }, 410   },
HITCBC 414   110 +[](void* p) { 411   110 +[](void* p) {
HITCBC 415   110 return static_cast<PullAwaitable*>(p)->await_resume(); 412   110 return static_cast<PullAwaitable*>(p)->await_resume();
416   }, 413   },
HITCBC 417   110 +[](void* p) noexcept { 414   110 +[](void* p) noexcept {
HITCBC 418   110 static_cast<PullAwaitable*>(p)->~PullAwaitable(); 415   110 static_cast<PullAwaitable*>(p)->~PullAwaitable();
419   } 416   }
420   }; 417   };
HITCBC 421   110 return &ops; 418   110 return &ops;
422   } 419   }
423 - //------------------------------------------------------  
424 - // ReadSource forwarding (only instantiated when ReadSource<S>)  
425 -  
426   420  
427   static read_awaitable_ops const* 421   static read_awaitable_ops const*
HITCBC 428   48 construct_read_some_awaitable_impl( 422   48 construct_read_some_awaitable_impl(
429   void* source, 423   void* source,
430   void* storage, 424   void* storage,
431   std::span<mutable_buffer const> buffers) 425   std::span<mutable_buffer const> buffers)
432   requires ReadSource<S> 426   requires ReadSource<S>
433   { 427   {
434   using Aw = decltype(std::declval<S&>().read_some( 428   using Aw = decltype(std::declval<S&>().read_some(
435   std::span<mutable_buffer const>{})); 429   std::span<mutable_buffer const>{}));
HITCBC 436   48 auto& s = *static_cast<S*>(source); 430   48 auto& s = *static_cast<S*>(source);
HITCBC 437   48 ::new(storage) Aw(s.read_some(buffers)); 431   48 ::new(storage) Aw(s.read_some(buffers));
438   432  
439   static constexpr read_awaitable_ops ops = { 433   static constexpr read_awaitable_ops ops = {
HITCBC 440   48 +[](void* p) { 434   48 +[](void* p) {
HITCBC 441   48 return static_cast<Aw*>(p)->await_ready(); 435   48 return static_cast<Aw*>(p)->await_ready();
442   }, 436   },
MISUBC 443   +[](void* p, std::coroutine_handle<> h, io_env const* env) { 437   +[](void* p, std::coroutine_handle<> h, io_env const* env) {
MISUBC 444   return detail::call_await_suspend( 438   return detail::call_await_suspend(
MISUBC 445   static_cast<Aw*>(p), h, env); 439   static_cast<Aw*>(p), h, env);
446   }, 440   },
HITCBC 447   48 +[](void* p) { 441   48 +[](void* p) {
HITCBC 448   48 return static_cast<Aw*>(p)->await_resume(); 442   48 return static_cast<Aw*>(p)->await_resume();
449   }, 443   },
HITCBC 450   48 +[](void* p) noexcept { 444   48 +[](void* p) noexcept {
HITCBC 451   48 static_cast<Aw*>(p)->~Aw(); 445   48 static_cast<Aw*>(p)->~Aw();
452   } 446   }
453   }; 447   };
HITCBC 454   48 return &ops; 448   48 return &ops;
455   } 449   }
456   450  
457   static read_awaitable_ops const* 451   static read_awaitable_ops const*
HITCBC 458   18 construct_read_awaitable_impl( 452   18 construct_read_awaitable_impl(
459   void* source, 453   void* source,
460   void* storage, 454   void* storage,
461   std::span<mutable_buffer const> buffers) 455   std::span<mutable_buffer const> buffers)
462   requires ReadSource<S> 456   requires ReadSource<S>
463   { 457   {
464   using Aw = decltype(std::declval<S&>().read( 458   using Aw = decltype(std::declval<S&>().read(
465   std::span<mutable_buffer const>{})); 459   std::span<mutable_buffer const>{}));
HITCBC 466   18 auto& s = *static_cast<S*>(source); 460   18 auto& s = *static_cast<S*>(source);
HITCBC 467   18 ::new(storage) Aw(s.read(buffers)); 461   18 ::new(storage) Aw(s.read(buffers));
468   462  
469   static constexpr read_awaitable_ops ops = { 463   static constexpr read_awaitable_ops ops = {
HITCBC 470   18 +[](void* p) { 464   18 +[](void* p) {
HITCBC 471   18 return static_cast<Aw*>(p)->await_ready(); 465   18 return static_cast<Aw*>(p)->await_ready();
472   }, 466   },
MISUBC 473   +[](void* p, std::coroutine_handle<> h, io_env const* env) { 467   +[](void* p, std::coroutine_handle<> h, io_env const* env) {
MISUBC 474   return detail::call_await_suspend( 468   return detail::call_await_suspend(
MISUBC 475   static_cast<Aw*>(p), h, env); 469   static_cast<Aw*>(p), h, env);
476   }, 470   },
HITCBC 477   18 +[](void* p) { 471   18 +[](void* p) {
HITCBC 478   18 return static_cast<Aw*>(p)->await_resume(); 472   18 return static_cast<Aw*>(p)->await_resume();
479   }, 473   },
HITCBC 480   18 +[](void* p) noexcept { 474   18 +[](void* p) noexcept {
HITCBC 481   18 static_cast<Aw*>(p)->~Aw(); 475   18 static_cast<Aw*>(p)->~Aw();
482   } 476   }
483   }; 477   };
HITCBC 484   18 return &ops; 478   18 return &ops;
485   } 479   }
486 - //------------------------------------------------------  
487 -  
488   480  
489   static consteval std::size_t 481   static consteval std::size_t
490   compute_max_size() noexcept 482   compute_max_size() noexcept
491   { 483   {
492   std::size_t s = sizeof(PullAwaitable); 484   std::size_t s = sizeof(PullAwaitable);
493   if constexpr (ReadSource<S>) 485   if constexpr (ReadSource<S>)
494   { 486   {
495   using RS = decltype(std::declval<S&>().read_some( 487   using RS = decltype(std::declval<S&>().read_some(
496   std::span<mutable_buffer const>{})); 488   std::span<mutable_buffer const>{}));
497   using R = decltype(std::declval<S&>().read( 489   using R = decltype(std::declval<S&>().read(
498   std::span<mutable_buffer const>{})); 490   std::span<mutable_buffer const>{}));
499   491  
500   if(sizeof(RS) > s) s = sizeof(RS); 492   if(sizeof(RS) > s) s = sizeof(RS);
501   if(sizeof(R) > s) s = sizeof(R); 493   if(sizeof(R) > s) s = sizeof(R);
502   } 494   }
503   return s; 495   return s;
504   } 496   }
505   497  
506   static consteval std::size_t 498   static consteval std::size_t
507   compute_max_align() noexcept 499   compute_max_align() noexcept
508   { 500   {
509   std::size_t a = alignof(PullAwaitable); 501   std::size_t a = alignof(PullAwaitable);
510   if constexpr (ReadSource<S>) 502   if constexpr (ReadSource<S>)
511   { 503   {
512   using RS = decltype(std::declval<S&>().read_some( 504   using RS = decltype(std::declval<S&>().read_some(
513   std::span<mutable_buffer const>{})); 505   std::span<mutable_buffer const>{}));
514   using R = decltype(std::declval<S&>().read( 506   using R = decltype(std::declval<S&>().read(
515   std::span<mutable_buffer const>{})); 507   std::span<mutable_buffer const>{}));
516   508  
517   if(alignof(RS) > a) a = alignof(RS); 509   if(alignof(RS) > a) a = alignof(RS);
518   if(alignof(R) > a) a = alignof(R); 510   if(alignof(R) > a) a = alignof(R);
519   } 511   }
520   return a; 512   return a;
521   } 513   }
522   514  
523   static consteval vtable 515   static consteval vtable
524   make_vtable() noexcept 516   make_vtable() noexcept
525   { 517   {
526   vtable v{}; 518   vtable v{};
527   v.destroy = &do_destroy_impl; 519   v.destroy = &do_destroy_impl;
528   v.do_consume = &do_consume_impl; 520   v.do_consume = &do_consume_impl;
529   v.awaitable_size = compute_max_size(); 521   v.awaitable_size = compute_max_size();
530   v.awaitable_align = compute_max_align(); 522   v.awaitable_align = compute_max_align();
531   v.construct_awaitable = &construct_awaitable_impl; 523   v.construct_awaitable = &construct_awaitable_impl;
532   v.construct_read_some_awaitable = nullptr; 524   v.construct_read_some_awaitable = nullptr;
533   v.construct_read_awaitable = nullptr; 525   v.construct_read_awaitable = nullptr;
534   526  
535   if constexpr (ReadSource<S>) 527   if constexpr (ReadSource<S>)
536   { 528   {
537   v.construct_read_some_awaitable = 529   v.construct_read_some_awaitable =
538   &construct_read_some_awaitable_impl; 530   &construct_read_some_awaitable_impl;
539   v.construct_read_awaitable = 531   v.construct_read_awaitable =
540   &construct_read_awaitable_impl; 532   &construct_read_awaitable_impl;
541   } 533   }
542   return v; 534   return v;
543   } 535   }
544   536  
545   static constexpr vtable value = make_vtable(); 537   static constexpr vtable value = make_vtable();
546   }; 538   };
547 - //----------------------------------------------------------  
548 -  
549   539  
550   inline 540   inline
HITCBC 551   124 any_buffer_source::~any_buffer_source() 541   124 any_buffer_source::~any_buffer_source()
552   { 542   {
HITCBC 553   124 if(storage_) 543   124 if(storage_)
554   { 544   {
HITCBC 555   7 vt_->destroy(source_); 545   7 vt_->destroy(source_);
HITCBC 556   7 ::operator delete(storage_); 546   7 ::operator delete(storage_);
557   } 547   }
HITCBC 558   124 if(cached_awaitable_) 548   124 if(cached_awaitable_)
HITCBC 559   119 ::operator delete(cached_awaitable_); 549   119 ::operator delete(cached_awaitable_);
HITCBC 560   124 } 550   124 }
561   551  
562   inline any_buffer_source& 552   inline any_buffer_source&
HITCBC 563   2 any_buffer_source::operator=(any_buffer_source&& other) noexcept 553   2 any_buffer_source::operator=(any_buffer_source&& other) noexcept
564   { 554   {
HITCBC 565   2 if(this != &other) 555   2 if(this != &other)
566   { 556   {
HITCBC 567   2 if(storage_) 557   2 if(storage_)
568   { 558   {
MISUBC 569   vt_->destroy(source_); 559   vt_->destroy(source_);
MISUBC 570   ::operator delete(storage_); 560   ::operator delete(storage_);
571   } 561   }
HITCBC 572   2 if(cached_awaitable_) 562   2 if(cached_awaitable_)
MISUBC 573   ::operator delete(cached_awaitable_); 563   ::operator delete(cached_awaitable_);
HITCBC 574   2 source_ = std::exchange(other.source_, nullptr); 564   2 source_ = std::exchange(other.source_, nullptr);
HITCBC 575   2 vt_ = std::exchange(other.vt_, nullptr); 565   2 vt_ = std::exchange(other.vt_, nullptr);
HITCBC 576   2 cached_awaitable_ = std::exchange(other.cached_awaitable_, nullptr); 566   2 cached_awaitable_ = std::exchange(other.cached_awaitable_, nullptr);
HITCBC 577   2 storage_ = std::exchange(other.storage_, nullptr); 567   2 storage_ = std::exchange(other.storage_, nullptr);
HITCBC 578   2 active_ops_ = std::exchange(other.active_ops_, nullptr); 568   2 active_ops_ = std::exchange(other.active_ops_, nullptr);
HITCBC 579   2 active_read_ops_ = std::exchange(other.active_read_ops_, nullptr); 569   2 active_read_ops_ = std::exchange(other.active_read_ops_, nullptr);
580   } 570   }
HITCBC 581   2 return *this; 571   2 return *this;
582   } 572   }
583   573  
584   template<BufferSource S> 574   template<BufferSource S>
585   requires (!std::same_as<std::decay_t<S>, any_buffer_source>) 575   requires (!std::same_as<std::decay_t<S>, any_buffer_source>)
HITCBC 586   7 any_buffer_source::any_buffer_source(S s) 576   7 any_buffer_source::any_buffer_source(S s)
HITCBC 587   7 : vt_(&vtable_for_impl<S>::value) 577   7 : vt_(&vtable_for_impl<S>::value)
588   { 578   {
589   struct guard { 579   struct guard {
590   any_buffer_source* self; 580   any_buffer_source* self;
591   bool committed = false; 581   bool committed = false;
HITCBC 592   7 ~guard() { 582   7 ~guard() {
HITCBC 593   7 if(!committed && self->storage_) { 583   7 if(!committed && self->storage_) {
MISUBC 594   self->vt_->destroy(self->source_); 584   self->vt_->destroy(self->source_);
MISUBC 595   ::operator delete(self->storage_); 585   ::operator delete(self->storage_);
MISUBC 596   self->storage_ = nullptr; 586   self->storage_ = nullptr;
MISUBC 597   self->source_ = nullptr; 587   self->source_ = nullptr;
598   } 588   }
HITCBC 599   7 } 589   7 }
HITCBC 600   7 } g{this}; 590   7 } g{this};
601   591  
HITCBC 602   7 storage_ = ::operator new(sizeof(S)); 592   7 storage_ = ::operator new(sizeof(S));
HITCBC 603   7 source_ = ::new(storage_) S(std::move(s)); 593   7 source_ = ::new(storage_) S(std::move(s));
604   594  
HITCBC 605   7 cached_awaitable_ = ::operator new(vt_->awaitable_size); 595   7 cached_awaitable_ = ::operator new(vt_->awaitable_size);
606   596  
HITCBC 607   7 g.committed = true; 597   7 g.committed = true;
HITCBC 608   7 } 598   7 }
609   599  
610   template<BufferSource S> 600   template<BufferSource S>
HITCBC 611   112 any_buffer_source::any_buffer_source(S* s) 601   112 any_buffer_source::any_buffer_source(S* s)
HITCBC 612   112 : source_(s) 602   112 : source_(s)
HITCBC 613   112 , vt_(&vtable_for_impl<S>::value) 603   112 , vt_(&vtable_for_impl<S>::value)
614   { 604   {
HITCBC 615   112 cached_awaitable_ = ::operator new(vt_->awaitable_size); 605   112 cached_awaitable_ = ::operator new(vt_->awaitable_size);
HITCBC 616   112 } 606   112 }
617 - //----------------------------------------------------------  
618 -  
619   607  
620   inline void 608   inline void
HITCBC 621   45 any_buffer_source::consume(std::size_t n) noexcept 609   45 any_buffer_source::consume(std::size_t n) noexcept
622   { 610   {
HITCBC 623   45 vt_->do_consume(source_, n); 611   45 vt_->do_consume(source_, n);
HITCBC 624   45 } 612   45 }
625   613  
626   inline auto 614   inline auto
HITCBC 627   110 any_buffer_source::pull(std::span<const_buffer> dest) 615   110 any_buffer_source::pull(std::span<const_buffer> dest)
628   { 616   {
629   struct awaitable 617   struct awaitable
630   { 618   {
631   any_buffer_source* self_; 619   any_buffer_source* self_;
632   std::span<const_buffer> dest_; 620   std::span<const_buffer> dest_;
633   621  
634   bool 622   bool
HITCBC 635   110 await_ready() 623   110 await_ready()
636   { 624   {
HITCBC 637   220 self_->active_ops_ = self_->vt_->construct_awaitable( 625   220 self_->active_ops_ = self_->vt_->construct_awaitable(
HITCBC 638   110 self_->source_, 626   110 self_->source_,
HITCBC 639   110 self_->cached_awaitable_, 627   110 self_->cached_awaitable_,
640   dest_); 628   dest_);
HITCBC 641   110 return self_->active_ops_->await_ready(self_->cached_awaitable_); 629   110 return self_->active_ops_->await_ready(self_->cached_awaitable_);
642   } 630   }
643   631  
644   std::coroutine_handle<> 632   std::coroutine_handle<>
MISUBC 645   await_suspend(std::coroutine_handle<> h, io_env const* env) 633   await_suspend(std::coroutine_handle<> h, io_env const* env)
646   { 634   {
MISUBC 647   return self_->active_ops_->await_suspend( 635   return self_->active_ops_->await_suspend(
MISUBC 648   self_->cached_awaitable_, h, env); 636   self_->cached_awaitable_, h, env);
649   } 637   }
650   638  
651   io_result<std::span<const_buffer>> 639   io_result<std::span<const_buffer>>
HITCBC 652   110 await_resume() 640   110 await_resume()
653   { 641   {
654   struct guard { 642   struct guard {
655   any_buffer_source* self; 643   any_buffer_source* self;
HITCBC 656   110 ~guard() { 644   110 ~guard() {
HITCBC 657   110 self->active_ops_->destroy(self->cached_awaitable_); 645   110 self->active_ops_->destroy(self->cached_awaitable_);
HITCBC 658   110 self->active_ops_ = nullptr; 646   110 self->active_ops_ = nullptr;
HITCBC 659   110 } 647   110 }
HITCBC 660   110 } g{self_}; 648   110 } g{self_};
HITCBC 661   110 return self_->active_ops_->await_resume( 649   110 return self_->active_ops_->await_resume(
HITCBC 662   195 self_->cached_awaitable_); 650   195 self_->cached_awaitable_);
HITCBC 663   110 } 651   110 }
664   }; 652   };
HITCBC 665   110 return awaitable{this, dest}; 653   110 return awaitable{this, dest};
666   } 654   }
667 - //----------------------------------------------------------  
668 - // Private helpers for native ReadSource forwarding  
669 -  
670   655  
671   inline auto 656   inline auto
HITCBC 672   48 any_buffer_source::read_some_( 657   48 any_buffer_source::read_some_(
673   std::span<mutable_buffer const> buffers) 658   std::span<mutable_buffer const> buffers)
674   { 659   {
675   struct awaitable 660   struct awaitable
676   { 661   {
677   any_buffer_source* self_; 662   any_buffer_source* self_;
678   std::span<mutable_buffer const> buffers_; 663   std::span<mutable_buffer const> buffers_;
679   664  
680   bool 665   bool
HITCBC 681   48 await_ready() const noexcept 666   48 await_ready() const noexcept
682   { 667   {
HITCBC 683   48 return false; 668   48 return false;
684   } 669   }
685   670  
686   std::coroutine_handle<> 671   std::coroutine_handle<>
HITCBC 687   48 await_suspend(std::coroutine_handle<> h, io_env const* env) 672   48 await_suspend(std::coroutine_handle<> h, io_env const* env)
688   { 673   {
HITCBC 689   96 self_->active_read_ops_ = 674   96 self_->active_read_ops_ =
HITCBC 690   96 self_->vt_->construct_read_some_awaitable( 675   96 self_->vt_->construct_read_some_awaitable(
HITCBC 691   48 self_->source_, 676   48 self_->source_,
HITCBC 692   48 self_->cached_awaitable_, 677   48 self_->cached_awaitable_,
693   buffers_); 678   buffers_);
694   679  
HITCBC 695   48 if(self_->active_read_ops_->await_ready( 680   48 if(self_->active_read_ops_->await_ready(
HITCBC 696   48 self_->cached_awaitable_)) 681   48 self_->cached_awaitable_))
HITCBC 697   48 return h; 682   48 return h;
698   683  
MISUBC 699   return self_->active_read_ops_->await_suspend( 684   return self_->active_read_ops_->await_suspend(
MISUBC 700   self_->cached_awaitable_, h, env); 685   self_->cached_awaitable_, h, env);
701   } 686   }
702   687  
703   io_result<std::size_t> 688   io_result<std::size_t>
HITCBC 704   48 await_resume() 689   48 await_resume()
705   { 690   {
706   struct guard { 691   struct guard {
707   any_buffer_source* self; 692   any_buffer_source* self;
HITCBC 708   48 ~guard() { 693   48 ~guard() {
HITCBC 709   48 self->active_read_ops_->destroy( 694   48 self->active_read_ops_->destroy(
HITCBC 710   48 self->cached_awaitable_); 695   48 self->cached_awaitable_);
HITCBC 711   48 self->active_read_ops_ = nullptr; 696   48 self->active_read_ops_ = nullptr;
HITCBC 712   48 } 697   48 }
HITCBC 713   48 } g{self_}; 698   48 } g{self_};
HITCBC 714   48 return self_->active_read_ops_->await_resume( 699   48 return self_->active_read_ops_->await_resume(
HITCBC 715   88 self_->cached_awaitable_); 700   88 self_->cached_awaitable_);
HITCBC 716   48 } 701   48 }
717   }; 702   };
HITCBC 718   48 return awaitable{this, buffers}; 703   48 return awaitable{this, buffers};
719   } 704   }
720   705  
721   inline auto 706   inline auto
HITCBC 722   18 any_buffer_source::read_( 707   18 any_buffer_source::read_(
723   std::span<mutable_buffer const> buffers) 708   std::span<mutable_buffer const> buffers)
724   { 709   {
725   struct awaitable 710   struct awaitable
726   { 711   {
727   any_buffer_source* self_; 712   any_buffer_source* self_;
728   std::span<mutable_buffer const> buffers_; 713   std::span<mutable_buffer const> buffers_;
729   714  
730   bool 715   bool
HITCBC 731   18 await_ready() const noexcept 716   18 await_ready() const noexcept
732   { 717   {
HITCBC 733   18 return false; 718   18 return false;
734   } 719   }
735   720  
736   std::coroutine_handle<> 721   std::coroutine_handle<>
HITCBC 737   18 await_suspend(std::coroutine_handle<> h, io_env const* env) 722   18 await_suspend(std::coroutine_handle<> h, io_env const* env)
738   { 723   {
HITCBC 739   36 self_->active_read_ops_ = 724   36 self_->active_read_ops_ =
HITCBC 740   36 self_->vt_->construct_read_awaitable( 725   36 self_->vt_->construct_read_awaitable(
HITCBC 741   18 self_->source_, 726   18 self_->source_,
HITCBC 742   18 self_->cached_awaitable_, 727   18 self_->cached_awaitable_,
743   buffers_); 728   buffers_);
744   729  
HITCBC 745   18 if(self_->active_read_ops_->await_ready( 730   18 if(self_->active_read_ops_->await_ready(
HITCBC 746   18 self_->cached_awaitable_)) 731   18 self_->cached_awaitable_))
HITCBC 747   18 return h; 732   18 return h;
748   733  
MISUBC 749   return self_->active_read_ops_->await_suspend( 734   return self_->active_read_ops_->await_suspend(
MISUBC 750   self_->cached_awaitable_, h, env); 735   self_->cached_awaitable_, h, env);
751   } 736   }
752   737  
753   io_result<std::size_t> 738   io_result<std::size_t>
HITCBC 754   18 await_resume() 739   18 await_resume()
755   { 740   {
756   struct guard { 741   struct guard {
757   any_buffer_source* self; 742   any_buffer_source* self;
HITCBC 758   18 ~guard() { 743   18 ~guard() {
HITCBC 759   18 self->active_read_ops_->destroy( 744   18 self->active_read_ops_->destroy(
HITCBC 760   18 self->cached_awaitable_); 745   18 self->cached_awaitable_);
HITCBC 761   18 self->active_read_ops_ = nullptr; 746   18 self->active_read_ops_ = nullptr;
HITCBC 762   18 } 747   18 }
HITCBC 763   18 } g{self_}; 748   18 } g{self_};
HITCBC 764   18 return self_->active_read_ops_->await_resume( 749   18 return self_->active_read_ops_->await_resume(
HITCBC 765   30 self_->cached_awaitable_); 750   30 self_->cached_awaitable_);
HITCBC 766   18 } 751   18 }
767   }; 752   };
HITCBC 768   18 return awaitable{this, buffers}; 753   18 return awaitable{this, buffers};
769   } 754   }
770 - //----------------------------------------------------------  
771 - // Public ReadSource methods  
772 -  
773   755  
774   template<MutableBufferSequence MB> 756   template<MutableBufferSequence MB>
775   io_task<std::size_t> 757   io_task<std::size_t>
HITCBC 776   58 any_buffer_source::read_some(MB buffers) 758   58 any_buffer_source::read_some(MB buffers)
777   { 759   {
778   buffer_param<MB> bp(buffers); 760   buffer_param<MB> bp(buffers);
779   auto dest = bp.data(); 761   auto dest = bp.data();
780   if(dest.empty()) 762   if(dest.empty())
781   co_return {{}, 0}; 763   co_return {{}, 0};
782   764  
783   // Native ReadSource path 765   // Native ReadSource path
784   if(vt_->construct_read_some_awaitable) 766   if(vt_->construct_read_some_awaitable)
785   co_return co_await read_some_(dest); 767   co_return co_await read_some_(dest);
786   768  
787   // Synthesized path: pull + buffer_copy + consume 769   // Synthesized path: pull + buffer_copy + consume
788   const_buffer arr[detail::max_iovec_]; 770   const_buffer arr[detail::max_iovec_];
789   auto [ec, bufs] = co_await pull(arr); 771   auto [ec, bufs] = co_await pull(arr);
790   if(ec) 772   if(ec)
791   co_return {ec, 0}; 773   co_return {ec, 0};
792   774  
793   auto n = buffer_copy(dest, bufs); 775   auto n = buffer_copy(dest, bufs);
794   consume(n); 776   consume(n);
795   co_return {{}, n}; 777   co_return {{}, n};
HITCBC 796   116 } 778   116 }
797   779  
798   template<MutableBufferSequence MB> 780   template<MutableBufferSequence MB>
799   io_task<std::size_t> 781   io_task<std::size_t>
HITCBC 800   24 any_buffer_source::read(MB buffers) 782   24 any_buffer_source::read(MB buffers)
801   { 783   {
802   buffer_param<MB> bp(buffers); 784   buffer_param<MB> bp(buffers);
803   std::size_t total = 0; 785   std::size_t total = 0;
804   786  
805   // Native ReadSource path 787   // Native ReadSource path
806   if(vt_->construct_read_awaitable) 788   if(vt_->construct_read_awaitable)
807   { 789   {
808   for(;;) 790   for(;;)
809   { 791   {
810   auto dest = bp.data(); 792   auto dest = bp.data();
811   if(dest.empty()) 793   if(dest.empty())
812   break; 794   break;
813   795  
814   auto [ec, n] = co_await read_(dest); 796   auto [ec, n] = co_await read_(dest);
815   total += n; 797   total += n;
816   if(ec) 798   if(ec)
817   co_return {ec, total}; 799   co_return {ec, total};
818   bp.consume(n); 800   bp.consume(n);
819   } 801   }
820   co_return {{}, total}; 802   co_return {{}, total};
821   } 803   }
822   804  
823   // Synthesized path: pull + buffer_copy + consume 805   // Synthesized path: pull + buffer_copy + consume
824   for(;;) 806   for(;;)
825   { 807   {
826   auto dest = bp.data(); 808   auto dest = bp.data();
827   if(dest.empty()) 809   if(dest.empty())
828   break; 810   break;
829   811  
830   const_buffer arr[detail::max_iovec_]; 812   const_buffer arr[detail::max_iovec_];
831   auto [ec, bufs] = co_await pull(arr); 813   auto [ec, bufs] = co_await pull(arr);
832   814  
833   if(ec) 815   if(ec)
834   co_return {ec, total}; 816   co_return {ec, total};
835   817  
836   auto n = buffer_copy(dest, bufs); 818   auto n = buffer_copy(dest, bufs);
837   consume(n); 819   consume(n);
838   total += n; 820   total += n;
839   bp.consume(n); 821   bp.consume(n);
840   } 822   }
841   823  
842   co_return {{}, total}; 824   co_return {{}, total};
DCB 843 - 48  
844 - //----------------------------------------------------------  
HITGIC 845   } 825   48 }
846   826  
847   static_assert(BufferSource<any_buffer_source>); 827   static_assert(BufferSource<any_buffer_source>);
848   static_assert(ReadSource<any_buffer_source>); 828   static_assert(ReadSource<any_buffer_source>);
849   829  
850   } // namespace capy 830   } // namespace capy
851   } // namespace boost 831   } // namespace boost
852   832  
853   #endif 833   #endif