Skip to content

feat: make IoAwaitables composable as std::execution senders#371

Merged
sgerbino merged 1 commit into
cppalliance:developfrom
sgerbino:pr/awaitable-sender
Jul 23, 2026
Merged

feat: make IoAwaitables composable as std::execution senders#371
sgerbino merged 1 commit into
cppalliance:developfrom
sgerbino:pr/awaitable-sender

Conversation

@sgerbino

Copy link
Copy Markdown
Collaborator

Extend the awaitable-sender example so capy I/O awaitables participate in C++26 sender pipelines, written against std::execution names only (a bundled pre-standard implementation fills in through a single alias until standard libraries ship __cpp_lib_senders; every accommodation for it is marked DROP AT GRADUATION):

  • as_sender accepts compound io_result awaitables, splitting (ec, vs...) into set_error(ec) and set_value(vs...) channels; the task<error_code> workaround is gone. Splitting keys on io_result itself: only the type that declares element-0-is-outcome intent is split, and a generic tuple-like leading with error_code is a value.
  • completion channels are chosen by the operation's own disposition: an error comparing equal to errc::operation_canceled completes with set_stopped(), other errors with set_error(ec), and a successful result is delivered even when a stop request landed while the operation was finishing; the success path pays a bool test, not the category-virtual condition comparison
  • completion signatures are deduced from await_resume() at the query, where the CRTP Derived type is complete, via the C++26 static member function template mechanism ([exec.getcomplsigs]); nothing is stated twice and the advertisement cannot drift from the implementation
  • awaitable_sender_base makes an op a sender natively; both protocols drive the identical awaitable members, and the documented dual-protocol contract (disposition reported in-band) makes the co_await and connect/start views provably consistent, pinned by cross-protocol tests
  • the AwaitableSender concept refines IoAwaitable with the sender requirements; both halves are structural, deriving the base is one way to satisfy it, and ensure_sender normalizes any IoAwaitable at a pipeline boundary (dual-protocol ops pass through, awaitable-only ops are lifted with as_sender)
  • shared op_state machinery drives the IoAwaitable protocol for both front-ends: receiver stop tokens of any stoppable_token type bridge into io_env's std::stop_token, get_io_executor is a forwarding query, and environments providing only a scheduler are served through an op_state-owned bridge, so bare sync_wait consumes capy ops end-to-end; a pmr::polymorphic_allocator in the environment lends its memory_resource as the frame allocator
  • ops keep data members private, the durable opt-out from sender decomposition (tag_of_t claims any type whose members admit a structured binding); read_op models the compliant shape and its stop-wait mode composes async_waker instead of hand-rolling stop-callback arming
  • example split into demo and test targets; 32 tests cover every completion channel through the adaptor, the native form, generic consumers, and both protocols; stop-dependent tests fail fast on timeout instead of hanging

Extend the awaitable-sender example so capy I/O awaitables participate
in C++26 sender pipelines, written against std::execution names only
(a bundled pre-standard implementation fills in through a single alias
until standard libraries ship __cpp_lib_senders; every accommodation
for it is marked DROP AT GRADUATION):

- as_sender accepts compound io_result awaitables, splitting (ec, vs...)
  into set_error(ec) and set_value(vs...) channels; the task<error_code>
  workaround is gone. Splitting keys on io_result itself: only the type
  that declares element-0-is-outcome intent is split, and a generic
  tuple-like leading with error_code is a value.
- completion channels are chosen by the operation's own disposition:
  an error comparing equal to errc::operation_canceled completes with
  set_stopped(), other errors with set_error(ec), and a successful
  result is delivered even when a stop request landed while the
  operation was finishing; the success path pays a bool test, not the
  category-virtual condition comparison
- completion signatures are deduced from await_resume() at the query,
  where the CRTP Derived type is complete, via the C++26 static member
  function template mechanism ([exec.getcomplsigs]); nothing is stated
  twice and the advertisement cannot drift from the implementation
- awaitable_sender_base<Derived> makes an op a sender natively; both
  protocols drive the identical awaitable members, and the documented
  dual-protocol contract (disposition reported in-band) makes the
  co_await and connect/start views provably consistent, pinned by
  cross-protocol tests
- the AwaitableSender concept refines IoAwaitable with the sender
  requirements; both halves are structural, deriving the base is one
  way to satisfy it, and ensure_sender normalizes any IoAwaitable at
  a pipeline boundary (dual-protocol ops pass through, awaitable-only
  ops are lifted with as_sender)
- shared op_state machinery drives the IoAwaitable protocol for both
  front-ends: receiver stop tokens of any stoppable_token type bridge
  into io_env's std::stop_token, get_io_executor is a forwarding
  query, and environments providing only a scheduler are served
  through an op_state-owned bridge, so bare sync_wait consumes capy
  ops end-to-end; a pmr::polymorphic_allocator in the environment
  lends its memory_resource as the frame allocator
- ops keep data members private, the durable opt-out from sender
  decomposition (tag_of_t claims any type whose members admit a
  structured binding); read_op models the compliant shape and its
  stop-wait mode composes async_waker instead of hand-rolling
  stop-callback arming
- example split into demo and test targets; 32 tests cover every
  completion channel through the adaptor, the native form, generic
  consumers, and both protocols; stop-dependent tests fail fast on
  timeout instead of hanging
@cppalliance-bot

Copy link
Copy Markdown

An automated preview of the documentation is available at https://371.capy.prtest3.cppalliance.org/index.html

If more commits are pushed to the pull request, the docs will rebuild at the same URL.

2026-07-23 15:12:08 UTC

@sgerbino
sgerbino merged commit 727f491 into cppalliance:develop Jul 23, 2026
36 checks passed
@sgerbino
sgerbino deleted the pr/awaitable-sender branch July 23, 2026 15:45
@github-project-automation github-project-automation Bot moved this from Backlog to Done in Beast2 Jul 23, 2026
@codecov

codecov Bot commented Jul 23, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.33%. Comparing base (f3d63c4) to head (d13cc92).
⚠️ Report is 8 commits behind head on develop.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop     #371      +/-   ##
===========================================
+ Coverage    98.15%   98.33%   +0.17%     
===========================================
  Files           76      152      +76     
  Lines         3913     8288    +4375     
===========================================
+ Hits          3841     8150    +4309     
- Misses          72      138      +66     
Flag Coverage Δ
linux 98.32% <ø> (+0.16%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.
see 78 files with indirect coverage changes


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update f3d63c4...d13cc92. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants