100.00% Lines (30/30)
100.00% Functions (12/12)
| TLA | Baseline | Branch | ||||||
|---|---|---|---|---|---|---|---|---|
| Line | Hits | Code | Line | Hits | 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. | ||||||
| HITGNC | 53 | + | 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>) | ||||||
| HITGNC | 56 | + | 1 | : stream_(std::move(stream)) | ||||
| HITGNC | 57 | + | 1 | , executor_(std::move(executor)) | ||||
| 58 | + | { | ||||||
| HITGNC | 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> | ||||||
| HITGNC | 88 | + | 2 | auto async_read_some(Buffer && buffer, CompletionToken && token) | ||||
| 89 | + | { | ||||||
| HITGNC | 90 | + | 4 | return asio_spawn( | ||||
| 91 | + | executor_, | ||||||
| HITGNC | 92 | + | 2 | stream_.read_some(as_asio_buffer_sequence(std::forward<Buffer>(buffer))), | ||||
| HITGNC | 93 | + | 2 | std::forward<CompletionToken>(token)); | ||||
| 94 | + | } | ||||||
| 95 | + | |||||||
| 96 | + | /// Returns a reference inter to the underlying stream. | ||||||
| HITGNC | 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. | ||||||
| HITGNC | 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>) | ||||||
| HITGNC | 141 | + | 1 | : stream_(std::move(stream)) | ||||
| HITGNC | 142 | + | 1 | , executor_(std::move(executor)) | ||||
| 143 | + | { | ||||||
| HITGNC | 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> | ||||||
| HITGNC | 174 | + | 1 | auto async_write_some(Buffer && buffer, CompletionToken && token) | ||||
| 175 | + | { | ||||||
| HITGNC | 176 | + | 2 | return asio_spawn( | ||||
| 177 | + | executor_, | ||||||
| HITGNC | 178 | + | 1 | stream_.write_some(as_asio_buffer_sequence(std::forward<Buffer>(buffer))), | ||||
| HITGNC | 179 | + | 1 | std::forward<CompletionToken>(token)); | ||||
| 180 | + | } | ||||||
| 181 | + | |||||||
| 182 | + | /// Returns a reference to the underlying stream. | ||||||
| HITGNC | 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. | ||||||
| HITGNC | 330 | + | 1 | explicit asio_read_stream(AsyncReadStream stream) | ||||
| 331 | + | noexcept(std::is_nothrow_move_constructible_v<AsyncReadStream>) | ||||||
| HITGNC | 332 | + | 1 | : stream_(std::move(stream)) | ||||
| 333 | + | { | ||||||
| HITGNC | 334 | + | 1 | } | ||||
| 335 | + | |||||||
| 336 | + | asio_read_stream(const asio_read_stream&) | ||||||
| 337 | + | noexcept(std::is_nothrow_copy_constructible_v<AsyncReadStream>) = default; | ||||||
| HITGNC | 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> | ||||||
| HITGNC | 350 | + | 1 | auto read_some(Seq buffers) | ||||
| 351 | + | { | ||||||
| HITGNC | 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. | ||||||
| HITGNC | 394 | + | 1 | explicit asio_write_stream(AsyncWriteStream stream) | ||||
| 395 | + | noexcept(std::is_nothrow_move_constructible_v<AsyncWriteStream>) | ||||||
| HITGNC | 396 | + | 1 | : stream_(std::move(stream)) | ||||
| 397 | + | { | ||||||
| HITGNC | 398 | + | 1 | } | ||||
| 399 | + | |||||||
| 400 | + | asio_write_stream(const asio_write_stream&) | ||||||
| 401 | + | noexcept(std::is_nothrow_copy_constructible_v<AsyncWriteStream>) = default; | ||||||
| HITGNC | 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> | ||||||
| HITGNC | 414 | + | 1 | auto write_some(Seq buffers) | ||||
| 415 | + | { | ||||||
| HITGNC | 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 | + | |||||||