Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .cursor/rules/doc-awaitable.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ alwaysApply: false
- **`@return`** — Describe the returned aggregate and its elements. The first element is always `error_code`. Name and describe each subsequent element (e.g. "bytes_transferred", "endpoint"). Note that the result is customarily destructured by the caller.
- **Error conditions** — Document the notable `error_code` values or conditions that may appear in the first element. E.g. `capy::cond::canceled` if the stop token was activated or the i/o object's `cancel()` was called, EOF conditions, protocol-specific errors, etc. State that error codes should be compared to error conditions, not specific values.
- **`@throws`** — Typically only for precondition violations. State which preconditions trigger exceptions, or state that no exceptions are thrown during normal operation.
- **Cancellation** — State that the operation supports cancellation via `stop_token` propagated through the IoAwaitable protocol, or via the i/o object's `cancel()` member. State that the resulting error compares equal to `capy::cond::canceled`.
- **Cancellation** — State that the operation supports cancellation via `stop_token` propagated through the ContextAwaitable protocol, or via the i/o object's `cancel()` member. State that the resulting error compares equal to `capy::cond::canceled`.
- **`@par Example`** — Two or three `@code` blocks showing different usage patterns: typical happy path with destructuring, error handling, cancellation, different overloads, etc.
- **`@note` / `@par Remarks`** — Behavioral gotchas. E.g. "This operation may not read all of the requested bytes." Or equivalence to another overload.
- **`@tparam`** — For non-variadic template parameters. State the concept requirement (e.g. "The type must satisfy the *AsyncStream* concept"). Don't document `Args...`.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

# Boost.Corosio

Boost.Corosio is a coroutine-only I/O library for C++20 that provides asynchronous networking primitives with automatic executor affinity propagation. Every operation returns an awaitable that integrates with the _IoAwaitable_ protocol, ensuring your coroutines resume on the correct executor without manual dispatch.
Boost.Corosio is a coroutine-only I/O library for C++20 that provides asynchronous networking primitives with automatic executor affinity propagation. Every operation returns an awaitable that integrates with the _ContextAwaitable_ protocol, ensuring your coroutines resume on the correct executor without manual dispatch.

## Quick Start

Expand Down
2 changes: 1 addition & 1 deletion doc/.vale/styles/Corosio/Terminology.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# `launch`/`spawn`-bearing identifier in the library and the pages is either
# snake_case (`launch_one`, `launch_all`, `spawn_work`, `co_spawn`,
# `launch_policies`, the snippet tag `4b_launching`) or a `launcher` compound
# (`when_any_io_launcher`, `launchable`, `relaunch`, `launchers`). `_` is a word
# (`when_any_results_launcher`, `launchable`, `relaunch`, `launchers`). `_` is a word
# character, so the `\b` after the stem already excludes the snake_case forms,
# and the inflection list below is deliberately limited to VERB endings so it
# cannot reach `launcher`. On top of that, `.vale.ini`'s `TokenIgnores` blanks
Expand Down
4 changes: 2 additions & 2 deletions doc/.vale/styles/config/vocabularies/Corosio/accept.txt
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@
# --- C++ terms used adjectivally or nominally in running prose ------------------
#
# Language keywords belong here, and several already did (const, nullptr, nothrow,
# enum, bool). The line against bare identifiers below is about SYMBOLS: `io_result`
# enum, bool). The line against bare identifiers below is about SYMBOLS: `results`
# has a generated reference page, so leaving it unlinked in prose is a real missed
# `cpp:` link (style guide B1). A keyword has no page and nothing to link to, so B1
# offers no remedy and the alert can never be actioned -- it is noise, not a signal.
Expand Down Expand Up @@ -252,7 +252,7 @@
# reference page ever appears for one, delete its line here and link it instead.
(?i)mockets?
(?i)socket_pair
(?i)io_result
(?i)results
(?i)const_buffer
(?i)mutable_buffer
(?i)buffer_slice
Expand Down
2 changes: 1 addition & 1 deletion doc/STYLE_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ as vocabulary is added — extend it rather than letting synonyms drift.)*
| callback passed to `run_async` | **completion handler** | handler (bare), callback |
| a `task<T>` value | **task** | coroutine (the language feature), coro |
| the C++20 language feature | **coroutine** | coro, async function |
| awaitable satisfying `IoAwaitable` | **I/O awaitable** | awaitable (bare, when the concept is meant) |
| awaitable satisfying `ContextAwaitable` | **I/O awaitable** | awaitable (bare, when the concept is meant) |
| object that listens for inbound connections | **acceptor** | listener, server socket, listening socket |
| an address plus a port | **endpoint** | address (when the port is included), socket address |
| the machine at the other end of a connection | **peer** | remote, other side, partner |
Expand Down
6 changes: 3 additions & 3 deletions doc/design/physical-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ private:

