Skip to content

Add range-based connect composed operation#233

Merged
mvandeberg merged 1 commit intocppalliance:developfrom
mvandeberg:pr/124-range-connect
Apr 17, 2026
Merged

Add range-based connect composed operation#233
mvandeberg merged 1 commit intocppalliance:developfrom
mvandeberg:pr/124-range-connect

Conversation

@mvandeberg
Copy link
Copy Markdown
Contributor

@mvandeberg mvandeberg commented Apr 17, 2026

Closes #124

Free functions in boost/corosio/connect.hpp that try each endpoint in a range (or iterator pair) until one connects, with optional connect-condition predicate. Mirrors Boost.Asio's async_connect semantics adapted to corosio's coroutine model.

Summary by CodeRabbit

  • New Features
    • Added coroutine-based connect that tries multiple endpoints in sequence.
    • Added optional predicates to conditionally skip endpoint attempts and surface cancellation.
    • Added endpoint_type aliases to socket types for more consistent and discoverable endpoint handling.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 17, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3c7e7c14-7188-4c5c-bcbd-067ada6763c4

📥 Commits

Reviewing files that changed from the base of the PR and between 41fc681 and 4cb9a08.

⛔ Files ignored due to path filters (2)
  • doc/modules/ROOT/pages/4.guide/4d.sockets.adoc is excluded by !**/doc/**
  • test/unit/connect.cpp is excluded by !**/test/**
📒 Files selected for processing (3)
  • include/boost/corosio/connect.hpp
  • include/boost/corosio/local_stream_socket.hpp
  • include/boost/corosio/tcp_socket.hpp
✅ Files skipped from review due to trivial changes (1)
  • include/boost/corosio/tcp_socket.hpp
🚧 Files skipped from review as they are similar to previous changes (1)
  • include/boost/corosio/local_stream_socket.hpp

📝 Walkthrough

Walkthrough

Adds coroutine-based boost::corosio::connect overloads that attempt to connect a socket to multiple candidate endpoints (range and iterator forms, with optional per-attempt predicate) and adds endpoint_type aliases to tcp_socket and local_stream_socket.

Changes

Cohort / File(s) Summary
Connect coroutines
include/boost/corosio/connect.hpp
New file. Introduces four coroutine connect templates: range and iterator overloads, each with optional ConnectCondition. Iterates candidates, optionally skips via predicate cond(last_ec, ep), closes socket before each attempt, co_awaits s.connect(ep), returns capy::io_result with connected endpoint/iterator on success, returns canceled immediately if per-attempt yields capy::cond::canceled, and returns last error or std::errc::no_such_device_or_address on exhaustion. Unconditioned overloads delegate to predicate forms.
Socket endpoint aliases
include/boost/corosio/tcp_socket.hpp, include/boost/corosio/local_stream_socket.hpp
Added public using endpoint_type = corosio::endpoint; (TCP) and using endpoint_type = corosio::local_endpoint; (local stream) to enable endpoint-aware generic usage.

Sequence Diagram(s)

(Skipped — changes are focused on a new internal coroutine API; no multi-component sequential flow diagram provided.)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hopped through endpoints, one, two, three,

co_awaiting dreams of connectivity.
With predicates keen and sockets neat,
I close, I try — I never cheat.
A connected hop — a rabbit's treat. 🥕

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add range-based connect composed operation' accurately and concisely describes the main change: adding a new range-based connect function to the boost::corosio library.
Linked Issues check ✅ Passed The PR implements the range-based connect feature requested in #124, providing composed operations that iterate through endpoints and attempt connections sequentially, mirroring Boost.Asio's async_connect semantics.
Out of Scope Changes check ✅ Passed All changes are scope-aligned: the new connect.hpp header implements the requested range-based connect feature, while endpoint_type aliases in tcp_socket.hpp and local_stream_socket.hpp are necessary supporting changes for the connect operation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
include/boost/corosio/connect.hpp (3)

180-181: Drop the no-op static_casts on the condition arguments.

last_ec and ep are already lvalues of the expected types; they bind to std::error_code const& / endpoint_type const& implicitly. The casts add noise without changing overload resolution (the predicate concept at Lines 70-73 / 81-84 only requires invocability with those const refs).

♻️ Proposed simplification
-        if (!cond(static_cast<std::error_code const&>(last_ec),
-                  static_cast<endpoint_type const&>(ep)))
-            continue;
+        if (!cond(last_ec, ep))
+            continue;

Apply the same at Lines 273–274.

Also applies to: 273-274

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/connect.hpp` around lines 180 - 181, Remove the
redundant static_casts when invoking the predicate `cond` with `last_ec` and
`ep` in `connect.hpp`: change the call sites where
`cond(static_cast<std::error_code const&>(last_ec), static_cast<endpoint_type
const&>(ep))` (and the analogous call later) to pass `last_ec` and `ep`
directly, since they already bind to `std::error_code const&` and `endpoint_type
const&`; update both occurrences (the one near the first `if` using `cond` and
the analogous occurrence around lines 273–274) to eliminate the no-op casts.

66-86: Consider a forwarding-reference Range&& / Iter pair instead of by-value.

Taking Range endpoints by value works and — as the comment at Lines 25-42 notes — extends the lifetime of temporaries like resolver_results. But it also silently copies lvalue containers (e.g. a user's std::vector<endpoint>), which can be surprising and pointlessly expensive. A forwarding reference + std::views::all / explicit move gets you both behaviors without the copy:

template<class Socket, std::ranges::input_range Range, class ConnectCondition>
    requires /* ... */
