Physical Isolation
This section explains how type-erased wrappers enable compilation firewalls and transport-independent APIs.
Prerequisites
-
Completed Transfer Algorithms
-
Understanding of type-erased wrappers
The Compilation Firewall Pattern
C++ templates are powerful but have a cost: every instantiation compiles in every translation unit that uses it. Change a template, and everything that includes it recompiles.
Type-erased wrappers break this dependency:
// protocol.hpp - No template dependencies
#pragma once
#include <boost/capy/io/any_stream.hpp>
#include <boost/capy/task.hpp>
// Declaration only - no implementation details
task<> handle_protocol(any_stream& stream);
// protocol.cpp - Implementation isolated here
#include "protocol.hpp"
#include <boost/capy/read.hpp>
#include <boost/capy/write.hpp>
task<> handle_protocol(any_stream& stream)
{
char buf[1024];
for (;;)
{
auto [ec, n] = co_await stream.read_some(mutable_buffer(buf));
if (ec.failed())
co_return;
// Process and respond...
co_await write(stream, make_buffer(response));
}
}
Changes to protocol.cpp only recompile that file. The header is stable.
Build Time Benefits
Before (Templates Everywhere)
// Old approach: template propagates everywhere
template<typename Stream>
task<> handle_protocol(Stream& stream);
// Every caller instantiates for their stream type
// Changes force recompilation of all callers
Transport Independence
Type erasure decouples your code from specific transport implementations:
// Your library code
task<> send_message(any_write_sink& sink, message const& msg)
{
co_await sink.write(make_buffer(msg.header));
co_await sink.write(make_buffer(msg.body), true);
}
Callers provide any conforming implementation:
// TCP socket
tcp::socket socket;
any_write_sink sink{socket};
send_message(sink, msg);
// TLS stream
tls::stream stream;
any_write_sink sink{stream};
send_message(sink, msg);
// HTTP chunked encoding
chunked_sink chunked{underlying};
any_write_sink sink{chunked};
send_message(sink, msg);
// Test mock
test::write_sink mock;
any_write_sink sink{mock};
send_message(sink, msg);
Same send_message function, different transports—compile once, use everywhere.
API Design Guidelines
Accept Type-Erased References
// Good: accepts any stream
task<> process(any_stream& stream);
// Avoid: forces specific type
task<> process(tcp::socket& socket);
Example: Library API
// http_client.hpp
#pragma once
#include <boost/capy/io/any_read_source.hpp>
#include <boost/capy/io/any_write_sink.hpp>
struct http_request
{
std::string method;
std::string url;
std::map<std::string, std::string> headers;
};
struct http_response
{
int status_code;
std::map<std::string, std::string> headers;
any_read_source body; // Body is a source, not a buffer
};
// Send request, receive response
// Works with any transport that provides any_stream
task<http_response> send_request(any_stream& conn, http_request const& req);
Users don’t need to know how HTTP is implemented:
// User code
tcp::socket socket;
// ... connect ...
any_stream conn{socket};
auto response = co_await send_request(conn, {
.method = "GET",
.url = "/api/data"
});
// Read body through type-erased source
flat_dynamic_buffer buf;
co_await read(response.body, buf);
The HTTP library is isolated from transport details. It compiles once. Users bring their own transport.
Wrapper Overhead
Type erasure has runtime cost:
-
Virtual dispatch for each operation
-
Extra indirection through wrapper
But the cost is typically negligible compared to I/O latency. A nanosecond of dispatch overhead is invisible next to microsecond network operations.
When profiling shows wrapper overhead matters:
-
Consider batching operations
-
Use concrete types in hot paths
-
Accept the template cost for that code path
Reference
Type-erased wrappers are in <boost/capy/io/>:
-
any_stream -
any_read_stream,any_write_stream -
any_read_source,any_write_sink -
any_buffer_source,any_buffer_sink
You have now completed the Stream Concepts section. These abstractions—streams, sources, sinks, and their type-erased wrappers—form the foundation for Capy’s I/O model. Continue to Example Programs to see complete working examples.