auto await_suspend(
std::coroutine_handle<> h,
capy::io_env const* env ) -> std::coroutine_handle<>
capy::await_context const* env ) -> std::coroutine_handle<>
{
// Virtual dispatch through implementation - type-erased
return self_.get().read_some( h, env->executor,
Expand Down Expand Up @@ -229,7 +229,7 @@ private:

auto await_suspend(
std::coroutine_handle<> h,
capy::io_env const* env ) -> std::coroutine_handle<>
capy::await_context const* env ) -> std::coroutine_handle<>
{
// Virtual dispatch through concrete implementation
return self_.get().connect( h, env->executor,
Expand Down Expand Up @@ -375,7 +375,7 @@ private:

auto await_suspend(
std::coroutine_handle<> h,
capy::io_env const* env ) -> std::coroutine_handle<>
capy::await_context const* env ) -> std::coroutine_handle<>
{
// Direct call to backend impl - no vtable, inlinable
return self_.get_impl().read_some( h, env->executor,
Expand Down
10 changes: 5 additions & 5 deletions doc/error-handling-rulebook.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@ by classifying its failures:
| Situation | Shape |
|---|---|
| Sync, no payload | `[[nodiscard]] std::error_code f(...) noexcept` |
| Sync, with payload | `[[nodiscard]] capy::io_result<T> f(...) noexcept` |
| Async | the awaitable completes with `io_result<...>` — initiators never throw |
| Sync, with payload | `[[nodiscard]] capy::results<T> f(...) noexcept` |
| Async | the awaitable completes with `results<...>` — initiators never throw |

`io_result<T>` is `std::tuple<std::error_code, T...>`, so results
`results<T>` is `std::tuple<std::error_code, T...>`, so results
destructure; the sync and async surfaces share one idiom:

```cpp
Expand All @@ -58,7 +58,7 @@ auto [ec2, ep] = make_endpoint("10.0.0.1:80"); // factory
```

The payload always rides in the return — the `make_*` factories
return `io_result<T>` with a default-constructed payload on failure.
return `results<T>` with a default-constructed payload on failure.
Every awaitable-returning initiator is `[[nodiscard]]`: a discarded
awaitable is a silent no-op that also drops any pre-set completion.

Expand Down Expand Up @@ -99,7 +99,7 @@ they own, race-free, before the call?**

Corollary: an operation with no realistic failure on a valid open
object (`size()`, `release()`, `available()`) stays on the throwing
channel — an `io_result` return would tax every correct call site to
channel — a `results` return would tax every correct call site to
carry a bit that is always "you have a bug".

## 4. The Closed-Object Condition
Expand Down
4 changes: 2 additions & 2 deletions doc/lint/extract-docstrings.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@
// BOTH Doxygen doc-comment forms are extracted: `/** ... */` blocks and runs of
// consecutive `///` lines. A run of `///` lines is ONE doc comment attached to
// the declaration that follows it, which is how Doxygen and MrDocs read it, and
// MrDocs really does publish that prose — `io_result.hpp:49`'s
// MrDocs really does publish that prose — `results.hpp:49`'s
// `/// The error code from the operation.` renders on both
// `reference/boost/corosio/io_result.html` and `reference/boost/corosio/io_result/ec.html`.
// `reference/boost/corosio/results.html` and `reference/boost/corosio/results/ec.html`.
// Until 2026-08 only the `/** */` form was extracted, so 86 published doc lines
// across 25 headers were invisible to every Vale rule and to the C2 checker,
// including the four the Phase-4 exit promoted to merge-blocking gates. It was
Expand Down
2 changes: 1 addition & 1 deletion doc/modules/ROOT/pages/4.guide/4d.sockets.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ The `connect()` operation initiates a TCP connection:
include::example$snippets/4d_sockets.cpp[tag=connect,indent=0]
----

This returns an `io_result<>` that you can unpack with structured bindings.
This returns a `results<>` that you can unpack with structured bindings.

=== Connection Errors

Expand Down
6 changes: 3 additions & 3 deletions doc/modules/ROOT/pages/4.guide/4h.timers.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,13 @@ Whichever finishes first decides the outcome:
include::example$snippets/4h_timers.cpp[tag=timeout_read,indent=0]
----

If the inner operation wins, its `io_result` is returned unchanged,
If the inner operation wins, its `results` is returned unchanged,
error or success, payload and all. If the deadline wins, the inner
operation is cancelled and `timeout()` produces its own result. `ec` is
`capy::cond::timeout`, and any payload such as a byte count is
default-initialized. It is not whatever the cancelled operation happened
to leave behind. Because the deadline-win path default-initializes
that payload, the inner operation's `io_result` payload type must be
that payload, the inner operation's `results` payload type must be
default constructible.

`timeout()` also accepts an absolute deadline:
Expand Down Expand Up @@ -157,7 +157,7 @@ requested delay would be worse than a hard failure.

== Composing with Other Operations

Because `timeout()` takes any awaitable that yields an `io_result`,
Because `timeout()` takes any awaitable that yields a `results`,
it composes with anything Corosio returns, not just socket reads. A
connect-with-retry loop pairs `timeout()` for the per-attempt deadline
with `delay()` for the pause between attempts:
Expand Down
12 changes: 6 additions & 6 deletions doc/modules/ROOT/pages/4.guide/4m.error-handling.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
= Error Handling
:page-mode: how-to

Corosio reports I/O errors through the `io_result` type, which carries an
Corosio reports I/O errors through the `results` type, which carries an
error code alongside any values produced by the operation.

[#one-channel]
Expand All @@ -20,9 +20,9 @@ error code alongside any values produced by the operation.
Every fallible operation reports through exactly one channel:

* *Expected runtime conditions return the error.* Synchronous
operations return `std::error_code` (or `io_result<T>` when a
operations return `std::error_code` (or `results<T>` when a
payload rides along — `seek()`, the `make_*` factories), and
asynchronous operations complete with `io_result<...>`. Every
asynchronous operations complete with `results<...>`. Every
error-returning function is `+[[nodiscard]]+`.
* *Misuse of a documented precondition throws* `std::system_error` —
for example `release()`, `set_option()`, or `get_option()` on a
Expand Down Expand Up @@ -104,9 +104,9 @@ include::example$snippets/4m_error_handling.cpp[tag=assume]
----
====

== The io_result Type
== The `results` Type

`io_result<Ts...>` is an alias for `std::tuple<std::error_code, Ts...>`:
`results<Ts...>` is an alias for `std::tuple<std::error_code, Ts...>`:
the error code always comes first, followed by any values the operation
produced. Because it is a `std::tuple`, results interoperate with the
whole tuple API — structured bindings, `std::tie`, `std::get`,
Expand Down Expand Up @@ -145,7 +145,7 @@ value for you.

== Throwing on Error

`io_result` never throws on its own. To turn an error into an exception,
`results` never throws on its own. To turn an error into an exception,
test `ec` and throw explicitly:

[source,cpp]
Expand Down
2 changes: 1 addition & 1 deletion doc/modules/ROOT/pages/4.guide/4q.udp.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -298,4 +298,4 @@ cost in the kernel, so a server can run several receivers in parallel.
protocol-level background
* xref:4.guide/4d.sockets.adoc[Sockets] — generic socket options and lifetime rules
* xref:4.guide/4f.endpoints.adoc[Endpoints] — IP address and port construction
* xref:4.guide/4m.error-handling.adoc[Error Handling] — the `io_result` pattern
* xref:4.guide/4m.error-handling.adoc[Error Handling] — the `results` pattern
2 changes: 1 addition & 1 deletion doc/modules/ROOT/pages/4.guide/4r.wait.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ include::example$snippets/4r_wait.cpp[tag=wait_cancel,indent=0]

cpp:timeout[] composes with `wait()` the
same way it does with the other socket operations, since `wait()`
yields an `io_result` like any other awaitable:
yields a `results` like any other awaitable:

[source,cpp]
----
Expand Down
2 changes: 1 addition & 1 deletion doc/modules/ROOT/pages/4.guide/4t.lifetime.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ Check each of these:
still held by the caller after a `post` that threw. Never two of these, and
never none.
. *The environment outlives the work it is lent to.* An inner task or
awaitable may use an `io_env`, stop source or stop token held in another
awaitable may use an `await_context`, stop source or stop token held in another
member. Declare that member first, so it is destroyed after the work.
. *End an operation before what it references.* A wrapper that caches an inner
operation ends it before destroying or replacing the object the operation
Expand Down
4 changes: 2 additions & 2 deletions doc/modules/ROOT/pages/glossary.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ An I/O object that listens for and accepts incoming connections. See
cpp:tcp_acceptor[] and xref:4.guide/4e.tcp-acceptor.adoc[Acceptors Guide].

Affine Awaitable:: An awaitable type that implements the affine protocol.
It receives an `io_env const*` in `await_suspend`, carrying the executor,
It receives an `await_context const*` in `await_suspend`, carrying the executor,
stop token, and frame allocator, to ensure correct executor affinity.

Affinity::
Expand Down Expand Up @@ -135,7 +135,7 @@ I/O Stream::
An I/O object that supports reading and writing data. Base class is
`corosio::io_stream`.

io_result::
results::
The result type for Corosio operations, containing an error code and optional
values. Supports structured bindings.

Expand Down
4 changes: 2 additions & 2 deletions doc/modules/ROOT/pages/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ asynchronous networking primitives with automatic executor affinity propagation.

Corosio provides asynchronous I/O operations designed from the ground up for
C++20 coroutines. Every operation returns an awaitable that integrates with
the _IoAwaitable_ protocol, ensuring your coroutines resume on the correct
the _ContextAwaitable_ protocol, ensuring your coroutines resume on the correct
executor without manual dispatch.

* cpp:io_context[] — Event loop for processing asynchronous operations
Expand Down Expand Up @@ -54,7 +54,7 @@ callback-based interfaces.
parameters, not through thread-local storage. When an I/O operation completes,
it resumes your coroutine through the executor you provided.

**Structured bindings.** Results use `io_result<T>` which supports structured
**Structured bindings.** Results use `results<T>` which supports structured
bindings: `auto [ec, n] = co_await s.read_some(buf)`. See
xref:4.guide/4m.error-handling.adoc[Error Handling] for how to handle the
error code.
Expand Down
12 changes: 6 additions & 6 deletions doc/scheduler.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Asio and Corosio take fundamentally different approaches to coroutine management
| Aspect | Asio | Corosio |
|--------|------|---------|
| Symmetric transfer | Simulated via `pump()` loop | Native language mechanism |
| Type system | Closed (`asio::awaitable` only) | Open (`IoAwaitable` concept) |
| Type system | Closed (`asio::awaitable` only) | Open (`ContextAwaitable` concept) |
| `await_suspend` return | `void` | `coroutine_handle` |
| I/O initiation timing | `after_suspend_fn_` callback | TBD |

Expand Down Expand Up @@ -62,7 +62,7 @@ Corosio's `task<T>` returns `coroutine_handle` from `await_suspend`, enabling co

```cpp
// task<T>::await_suspend - returns coroutine_handle
std::coroutine_handle<> await_suspend(std::coroutine_handle<> cont, io_env const* env)
std::coroutine_handle<> await_suspend(std::coroutine_handle<> cont, await_context const* env)
{
h_.promise().set_continuation(cont, env->executor);
h_.promise().set_environment(env);
Expand Down Expand Up @@ -104,14 +104,14 @@ This creates a closed type system where only `asio::awaitable<T>` coroutines can

### Corosio's Open System

Corosio uses the `IoAwaitable` concept, allowing any conforming type to participate:
Corosio uses the `ContextAwaitable` concept, allowing any conforming type to participate:

```cpp
template<class Awaitable>
auto transform_awaitable(Awaitable&& a)
{
using A = std::decay_t<Awaitable>;
if constexpr (IoAwaitable<A>)
if constexpr (ContextAwaitable<A>)
{
return transform_awaiter<Awaitable>{
std::forward<Awaitable>(a), this};
Expand All @@ -123,10 +123,10 @@ auto transform_awaitable(Awaitable&& a)
The `await_suspend` signature accepts the execution environment:

```cpp
std::coroutine_handle<> await_suspend(std::coroutine_handle<> cont, io_env const* env)
std::coroutine_handle<> await_suspend(std::coroutine_handle<> cont, await_context const* env)
```

This design allows third-party awaitable types to integrate with Corosio's I/O system by satisfying the `IoAwaitable` concept.
This design allows third-party awaitable types to integrate with Corosio's I/O system by satisfying the `ContextAwaitable` concept.

## I/O Initiation Timing

Expand Down
Loading
Loading