Skip to content

feat(native): complete async-op shadowing across all I/O types#253

Merged
sgerbino merged 2 commits into
cppalliance:developfrom
sgerbino:pr/shadow
May 26, 2026
Merged

feat(native): complete async-op shadowing across all I/O types#253
sgerbino merged 2 commits into
cppalliance:developfrom
sgerbino:pr/shadow

Conversation

@sgerbino
Copy link
Copy Markdown
Collaborator

Extend the shadow pattern (concrete-class method names hidden by derived native_ templates that return strongly-typed awaitables instead of dispatching virtually) so every async operation on every public I/O type has a native_ counterpart.

Before this branch, only a subset of the async surface was shadowed. native_tcp_socket and native_tcp_acceptor shadowed their read/write/accept/connect ops, but native_udp_socket covered only send_to/recv_from, and the local-socket and file types had no shadow at all. Code holding a native_X reference therefore went through the virtual io_object dispatch for any non-shadowed call, defeating the point of using the typed wrapper.

This commit closes the gap:

  • native_udp_socket gains connect, send, recv shadows.
  • New native_local_stream_socket shadows read_some, write_some, connect.
  • New native_local_stream_acceptor shadows accept(peer&) and the move-accept overload (returning a native_local_stream_socket).
  • New native_local_datagram_socket shadows send_to, recv_from, connect, send, recv.
  • New native_stream_file shadows read_some, write_some.
  • New native_random_access_file shadows read_some_at, write_some_at.
  • Every shadow type also gets wait() returning a typed native_wait_awaitable.

Tests under test/unit/native/ exercise each new shadow with a static_assert that pins the shadowing contract (the native op must return a type distinct from the concrete base op), plus runtime checks of the awaitable path and a polymorphic-slice test that verifies the base class still works via virtual dispatch when the object is used through its non-native interface.

Supporting bits:

  • backend.hpp gains the file-type tag typedefs (stream_file_type, random_access_file_type, and service_type) for every backend so create_handle<service_type>(ctx) compiles in the new native_file wrappers.
  • stream_file and random_access_file grow protected constructors so the native virtual-base initialization works (io_stream virtually inherits io_object; only the most-derived class initializes it).
  • local_stream_acceptor::bind now honors bind_option::unlink_existing on Windows via DeleteFileA — the option was previously a no-op in the non-POSIX branch, which broke testUnlinkExisting on the iocp variant.
  • win_tcp_service::connect_ex / accept_ex getters move into the class body so TUs that include only the service header (the new native_local_stream_socket test among them) get the inline definitions.
  • win_local_stream_service.hpp pulls in the acceptor header directly so its inline shutdown() sees the full win_local_stream_acceptor_internal type regardless of consumer include order.
  • A portable test/unit/local_temp.hpp helper replaces the old POSIX-only mkdtemp/unlink pattern in the local-socket tests, using std::filesystem + a random_device-seeded RNG so parallel ctest processes don't collide on /tmp paths.

Known platform gaps documented in-file:

  • local_datagram_socket tests stay POSIX-only at the top-of-file. Windows has never shipped AF_UNIX SOCK_DGRAM; the very first WSASocket(AF_UNIX, SOCK_DGRAM, ...) returns WSAESOCKTNOSUPPORT.
  • local_stream_socket's three socketpair-based tests (testReadWrite, testSocketPair, testAvailable) and the raw-fd testRelease remain per-test POSIX-gated; make_local_stream_pair is gated POSIX-only in the public header because socketpair() doesn't exist on Windows. TCP socket tests already exercise the equivalent read/write paths on Windows IOCP.

@cppalliance-bot
Copy link
Copy Markdown

cppalliance-bot commented May 26, 2026

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

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

2026-05-26 18:23:38 UTC

@cppalliance-bot
Copy link
Copy Markdown

cppalliance-bot commented May 26, 2026

GCOVR code coverage report https://253.corosio.prtest3.cppalliance.org/gcovr/index.html
LCOV code coverage report https://253.corosio.prtest3.cppalliance.org/genhtml/index.html
Coverage Diff Report https://253.corosio.prtest3.cppalliance.org/diff-report/index.html

Build time: 2026-05-26 18:28:18 UTC

@codecov
Copy link
Copy Markdown

codecov Bot commented May 26, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 77.76%. Comparing base (f17d881) to head (4fd8b0b).

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff            @@
##           develop     #253   +/-   ##
========================================
  Coverage    77.76%   77.76%           
