Streams (Partial I/O)
This section explains the ReadStream and WriteStream concepts for partial I/O operations.
Prerequisites
-
Completed Stream Concepts Overview
-
Understanding of the six stream concept categories
ReadStream
A type satisfies ReadStream if it provides partial read operations via read_some:
template<typename T>
concept ReadStream =
requires(T& stream, mutable_buffer_archetype buffers) {
{ stream.read_some(buffers) } -> IoAwaitable;
};
read_some Semantics
template<MutableBufferSequence MB>
IoAwaitable auto read_some(MB const& buffers);
Returns an awaitable yielding (error_code, std::size_t):
-
On success:
!ec.failed(), andn >= 1bytes were read -
On error:
ec.failed(), andn == 0 -
On EOF:
ec == cond::eof, andn == 0
If buffer_empty(buffers) is true, completes immediately with n == 0 and no error.
Partial Transfer
read_some may return fewer bytes than the buffer can hold:
char buf[1024];
auto [ec, n] = co_await stream.read_some(mutable_buffer(buf));
// n might be 1, might be 500, might be 1024
// The only guarantee: if !ec.failed() && n > 0
This matches underlying OS behavior—reads return when some data is available.
WriteStream
A type satisfies WriteStream if it provides partial write operations via write_some:
template<typename T>
concept WriteStream =
requires(T& stream, const_buffer_archetype buffers) {
{ stream.write_some(buffers) } -> IoAwaitable;
};
write_some Semantics
template<ConstBufferSequence CB>
IoAwaitable auto write_some(CB const& buffers);
Returns an awaitable yielding (error_code, std::size_t):
-
On success:
!ec.failed(), andn >= 1bytes were written -
On error:
ec.failed(), andnindicates bytes written before error (may be 0)
If buffer_empty(buffers) is true, completes immediately with n == 0 and no error.
Type-Erasing Wrappers
any_read_stream
Wraps any ReadStream in a type-erased container:
#include <boost/capy/io/any_read_stream.hpp>
template<ReadStream S>
any_read_stream(S& stream);
The wrapped stream is referenced—the original must outlive the wrapper.
any_write_stream
Wraps any WriteStream:
#include <boost/capy/io/any_write_stream.hpp>
template<WriteStream S>
any_write_stream(S& stream);
any_stream
Wraps bidirectional streams (both ReadStream and WriteStream):
#include <boost/capy/io/any_stream.hpp>
template<ReadStream S>
requires WriteStream<S>
any_stream(S& stream);
Wrapper Characteristics
All wrappers share these properties:
-
Reference semantics — Wrap existing objects without ownership
-
Preallocated coroutine frame — Zero steady-state allocation
-
Move-only — Non-copyable; moving transfers the cached frame
-
Lifetime requirement — Wrapped object must outlive wrapper
Example usage:
void process_stream(any_stream& stream);
tcp::socket socket;
// ... connect socket ...
any_stream wrapped{socket}; // Type erasure here
process_stream(wrapped); // process_stream doesn't know about tcp::socket
Example: Echo Server with any_stream
// echo.hpp - Header only declares the signature
task<> handle_connection(any_stream& stream);
// echo.cpp - Implementation in separate translation unit
task<> handle_connection(any_stream& stream)
{
char buf[1024];
for (;;)
{
// Read some data
auto [ec, n] = co_await stream.read_some(mutable_buffer(buf));
if (ec == cond::eof)
co_return; // Client closed connection
if (ec.failed())
throw std::system_error(ec);
// Echo it back
auto [wec, wn] = co_await write(stream, const_buffer(buf, n));
if (wec.failed())
throw std::system_error(wec);
}
}
The implementation doesn’t know the concrete stream type. It compiles once and works with any transport.
Reference
| Header | Description |
|---|---|
|
ReadStream concept definition |
|
WriteStream concept definition |
|
Type-erased read stream wrapper |
|
Type-erased write stream wrapper |
|
Type-erased bidirectional stream wrapper |
You have now learned the stream concepts for partial I/O. Continue to Sources and Sinks to learn about complete I/O with EOF signaling.