capy::task<capy::io_result<typename Socket::endpoint_type>>
connect(Socket& s, Range&& endpoints, ConnectCondition cond);

Callers passing rvalues still get the frame-extended lifetime (via the forwarded value captured into the coroutine frame); callers passing lvalues avoid the deep copy. If by-value is a deliberate parity choice with Asio's async_connect, the current comment could call that out explicitly.

Non-blocking — flag for consideration.

Also applies to: 129-138, 226-238

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/connect.hpp` around lines 66 - 86, The two connect
overloads take Range endpoints and Iter by-value which causes unnecessary copies
of lvalue containers; change them to forwarding references (e.g., template
parameters Range&& endpoints and Iter&& begin/Iter&& end or an Iter pair
wrapper) and use std::views::all / std::ranges::borrowed_range or explicit
std::move when capturing rvalues so temporaries still get coroutine-frame
lifetime extension while lvalues avoid deep copies; update the declarations for
the connect(Socket& s, Range&& endpoints, ConnectCondition cond) and the
connect(Socket& s, Iter begin, Iter end, ConnectCondition cond) overloads (and
the analogous declarations at lines noted) to accept forwarding references and
adapt the implementation to capture/move the forwarded ranges/iterators into the
coroutine frame.

88-128: Bring the composed-connect doxygen into line with the repo's doc guidelines.

The docstrings are thorough prose, but a few required elements from the project's doc template are missing on a public header in a non-detail namespace:

  • No @li bulleted Completion conditions list (success, error, cancellation, empty/exhausted-range).
  • No @tparam Socket stating the required operations. Range/Iter/ConnectCondition already carry concept/requires constraints and per guidelines do not need @tparam, but Socket has no concept and implicitly requires endpoint_type, is_open(), close(), and an awaitable connect(endpoint_type) — worth spelling out.
  • No concurrency / overlap note (e.g. "this composed operation is implemented in terms of Socket::connect; only one connect may be in flight, and no other connect-initiating calls may be issued concurrently on s").
  • No @see at the end (e.g. Socket::connect, Asio's async_connect for the semantics you're mirroring).
  • The iterator overload at Lines 204–225 omits the cancellation paragraph present on the range overload, even though the implementation at Line 285–286 does return end on capy::cond::canceled.

As per coding guidelines: "Completion conditions — Bulleted @li list of conditions under which the operation completes and the coroutine resumes", "@tparam documentation — For non-variadic template parameters, state the concept requirement", "Concurrency and overlap — State which operations may be simultaneously in flight ... all calls to the stream must be made from the same implicit or explicit serialization context", and "@see cross-references — Always place last".

Also applies to: 140-160, 204-225, 240-253

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/connect.hpp` around lines 88 - 128, Update the
corosio::connect doxygen: add a bulleted "@li" Completion conditions list
covering success (connected endpoint), failure after all attempts (last error +
default endpoint), cancellation (immediately returns capy::cond::canceled and
does not try further endpoints), and empty-range
(std::errc::no_such_device_or_address); add an "@tparam Socket" describing
required members/types (Socket::endpoint_type, is_open(), close(), and a
connect(endpoint_type) returning an awaitable); add a concurrency/overlap note
stating the composed operation is implemented in terms of Socket::connect so
only one connect may be in flight on the same socket and no other
connect-initiating calls may be issued concurrently on s; add a "@see" pointing
to Socket::connect and asio::async_connect; and mirror the range-overload
cancellation paragraph in the iterator overload (document that
capy::cond::canceled causes the operation to complete immediately and the
iterator-returning overload returns end on cancellation).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@include/boost/corosio/connect.hpp`:
- Around line 184-185: Document that calling s.close() before each connect
attempt discards any socket options the caller previously set: add a one-line
`@note` to the overload docs in connect.hpp (the overloads that perform the
candidate-loop using s.close()) stating that user-applied socket options (e.g.
SO_REUSEADDR, IPV6_V6ONLY, TCP_NODELAY) are discarded between attempts and that
callers should set options via the ConnectCondition hook or apply options after
the composed operation completes; reference the s.close() behavior and the
ConnectCondition hook in the note so users know where to apply options.

---

Nitpick comments:
In `@include/boost/corosio/connect.hpp`:
- Around line 180-181: Remove the redundant static_casts when invoking the
predicate `cond` with `last_ec` and `ep` in `connect.hpp`: change the call sites
where `cond(static_cast<std::error_code const&>(last_ec),
static_cast<endpoint_type const&>(ep))` (and the analogous call later) to pass
`last_ec` and `ep` directly, since they already bind to `std::error_code const&`
and `endpoint_type const&`; update both occurrences (the one near the first `if`
using `cond` and the analogous occurrence around lines 273–274) to eliminate the
no-op casts.
- Around line 66-86: The two connect overloads take Range endpoints and Iter
by-value which causes unnecessary copies of lvalue containers; change them to
forwarding references (e.g., template parameters Range&& endpoints and Iter&&
begin/Iter&& end or an Iter pair wrapper) and use std::views::all /
std::ranges::borrowed_range or explicit std::move when capturing rvalues so
temporaries still get coroutine-frame lifetime extension while lvalues avoid
deep copies; update the declarations for the connect(Socket& s, Range&&
endpoints, ConnectCondition cond) and the connect(Socket& s, Iter begin, Iter
end, ConnectCondition cond) overloads (and the analogous declarations at lines
noted) to accept forwarding references and adapt the implementation to
capture/move the forwarded ranges/iterators into the coroutine frame.
- Around line 88-128: Update the corosio::connect doxygen: add a bulleted "@li"
Completion conditions list covering success (connected endpoint), failure after
all attempts (last error + default endpoint), cancellation (immediately returns
capy::cond::canceled and does not try further endpoints), and empty-range
(std::errc::no_such_device_or_address); add an "@tparam Socket" describing
required members/types (Socket::endpoint_type, is_open(), close(), and a
connect(endpoint_type) returning an awaitable); add a concurrency/overlap note
stating the composed operation is implemented in terms of Socket::connect so
only one connect may be in flight on the same socket and no other
connect-initiating calls may be issued concurrently on s; add a "@see" pointing
to Socket::connect and asio::async_connect; and mirror the range-overload
cancellation paragraph in the iterator overload (document that
capy::cond::canceled causes the operation to complete immediately and the
iterator-returning overload returns end on cancellation).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: dd550d39-7311-452e-9e0c-1961237aecda

📥 Commits

Reviewing files that changed from the base of the PR and between 3fc8c97 and 41fc681.

⛔ Files ignored due to path filters (2)
  • doc/modules/ROOT/pages/4.guide/4d.sockets.adoc is excluded by !**/doc/**
  • test/unit/connect.cpp is excluded by !**/test/**
📒 Files selected for processing (3)
  • include/boost/corosio/connect.hpp
  • include/boost/corosio/local_stream_socket.hpp
  • include/boost/corosio/tcp_socket.hpp

Comment thread include/boost/corosio/connect.hpp
@cppalliance-bot
Copy link
Copy Markdown

cppalliance-bot commented Apr 17, 2026

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

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

2026-04-17 16:42:32 UTC

@cppalliance-bot
Copy link
Copy Markdown

cppalliance-bot commented Apr 17, 2026

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

Build time: 2026-04-17 16:51:19 UTC

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 17, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 77.71%. Comparing base (3fc8c97) to head (4cb9a08).
⚠️ Report is 2 commits behind head on develop.

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff            @@
##           develop     #233   +/-   ##
========================================
  Coverage    77.71%   77.71%           
========================================
  Files           96       96           
  Lines         7298     7298           
  Branches      1787     1787           
========================================
  Hits          5672     5672           
  Misses        1108     1108           
  Partials       518      518           
Files with missing lines Coverage Δ
include/boost/corosio/tcp_socket.hpp 87.17% <ø> (ø)

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 3fc8c97...4cb9a08. Read the comment docs.

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

Free functions in boost/corosio/connect.hpp that try each endpoint in a
range (or iterator pair) until one connects, with optional connect-condition
predicate. Mirrors Boost.Asio's async_connect semantics adapted to
corosio's coroutine model.
@mvandeberg mvandeberg force-pushed the pr/124-range-connect branch from 41fc681 to 4cb9a08 Compare April 17, 2026 16:35
@mvandeberg
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 17, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@mvandeberg mvandeberg merged commit 18a8a2f into cppalliance:develop Apr 17, 2026
43 checks passed
@mvandeberg mvandeberg deleted the pr/124-range-connect branch April 17, 2026 17:47
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.

Feature request: range connect

2 participants