========================================
  Files           96       96           
  Lines         7264     7264           
  Branches      1775     1775           
========================================
  Hits          5649     5649           
  Misses        1104     1104           
  Partials       511      511           
Files with missing lines Coverage Δ
...clude/boost/corosio/native/native_tcp_acceptor.hpp 90.90% <ø> (ø)
include/boost/corosio/native/native_tcp_socket.hpp 90.41% <ø> (ø)

Continue to review full report in Codecov by Sentry.

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

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

Extend the shadow pattern (concrete-class method names hidden by
derived native_*<Backend> templates that return strongly-typed
awaitables instead of dispatching virtually) so every async
operation on every public I/O type has a native_* counterpart.

Before this branch, only a subset of the async surface was
shadowed. native_tcp_socket and native_tcp_acceptor shadowed
their read/write/accept/connect ops, but native_udp_socket
covered only send_to/recv_from, and the local-socket and file
types had no shadow at all. Code holding a native_X<Backend>
reference therefore went through the virtual io_object dispatch
for any non-shadowed call, defeating the point of using the
typed wrapper.

This commit closes the gap:

  - native_udp_socket gains connect, send, recv shadows.
  - New native_local_stream_socket shadows read_some, write_some,
    connect.
  - New native_local_stream_acceptor shadows accept(peer&) and
    the move-accept overload (returning a
    native_local_stream_socket<Backend>).
  - New native_local_datagram_socket shadows send_to, recv_from,
    connect, send, recv.
  - New native_stream_file shadows read_some, write_some.
  - New native_random_access_file shadows read_some_at,
    write_some_at.
  - Every shadow type also gets wait() returning a typed
    native_wait_awaitable.

Tests under test/unit/native/ exercise each new shadow with a
static_assert that pins the shadowing contract (the native op
must return a type distinct from the concrete base op), plus
runtime checks of the awaitable path and a polymorphic-slice
test that verifies the base class still works via virtual
dispatch when the object is used through its non-native
interface.

Supporting bits:

  - backend.hpp gains the file-type tag typedefs (stream_file_type,
    random_access_file_type, and *_service_type) for every
    backend so create_handle<service_type>(ctx) compiles in the
    new native_*_file wrappers.
  - stream_file and random_access_file grow protected constructors
    so the native virtual-base initialization works (io_stream
    virtually inherits io_object; only the most-derived class
    initializes it).
  - local_stream_acceptor::bind now honors bind_option::unlink_existing
    on Windows via DeleteFileA — the option was previously a no-op
    in the non-POSIX branch, which broke testUnlinkExisting on the
    iocp variant.
  - win_tcp_service::connect_ex / accept_ex getters move into the
    class body so TUs that include only the service header (the
    new native_local_stream_socket test among them) get the
    inline definitions.
  - win_local_stream_service.hpp pulls in the acceptor header
    directly so its inline shutdown() sees the full
    win_local_stream_acceptor_internal type regardless of
    consumer include order.
  - A portable test/unit/local_temp.hpp helper replaces the old
    POSIX-only mkdtemp/unlink pattern in the local-socket tests,
    using std::filesystem + a random_device-seeded RNG so
    parallel ctest processes don't collide on /tmp paths.

Known platform gaps documented in-file:

  - local_datagram_socket tests stay POSIX-only at the
    top-of-file. Windows has never shipped AF_UNIX SOCK_DGRAM;
    the very first WSASocket(AF_UNIX, SOCK_DGRAM, ...) returns
    WSAESOCKTNOSUPPORT.
  - local_stream_socket's three socketpair-based tests
    (testReadWrite, testSocketPair, testAvailable) and the
    raw-fd testRelease remain per-test POSIX-gated;
    make_local_stream_pair is gated POSIX-only in the public
    header because socketpair() doesn't exist on Windows. TCP
    socket tests already exercise the equivalent read/write
    paths on Windows IOCP.
…unt tests

Replace the 10ms delay timer that sequenced waiter registration before
the reset with explicit poll() drains. The previous structure relied on
the IOCP scheduler dispatching the two t.wait() suspensions before the
delay timer expired; on Windows release builds the order isn't
guaranteed and the test would intermittently observe zero canceled
waiters.
@sgerbino sgerbino merged commit 1c5b7d7 into cppalliance:develop May 26, 2026
41 checks passed
@sgerbino sgerbino deleted the pr/shadow branch May 26, 2026 18:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants