Split

Introduction

xpp::io::split(stream) splits any type satisfying both AsyncReader and AsyncWriter into independent ReadHalf<T> and WriteHalf<T>. Like tokio's io::split() — the two halves share the underlying stream via Arc<T> (atomic refcount).

Example — .await()

#include <xpp/io/split.h>

xpp::EventLoop loop;
xpp::WaitScope scope(loop);

auto [reader, writer] = xpp::io::split(std::move(stream));

// Concurrent read + write on the same connection
xpp::all(reader.read(buf, 10), writer.write("hi", 2)).await();

Example — co_await (C++20)

auto [reader, writer] = xpp::io::split(std::move(stream));
auto [n, _] = co_await xpp::all(reader.read(buf, 10), writer.write("hi", 2));

How it works

io::split(stream)
    └── Arc<T>::make(std::move(stream))
        ├── ReadHalf<T> { Arc<T> m_inner }  → read(buf, len)
        └── WriteHalf<T> { Arc<T> m_inner } → write(buf, len), flush()

Both halves hold a copy of the Arc<T> refcount.
The underlying stream is destroyed when the last half drops.

API Reference

MethodReturnsDescription
split(stream)pair<ReadHalf<T>, WriteHalf<T>>Split into independent read/write halves

Usage Examples

Split TcpStream — .await()

xpp::EventLoop loop;
xpp::WaitScope scope(loop);

auto [reader, writer] = xpp::io::split(std::move(conn));
char buf[16];

// Read first
ssize_t n = reader.read(buf, sizeof(buf)).await();

// Then echo back
writer.write(buf, static_cast<size_t>(n)).await();

Split TcpStream — co_await (C++20)

xpp::Promise<void> echo(xpp::net::TcpStream conn) {
    auto [reader, writer] = xpp::io::split(std::move(conn));
    char buf[16];
    ssize_t n = co_await reader.read(buf, sizeof(buf));
    co_await writer.write(buf, static_cast<size_t>(n));
}