TLA Line data Source code
1 : //
2 : // Copyright (c) 2026 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 : #ifndef BOOST_CAPY_ASIO_STREAM_HPP
10 : #define BOOST_CAPY_ASIO_STREAM_HPP
11 :
12 : #include <boost/capy/asio/as_io_awaitable.hpp>
13 : #include <boost/capy/asio/buffers.hpp>
14 : #include <boost/capy/asio/executor_adapter.hpp>
15 : #include <boost/capy/asio/spawn.hpp>
16 : #include <boost/capy/concept/stream.hpp>
17 : #include <boost/capy/concept/executor.hpp>
18 : #include <boost/capy/ex/any_executor.hpp>
19 : #include <boost/capy/io/any_stream.hpp>
20 : #include <boost/capy/io/any_read_stream.hpp>
21 : #include <boost/capy/io/any_write_stream.hpp>
22 :
23 : namespace boost::capy
24 : {
25 :
26 : /** Wraps a capy ReadStream for use with Asio async operations.
27 :
28 : Adapts a capy `ReadStream` to provide Asio-style `async_read_some`
29 : operations with completion token support.
30 :
31 : @tparam Stream The underlying capy ReadStream type
32 : @tparam Exec The executor type
33 :
34 : @par Example
35 : @code
36 : capy::any_read_stream stream = ...;
37 : auto exec = capy::wrap_asio_executor(io.get_executor());
38 : capy::async_read_stream reader(std::move(stream), exec);
39 :
40 : auto [ec, n] = co_await reader.async_read_some(buffer, capy::as_io_awaitable);
41 : @endcode
42 : */
43 : template<ReadStream Stream = any_stream, Executor Exec = any_executor>
44 : struct async_read_stream
45 : {
46 : using executor_type = asio_executor_adapter<Exec>;
47 : using next_layer_type = Stream;
48 :
49 : /// Default constructor.
50 : async_read_stream() = default;
51 :
52 : /// Construct from a stream and executor.
53 HIT 1 : async_read_stream(Stream stream, Exec executor)
54 : noexcept(std::is_nothrow_move_constructible_v<Stream> &&
55 : std::is_nothrow_move_constructible_v<Exec>)
56 1 : : stream_(std::move(stream))
57 1 : , executor_(std::move(executor))
58 : {
59 1 : }
60 :
61 : async_read_stream(const async_read_stream&)
62 : noexcept(std::is_nothrow_copy_constructible_v<Stream> &&
63 : std::is_nothrow_copy_constructible_v<Exec>) = default;
64 : async_read_stream(async_read_stream&&)
65 : noexcept(std::is_nothrow_move_constructible_v<Stream> &&
66 : std::is_nothrow_move_constructible_v<Exec>) = default;
67 : async_read_stream& operator=(const async_read_stream&)
68 : noexcept(std::is_nothrow_copy_assignable_v<Stream> &&
69 : std::is_nothrow_copy_assignable_v<Exec>) = default;
70 : async_read_stream& operator=(async_read_stream&&)
71 : noexcept(std::is_nothrow_move_assignable_v<Stream> &&
72 : std::is_nothrow_move_assignable_v<Exec>) = default;
73 :
74 : /// Returns the executor adapter for Asio compatibility.
75 : executor_type get_executor() const { return executor_; }
76 :
77 : /// Initiates an async read, returning a spawn handle.
78 : template<typename Buffer>
79 : auto async_read_some(Buffer && buffer)
80 : {
81 : return asio_spawn(
82 : executor_,
83 : stream_.read_some(as_asio_buffer_sequence(std::forward<Buffer>(buffer))));
84 : }
85 :
86 : /// Initiates an async read with a completion token.
87 : template<typename Buffer, typename CompletionToken>
88 2 : auto async_read_some(Buffer && buffer, CompletionToken && token)
89 : {
90 4 : return asio_spawn(
91 : executor_,
92 2 : stream_.read_some(as_asio_buffer_sequence(std::forward<Buffer>(buffer))),
93 2 : std::forward<CompletionToken>(token));
94 : }
95 :
96 : /// Returns a reference inter to the underlying stream.
97 1 : next_layer_type& next_layer() { return stream_; }
98 : /// Returns a const reference to the underlying stream.
99 : const next_layer_type& next_layer() const { return stream_; }
100 :
101 : private:
102 : Stream stream_;
103 : Exec executor_;
104 : };
105 :
106 : // Deduction guides
107 : template<ReadStream Stream, Executor Exec>
108 : async_read_stream(Stream, Exec) -> async_read_stream<Stream, Exec>;
109 :
110 :
111 : /** Wraps a capy WriteStream for use with Asio async operations.
112 :
113 : Adapts a capy `WriteStream` to provide Asio-style `async_write_some`
114 : operations with completion token support.
115 :
116 : @tparam Stream The underlying capy WriteStream type
117 : @tparam Exec The executor type
118 :
119 : @par Example
120 : @code
121 : capy::any_write_stream stream = ...;
122 : auto exec = capy::wrap_asio_executor(io.get_executor());
123 : capy::async_write_stream writer(std::move(stream), exec);
124 :
125 : auto [ec, n] = co_await writer.async_write_some(buffer, capy::as_io_awaitable);
126 : @endcode
127 : */
128 : template<WriteStream Stream = any_stream, Executor Exec = any_executor>
129 : struct async_write_stream
130 : {
131 : using executor_type = asio_executor_adapter<Exec>;
132 : using next_layer_type = Stream;
133 :
134 : /// Default constructor.
135 : async_write_stream() = default;
136 :
137 : /// Construct from a stream and executor.
138 1 : async_write_stream(Stream stream, Exec executor)
139 : noexcept(std::is_nothrow_move_constructible_v<Stream> &&
140 : std::is_nothrow_move_constructible_v<Exec>)
141 1 : : stream_(std::move(stream))
142 1 : , executor_(std::move(executor))
143 : {
144 1 : }
145 :
146 : async_write_stream(const async_write_stream&)
147 : noexcept(std::is_nothrow_copy_constructible_v<Stream> &&
148 : std::is_nothrow_copy_constructible_v<Exec>) = default;
149 : async_write_stream(async_write_stream&&)
150 : noexcept(std::is_nothrow_move_constructible_v<Stream> &&
151 : std::is_nothrow_move_constructible_v<Exec>) = default;
152 : async_write_stream& operator=(const async_write_stream&)
153 : noexcept(std::is_nothrow_copy_assignable_v<Stream> &&
154 : std::is_nothrow_copy_assignable_v<Exec>) = default;
155 : async_write_stream& operator=(async_write_stream&&)
156 : noexcept(std::is_nothrow_move_assignable_v<Stream> &&
157 : std::is_nothrow_move_assignable_v<Exec>) = default;
158 :
159 : /// Returns the executor adapter for Asio compatibility.
160 : executor_type get_executor() const { return executor_; }
161 :
162 : /// Initiates an async write, returning a spawn handle.
163 : template<typename Buffer>
164 : auto async_write_some(Buffer && buffer)
165 : {
166 :
167 : return asio_spawn(
168 : executor_,
169 : stream_.write_some(as_asio_buffer_sequence(std::forward<Buffer>(buffer))));
170 : }
171 :
172 : /// Initiates an async write with a completion token.
173 : template<typename Buffer, typename CompletionToken>
174 1 : auto async_write_some(Buffer && buffer, CompletionToken && token)
175 : {
176 2 : return asio_spawn(
177 : executor_,
178 1 : stream_.write_some(as_asio_buffer_sequence(std::forward<Buffer>(buffer))),
179 1 : std::forward<CompletionToken>(token));
180 : }
181 :
182 : /// Returns a reference to the underlying stream.
183 1 : next_layer_type& next_layer() { return stream_; }
184 : /// Returns a const reference to the underlying stream.
185 : const next_layer_type& next_layer() const { return stream_; }
186 :
187 : private:
188 : Stream stream_;
189 : Exec executor_;
190 : };
191 :
192 : // Deduction guides
193 : template<WriteStream Stream, Executor Exec>
194 : async_write_stream(Stream, Exec) -> async_write_stream<Stream, Exec>;
195 :
196 :
197 : /** Wraps a capy Stream for use with Asio async operations.
198 :
199 : Adapts a capy `Stream` (supporting both read and write) to provide
200 : Asio-style `async_read_some` and `async_write_some` operations
201 : with completion token support.
202 :
203 : @tparam Stream The underlying capy Stream type
204 : @tparam Exec The executor type
205 :
206 : @par Example
207 : @code
208 : capy::any_stream stream = ...;
209 : auto exec = capy::wrap_asio_executor(io.get_executor());
210 : capy::async_stream sock(std::move(stream), exec);
211 :
212 : // Read
213 : auto [ec1, n1] = co_await sock.async_read_some(read_buf, capy::as_io_awaitable);
214 :
215 : // Write
216 : auto [ec2, n2] = co_await sock.async_write_some(write_buf, capy::as_io_awaitable);
217 : @endcode
218 : */
219 : template<Stream Stream = any_stream, Executor Exec = any_executor>
220 : struct async_stream
221 : {
222 : using executor_type = asio_executor_adapter<Exec>;
223 : using next_layer_type = Stream;
224 :
225 : /// Default constructor.
226 : async_stream() = default;
227 :
228 : /// Construct from a stream and executor.
229 : async_stream(Stream stream, Exec executor)
230 : noexcept(std::is_nothrow_move_constructible_v<Stream> &&
231 : std::is_nothrow_move_constructible_v<Exec>)
232 : : stream_(std::move(stream))
233 : , executor_(std::move(executor))
234 : {
235 : }
236 :
237 : async_stream(const async_stream&)
238 : noexcept(std::is_nothrow_copy_constructible_v<Stream> &&
239 : std::is_nothrow_copy_constructible_v<Exec>) = default;
240 : async_stream(async_stream&&)
241 : noexcept(std::is_nothrow_move_constructible_v<Stream> &&
242 : std::is_nothrow_move_constructible_v<Exec>) = default;
243 : async_stream& operator=(const async_stream&)
244 : noexcept(std::is_nothrow_copy_assignable_v<Stream> &&
245 : std::is_nothrow_copy_assignable_v<Exec>) = default;
246 : async_stream& operator=(async_stream&&)
247 : noexcept(std::is_nothrow_move_assignable_v<Stream> &&
248 : std::is_nothrow_move_assignable_v<Exec>) = default;
249 :
250 : /// Returns the executor adapter for Asio compatibility.
251 : executor_type get_executor() const { return executor_; }
252 :
253 : /// Initiates an async read, returning a spawn handle.
254 : template<typename Buffer>
255 : auto async_read_some(Buffer && buffer)
256 : {
257 : return asio_spawn(
258 : executor_,
259 : stream_.read_some(as_asio_buffer_sequence(std::forward<Buffer>(buffer))));
260 : }
261 :
262 : /// Initiates an async read with a completion token.
263 : template<typename Buffer, typename CompletionToken>
264 : auto async_read_some(Buffer && buffer, CompletionToken && token)
265 : {
266 : return asio_spawn(
267 : executor_,
268 : stream_.read_some(as_asio_buffer_sequence(std::forward<Buffer>(buffer))),
269 : std::forward<CompletionToken>(token));
270 : }
271 :
272 : /// Initiates an async write, returning a spawn handle.
273 : template<typename Buffer>
274 : auto async_write_some(Buffer && buffer)
275 : {
276 : return asio_spawn(
277 : executor_,
278 : stream_.write_some(as_asio_buffer_sequence(std::forward<Buffer>(buffer))));
279 : }
280 :
281 : /// Initiates an async write with a completion token.
282 : template<typename Buffer, typename CompletionToken>
283 : auto async_write_some(Buffer && buffer, CompletionToken && token)
284 : {
285 : return asio_spawn(
286 : executor_,
287 : stream_.write_some(as_asio_buffer_sequence(std::forward<Buffer>(buffer))),
288 : std::forward<CompletionToken>(token));
289 : }
290 :
291 : /// Returns a reference to the underlying stream.
292 : next_layer_type& next_layer() { return stream_; }
293 : /// Returns a const reference to the underlying stream.
294 : const next_layer_type& next_layer() const { return stream_; }
295 :
296 : private:
297 : Stream stream_;
298 : Exec executor_;
299 : };
300 :
301 : // Deduction guides
302 : template<Stream StreamT, Executor Exec>
303 : async_stream(StreamT, Exec) -> async_stream<StreamT, Exec>;
304 :
305 : /** Wraps an Asio AsyncReadStream for use with capy's ReadStream concept.
306 :
307 : Adapts an Asio `AsyncReadStream` to provide capy-style `read_some`
308 : operations that return an IoAwaitable.
309 :
310 : @tparam AsyncReadStream The underlying Asio AsyncReadStream type
311 :
312 : @par Example
313 : @code
314 : boost::asio::ip::tcp::socket socket(io);
315 : capy::asio_read_stream reader(std::move(socket));
316 :
317 : auto result = co_await reader.read_some(buffer);
318 : @endcode
319 : */
320 : template<typename AsyncReadStream>
321 : struct asio_read_stream
322 : {
323 : using executor_type = typename AsyncReadStream::executor_type;
324 : using next_layer_type = AsyncReadStream;
325 :
326 : /// Default constructor.
327 : asio_read_stream() = default;
328 :
329 : /// Construct from an Asio stream.
330 1 : explicit asio_read_stream(AsyncReadStream stream)
331 : noexcept(std::is_nothrow_move_constructible_v<AsyncReadStream>)
332 1 : : stream_(std::move(stream))
333 : {
334 1 : }
335 :
336 : asio_read_stream(const asio_read_stream&)
337 : noexcept(std::is_nothrow_copy_constructible_v<AsyncReadStream>) = default;
338 1 : asio_read_stream(asio_read_stream&&)
339 : noexcept(std::is_nothrow_move_constructible_v<AsyncReadStream>) = default;
340 : asio_read_stream& operator=(const asio_read_stream&)
341 : noexcept(std::is_nothrow_copy_assignable_v<AsyncReadStream>) = default;
342 : asio_read_stream& operator=(asio_read_stream&&)
343 : noexcept(std::is_nothrow_move_assignable_v<AsyncReadStream>) = default;
344 :
345 : /// Returns the executor from the underlying stream.
346 : executor_type get_executor() const { return stream_.get_executor(); }
347 :
348 : /// Initiates an async read, returning an IoAwaitable.
349 : template<MutableBufferSequence Seq>
350 1 : auto read_some(Seq buffers)
351 : {
352 2 : return stream_.async_read_some(as_asio_buffer_sequence(buffers), as_io_awaitable);
353 : }
354 :
355 : /// Returns a reference to the underlying stream.
356 : next_layer_type& next_layer() { return stream_; }
357 : /// Returns a const reference to the underlying stream.
358 : const next_layer_type& next_layer() const { return stream_; }
359 :
360 : private:
361 : AsyncReadStream stream_;
362 : };
363 :
364 : // Deduction guide
365 : template<typename AsyncReadStream>
366 : asio_read_stream(AsyncReadStream) -> asio_read_stream<AsyncReadStream>;
367 :
368 :
369 : /** Wraps an Asio AsyncWriteStream for use with capy's WriteStream concept.
370 :
371 : Adapts an Asio `AsyncWriteStream` to provide capy-style `write_some`
372 : operations that return an IoAwaitable.
373 :
374 : @tparam AsyncWriteStream The underlying Asio AsyncWriteStream type
375 :
376 : @par Example
377 : @code
378 : boost::asio::ip::tcp::socket socket(io);
379 : capy::asio_write_stream writer(std::move(socket));
380 :
381 : auto result = co_await writer.write_some(buffer);
382 : @endcode
383 : */
384 : template<typename AsyncWriteStream>
385 : struct asio_write_stream
386 : {
387 : using executor_type = typename AsyncWriteStream::executor_type;
388 : using next_layer_type = AsyncWriteStream;
389 :
390 : /// Default constructor.
391 : asio_write_stream() = default;
392 :
393 : /// Construct from an Asio stream.
394 1 : explicit asio_write_stream(AsyncWriteStream stream)
395 : noexcept(std::is_nothrow_move_constructible_v<AsyncWriteStream>)
396 1 : : stream_(std::move(stream))
397 : {
398 1 : }
399 :
400 : asio_write_stream(const asio_write_stream&)
401 : noexcept(std::is_nothrow_copy_constructible_v<AsyncWriteStream>) = default;
402 1 : asio_write_stream(asio_write_stream&&)
403 : noexcept(std::is_nothrow_move_constructible_v<AsyncWriteStream>) = default;
404 : asio_write_stream& operator=(const asio_write_stream&)
405 : noexcept(std::is_nothrow_copy_assignable_v<AsyncWriteStream>) = default;
406 : asio_write_stream& operator=(asio_write_stream&&)
407 : noexcept(std::is_nothrow_move_assignable_v<AsyncWriteStream>) = default;
408 :
409 : /// Returns the executor from the underlying stream.
410 : executor_type get_executor() const { return stream_.get_executor(); }
411 :
412 : /// Initiates an async write, returning an IoAwaitable.
413 : template<ConstBufferSequence Seq>
414 1 : auto write_some(Seq buffers)
415 : {
416 2 : return stream_.async_write_some(as_asio_buffer_sequence(buffers), as_io_awaitable);
417 : }
418 :
419 : /// Returns a reference to the underlying stream.
420 : next_layer_type& next_layer() { return stream_; }
421 : /// Returns a const reference to the underlying stream.
422 : const next_layer_type& next_layer() const { return stream_; }
423 :
424 : private:
425 : AsyncWriteStream stream_;
426 : };
427 :
428 : // Deduction guide
429 : template<typename AsyncWriteStream>
430 : asio_write_stream(AsyncWriteStream) -> asio_write_stream<AsyncWriteStream>;
431 :
432 :
433 : /** Wraps an Asio AsyncStream for use with capy's Stream concept.
434 :
435 : Adapts an Asio stream (supporting both read and write) to provide
436 : capy-style `read_some` and `write_some` operations that return
437 : an IoAwaitable.
438 :
439 : @tparam AsyncStream The underlying Asio stream type
440 :
441 : @par Example
442 : @code
443 : boost::asio::ip::tcp::socket socket(io);
444 : capy::asio_stream stream(std::move(socket));
445 :
446 : // Read
447 : auto read_result = co_await stream.read_some(read_buf);
448 :
449 : // Write
450 : auto write_result = co_await stream.write_some(write_buf);
451 : @endcode
452 : */
453 : template<typename AsyncStream>
454 : struct asio_stream
455 : {
456 : using executor_type = typename AsyncStream::executor_type;
457 : using next_layer_type = AsyncStream;
458 :
459 : /// Default constructor.
460 : asio_stream() = default;
461 :
462 : /// Construct from an Asio stream.
463 : explicit asio_stream(AsyncStream stream)
464 : noexcept(std::is_nothrow_move_constructible_v<AsyncStream>)
465 : : stream_(std::move(stream))
466 : {
467 : }
468 :
469 : asio_stream(const asio_stream&)
470 : noexcept(std::is_nothrow_copy_constructible_v<AsyncStream>) = default;
471 : asio_stream(asio_stream&&)
472 : noexcept(std::is_nothrow_move_constructible_v<AsyncStream>) = default;
473 : asio_stream& operator=(const asio_stream&)
474 : noexcept(std::is_nothrow_copy_assignable_v<AsyncStream>) = default;
475 : asio_stream& operator=(asio_stream&&)
476 : noexcept(std::is_nothrow_move_assignable_v<AsyncStream>) = default;
477 :
478 : /// Returns the executor from the underlying stream.
479 : executor_type get_executor() const { return stream_.get_executor(); }
480 :
481 : /// Initiates an async read, returning an IoAwaitable.
482 : template<MutableBufferSequence Seq>
483 : auto read_some(Seq buffers)
484 : {
485 : return stream_.async_read_some(as_asio_buffer_sequence(buffers), as_io_awaitable);
486 : }
487 :
488 : /// Initiates an async write, returning an IoAwaitable.
489 : template<ConstBufferSequence Seq>
490 : auto write_some(Seq buffers)
491 : {
492 : return stream_.async_write_some(as_asio_buffer_sequence(buffers), as_io_awaitable);
493 : }
494 :
495 : /// Returns a reference to the underlying stream.
496 : next_layer_type& next_layer() { return stream_; }
497 : /// Returns a const reference to the underlying stream.
498 : const next_layer_type& next_layer() const { return stream_; }
499 :
500 : private:
501 : AsyncStream stream_;
502 : };
503 :
504 : // Deduction guide
505 : template<typename AsyncStream>
506 : asio_stream(AsyncStream) -> asio_stream<AsyncStream>;
507 :
508 : }
509 :
510 : #endif //BOOST_CAPY_ASIO_STREAM_HPP
511 :
|