Skip to content

Restore server typestate and split configuration#279

Merged
leynos merged 20 commits intomainfrom
codex/address-code-review-comments
Aug 9, 2025
Merged

Restore server typestate and split configuration#279
leynos merged 20 commits intomainfrom
codex/address-code-review-comments

Conversation

@leynos
Copy link
Copy Markdown
Owner

@leynos leynos commented Aug 6, 2025

Summary

  • enforce compile-time binding with Bound/Unbound typestate
  • introduce ServerError and reorganise config into binding and preamble modules

Testing

  • make lint
  • make test

https://chatgpt.com/codex/tasks/task_e_6893cfc7ed7c83228f453cfa2aec3629

Summary by Sourcery

Enforce compile-time server binding via typestate markers, reorganise configuration and error handling, and update examples and docs to reflect the new ServerError and typestate API.

New Features:

  • Introduce typestate markers (Unbound/Bound) for WireframeServer to enforce compile-time binding state
  • Split server configuration into separate binding and preamble modules
  • Add a dedicated ServerError enum for runtime errors

Enhancements:

  • Update runtime methods to return ServerError instead of io::Error and remove optional listener use
  • Refactor examples to use ? and return Result<(), Box<dyn Error>> for unified error handling

Build:

  • Add thiserror dependency for error derivation

Documentation:

  • Reformat tables and numbering in the asynchronous outbound messaging design document

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Aug 6, 2025

Reviewer's Guide

This PR refactors the server to enforce compile-time binding state via a typestate pattern, splits the configuration builder into dedicated binding and preamble modules, introduces a new ServerError type for runtime failures, updates example code to align with the new error and typestate APIs, and applies minor documentation formatting tweaks with an added thiserror dependency.

Class diagram for configuration module split

classDiagram
    class config {
    }
    class binding {
    }
    class preamble {
    }
    config --> binding : mod binding
    config --> preamble : mod preamble
Loading

File-Level Changes

Change Details Files
Restore compile-time typestate for server binding
  • Add generic S parameter and replace Option with state: Unbound/Bound
  • Define Unbound and Bound marker types and ServerState trait
  • Update WireframeServer impls to use typestate in new(), bind(), and run()
  • Adjust test utilities to return Bound server instead of Option listener
src/server/mod.rs
src/server/test_util.rs
Split configuration into binding and preamble modules
  • Remove inline bind and preamble methods from config/mod.rs
  • Create config/binding.rs and config/preamble.rs to house related logic
  • Update mod.rs to reference the new submodules and prune unused imports
src/server/config/mod.rs
src/server/config/binding.rs
src/server/config/preamble.rs
Introduce ServerError and update runtime error handling
  • Add ServerError enum with thiserror for accept errors
  • Change run and run_with_shutdown to return Result<(), ServerError>
  • Destructure Bound state in runtime rather than extracting Option listener
src/server/error.rs
src/server/runtime.rs
Update examples to match new error and typestate APIs
  • Change main return types to Result<(), Box>
  • Propagate bind and run errors with ? and add Ok(())
  • Remove outdated io::Result signatures
examples/ping_pong.rs
examples/echo.rs
examples/packet_enum.rs
examples/metadata_routing.rs
Minor documentation cleanup and dependency addition
  • Adjust markdown table formatting and numbering in design docs and README
  • Add thiserror dependency in Cargo.toml
docs/asynchronous-outbound-messaging-design.md
README.md
Cargo.toml

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Aug 6, 2025

Summary by CodeRabbit

New Features

  • Enhanced server configuration with explicit binding and preamble handler modules, allowing more flexible setup and custom connection preamble handling.
  • Introduced a custom error type for server operations, improving error clarity and handling.

Refactor

  • Server builder and runtime refactored to use typestate patterns, enforcing binding before running and clarifying server states.
  • Updated naming conventions from "callback" to "handler" for preamble processing throughout the codebase.

Bug Fixes

  • Improved test reliability by increasing timeout durations and ensuring correct callback/handler invocation logic.

Documentation

  • Improved markdown formatting, numbering, and terminology consistency in design documents and code comments.

Chores

  • Added a new dependency for error handling and updated imports accordingly.

Walkthrough

Refactor the server configuration and runtime to use a typestate pattern with explicit Unbound and Bound states, modularise binding and preamble configuration into separate submodules, introduce a custom ServerError type for error handling, and update all related examples, tests, and documentation to match the new API and terminology.

Changes

Cohort / File(s) Change Summary
Server Typestate, Error Handling, and API Refactor
src/server/mod.rs, src/server/runtime.rs, src/server/error.rs, Cargo.toml
Introduce typestate pattern for server binding (Unbound/Bound), add ServerError enum for error handling, update generic parameters and field structure, rename preamble callback types to handler traits, and update imports. Add thiserror dependency.
Server Configuration Modularisation
src/server/config/mod.rs, src/server/config/binding.rs, src/server/config/preamble.rs
Move binding and preamble configuration into separate submodules, remove direct binding and preamble methods from main config, update builder pattern, and add new public methods for preamble and binding setup.
Examples Update for New API
examples/echo.rs, examples/packet_enum.rs, examples/ping_pong.rs
Update server instantiation, binding, and error handling to use typestate and ServerError. Change main function signatures and error propagation.
Test Support and Utility Update
src/server/test_util.rs, src/server/config/tests.rs
Update test utilities and function signatures for typestate and handler terminology. Rename callback-related test functions and parameters to handler.
Connection Handling Terminology
src/server/connection.rs
Rename preamble callback types to handler types in function signatures and logging. No logic changes.
Documentation and Cosmetic Updates
docs/asynchronous-outbound-messaging-design.md
Adjust markdown formatting and numbering for clarity; no content or logic changes.
Preamble Callback/Handler Test Enhancements
tests/preamble.rs
Add new preamble type, extend tests to verify handler override behaviour, increase timeouts, and ensure correct callback dropping.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant WireframeServer (Unbound)
    participant WireframeServer (Bound)
    participant TcpListener
    participant AppFactory

    User->>WireframeServer (Unbound): new(factory)
    User->>WireframeServer (Unbound): with_preamble()/on_preamble_decode_success()
    User->>WireframeServer (Unbound): bind(addr)
    WireframeServer (Unbound)->>TcpListener: bind(addr)
    TcpListener-->>WireframeServer (Bound): listener (Arc)
    User->>WireframeServer (Bound): run().await
    WireframeServer (Bound)->>AppFactory: create app
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

Refactor winds blow through the code,
Typestates stand where options strode.
Handlers rise, callbacks fade,
Bound and Unbound now clearly laid.
Errors custom, tests anew,
Wireframe’s shape—refined, askew!
🦀✨

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/address-code-review-comments

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey @leynos - I've reviewed your changes - here's some feedback:

  • Verify that the new config/binding and config/preamble modules are publicly re‐exporting all builder methods (with_preamble, on_preamble_decode_*) so existing fluent calls still compile without extra imports.
  • Consider extending ServerError to capture binding/setup failures (not just accept errors) and unify the error types returned by run/run_with_shutdown instead of mixing io::Error and ServerError.
  • Align the example mains to use the new ServerError (or a concrete error type) instead of generic Box to improve clarity and consistency of error handling.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Verify that the new config/binding and config/preamble modules are publicly re‐exporting all builder methods (with_preamble, on_preamble_decode_*) so existing fluent calls still compile without extra imports.
- Consider extending ServerError to capture binding/setup failures (not just accept errors) and unify the error types returned by run/run_with_shutdown instead of mixing io::Error and ServerError.
- Align the example mains to use the new ServerError (or a concrete error type) instead of generic Box<dyn Error> to improve clarity and consistency of error handling.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Aug 7, 2025

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Aug 7, 2025

✅ 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.

Copy link
Copy Markdown
Contributor

@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: 4

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e890d53 and 8e1b9f8.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (14)
  • Cargo.toml (1 hunks)
  • README.md (1 hunks)
  • docs/asynchronous-outbound-messaging-design.md (4 hunks)
  • examples/echo.rs (2 hunks)
  • examples/metadata_routing.rs (1 hunks)
  • examples/packet_enum.rs (3 hunks)
  • examples/ping_pong.rs (2 hunks)
  • src/server/config/binding.rs (1 hunks)
  • src/server/config/mod.rs (2 hunks)
  • src/server/config/preamble.rs (1 hunks)
  • src/server/error.rs (1 hunks)
  • src/server/mod.rs (2 hunks)
  • src/server/runtime.rs (5 hunks)
  • src/server/test_util.rs (3 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.md

⚙️ CodeRabbit Configuration File

**/*.md: * Avoid 2nd person or 1st person pronouns ("I", "you", "we")

  • Use en-GB-oxendict (-ize / -our) spelling and grammar
  • Paragraphs and bullets must be wrapped to 80 columns, except where a long URL would prevent this (in which case, silence MD013 for that line)
  • Code blocks should be wrapped to 120 columns.
  • Headings must not be wrapped.
  • Documents must start with a level 1 heading
  • Headings must correctly increase or decrease by no more than one level at a time
  • Use GitHub-flavoured Markdown style for footnotes and endnotes.
  • Numbered footnotes must be numbered by order of appearance in the document.

Files:

  • README.md
  • docs/asynchronous-outbound-messaging-design.md
**/*.rs

⚙️ CodeRabbit Configuration File

**/*.rs: * Seek to keep the cyclomatic complexity of functions no more than 12.

  • Adhere to single responsibility and CQRS

  • Place function attributes after doc comments.

  • Do not use return in single-line functions.

  • Move conditionals with >2 branches into a predicate function.

  • Avoid unsafe unless absolutely necessary.

  • Every module must begin with a //! doc comment that explains the module's purpose and utility.

  • Comments and docs must follow en-GB-oxendict (-ize / -our) spelling and grammar

  • Lints must not be silenced except as a last resort.

    • #[allow] is forbidden.
    • Only narrowly scoped #[expect(lint, reason = "...")] is allowed.
    • No lint groups, no blanket or file-wide suppression.
    • Include FIXME: with link if a fix is expected.
  • Use rstest fixtures for shared setup and to avoid repetition between tests.

  • Replace duplicated tests with #[rstest(...)] parameterised cases.

  • Prefer mockall for mocks/stubs.

  • Prefer .expect() over .unwrap()

  • Ensure that any API or behavioural changes are reflected in the documentation in docs/

  • Ensure that any completed roadmap steps are recorded in the appropriate roadmap in docs/

  • Files must not exceed 400 lines in length

    • Large modules must be decomposed
    • Long match statements or dispatch tables should be decomposed by domain and collocated with targets
    • Large blocks of inline data (e.g., test fixtures, constants or templates) must be moved to external files and inlined at compile-time or loaded at run-time.

Files:

  • examples/echo.rs
  • examples/packet_enum.rs
  • src/server/error.rs
  • examples/ping_pong.rs
  • src/server/test_util.rs
  • examples/metadata_routing.rs
  • src/server/config/mod.rs
  • src/server/config/binding.rs
  • src/server/runtime.rs
  • src/server/mod.rs
  • src/server/config/preamble.rs
🧬 Code Graph Analysis (4)
examples/echo.rs (1)
examples/ping_pong.rs (1)
  • main (139-149)
examples/ping_pong.rs (3)
examples/echo.rs (1)
  • main (12-33)
examples/packet_enum.rs (1)
  • main (79-97)
examples/metadata_routing.rs (1)
  • main (63-108)
src/server/test_util.rs (1)
src/server/config/tests.rs (2)
  • WireframeServer (60-60)
  • WireframeServer (135-137)
src/server/config/preamble.rs (3)
src/extractor.rs (1)
  • std (270-270)
src/server/test_util.rs (1)
  • WireframeServer (46-46)
src/server/config/mod.rs (1)
  • new (37-48)
🪛 LanguageTool
docs/asynchronous-outbound-messaging-design.md

[uncategorized] ~72-~72: Loose punctuation mark.
Context: ...low_priority_push_rx: mpsc::Receiver`: For standard, non-urgent background ...

(UNLIKELY_OPENING_PUNCTUATION)

🔇 Additional comments (26)
docs/asynchronous-outbound-messaging-design.md (2)

41-47: LGTM! Table formatting improvements enhance readability.

The aligned table columns make the requirements section much more readable and professional.


72-98: LGTM! Numbering sequence properly corrected.

The sequential numbering (1, 2, 3, 4) for the polling order steps is now accurate and follows logical progression.

README.md (1)

86-86: LGTM! Minor formatting improvement.

Removing the unnecessary line break improves text flow whilst preserving the markdownlint directive for the long URL.

examples/echo.rs (2)

12-12: LGTM! Improved error handling with generalised return type.

The change to Result<(), Box<dyn std::error::Error>> provides better compatibility with the new ServerError type and follows the pattern established across other examples.


31-32: LGTM! Clean error propagation and explicit success handling.

Using the ? operator for error propagation and explicit Ok(()) return improves code clarity and consistency with other examples.

examples/metadata_routing.rs (1)

63-63: Approve error handling generalisation in metadata_routing.rs

Error handling pattern matches echo.rs: async calls use ? operator and an explicit Ok(()) return is present.

  • examples/metadata_routing.rs: client.write_all(&bytes).await?;, client.shutdown().await?;
  • examples/metadata_routing.rs: explicit Ok(()) at end of main
src/server/error.rs (3)

1-1: LGTM!

Module documentation properly explains purpose and follows required format with //! comment.


3-5: LGTM!

Imports are minimal and appropriate for the error handling implementation.


7-13: Well-designed error type with proper derives and automatic conversion.

The enum follows Rust error handling best practices with appropriate derives, clear documentation, and automatic conversion from io::Error. The design allows for easy extension with additional variants as the server functionality grows.

examples/packet_enum.rs (2)

6-6: LGTM!

Correctly removed unused io import following the change from io::Result<()> to Box<dyn std::error::Error>.


79-79: LGTM!

Main function signature updated to use general error type and properly propagates errors with ? operator. Changes align with the new ServerError type and are consistent with other examples.

Also applies to: 95-96

examples/ping_pong.rs (4)

6-6: LGTM!

Correctly removed unused io import following the error handling changes.


139-139: LGTM!

Function signature correctly updated to use general error type, consistent with other examples.


146-146: LGTM!

Simplified address parsing by removing unnecessary error mapping. The ? operator handles conversion automatically with the new error type.


147-148: LGTM!

Properly propagates errors with ? operator after await and returns explicit Ok(()). Changes are consistent with other examples.

src/server/test_util.rs (2)

8-8: LGTM!

Correctly added Bound import to support the updated return type using typestate markers.


32-32: LGTM!

Return type correctly updated to include Bound state marker, ensuring compile-time verification of server binding state.

src/server/runtime.rs (5)

3-3: LGTM!

Import changes correctly reflect the transition to custom error handling and typestate system. Removed unused io import and added necessary Bound and ServerError imports.

Also applies to: 15-15, 20-20


27-27: Excellent use of typestate pattern for compile-time safety.

Constraining the impl block to Bound servers prevents runtime errors by ensuring these methods can only be called on properly bound servers.


52-53: LGTM!

Method signatures correctly updated to return custom ServerError type, providing better domain-specific error handling than generic IO errors.

Also applies to: 92-92


96-104: Excellent elimination of runtime checks through typestate design.

The destructuring pattern state: Bound { listener } leverages the type system to guarantee listener availability, removing the need for runtime Option checks. This is a significant safety improvement.


27-135: Outstanding architectural improvement with typestate pattern and custom errors.

The combination of compile-time binding state verification and domain-specific error types significantly improves safety and maintainability. The elimination of runtime checks through type-level guarantees is exemplary Rust design.

src/server/mod.rs (1)

36-77: Well-implemented typestate pattern for compile-time safety.

The introduction of Unbound and Bound marker types with the ServerState trait provides excellent compile-time guarantees about the server's binding state. The use of Arc<TcpListener> in Bound correctly enables sharing between worker threads.

src/server/config/preamble.rs (1)

1-101: Clean separation of preamble configuration concerns.

The extraction of preamble configuration into a dedicated module improves modularity. The builder pattern implementation is correct, and the decision to reset callbacks when changing preamble types (lines 42-43) prevents potential type confusion issues.

src/server/config/mod.rs (1)

15-16: Module organisation enhances separation of concerns.

The extraction of binding and preamble configuration into dedicated submodules improves code organisation and maintainability.

src/server/config/binding.rs (1)

1-177: Excellent implementation of typestate-based binding configuration.

The binding module correctly implements state transitions between Unbound and Bound states. The support for rebinding (lines 117-176) provides flexibility whilst maintaining type safety. Setting listeners to non-blocking mode before Tokio conversion (lines 78, 163) is the correct approach.

Comment thread Cargo.toml Outdated
Comment thread src/server/config/mod.rs Outdated
Comment thread src/server/test_util.rs Outdated
Comment thread src/server/test_util.rs Outdated
Repository owner deleted a comment from coderabbitai Bot Aug 7, 2025
@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Aug 7, 2025

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Aug 7, 2025

✅ 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.

@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Aug 7, 2025

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Aug 7, 2025

✅ 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.

Copy link
Copy Markdown
Contributor

@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

♻️ Duplicate comments (2)
src/server/test_util.rs (2)

11-15: Replace #[allow] with #[expect] per coding guidelines.

The coding guidelines specifically forbid #[allow] and require narrowly scoped #[expect(lint, reason = "...")] instead.

Apply this diff:

 #[cfg_attr(
     not(test),
     expect(dead_code, reason = "Used in builder tests via fixtures")
 )]
-#[cfg_attr(test, allow(dead_code, reason = "Used in builder tests via fixtures"))]
+#[cfg_attr(test, expect(dead_code, reason = "Used in builder tests via fixtures"))]

45-49: Replace #[allow] with #[expect] per coding guidelines.

The coding guidelines specifically forbid #[allow] and require narrowly scoped #[expect(lint, reason = "...")] instead.

Apply this diff:

 #[cfg_attr(
     not(test),
     expect(dead_code, reason = "Only used in configuration tests")
 )]
-#[cfg_attr(test, allow(dead_code, reason = "Only used in configuration tests"))]
+#[cfg_attr(test, expect(dead_code, reason = "Only used in configuration tests"))]
📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8e1b9f8 and 6eb9e9c.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • Cargo.toml (1 hunks)
  • examples/echo.rs (2 hunks)
  • examples/packet_enum.rs (3 hunks)
  • examples/ping_pong.rs (2 hunks)
  • src/server/config/binding.rs (1 hunks)
  • src/server/config/mod.rs (2 hunks)
  • src/server/error.rs (1 hunks)
  • src/server/runtime.rs (7 hunks)
  • src/server/test_util.rs (3 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

⚙️ CodeRabbit Configuration File

**/*.rs: * Seek to keep the cyclomatic complexity of functions no more than 12.

  • Adhere to single responsibility and CQRS

  • Place function attributes after doc comments.

  • Do not use return in single-line functions.

  • Move conditionals with >2 branches into a predicate function.

  • Avoid unsafe unless absolutely necessary.

  • Every module must begin with a //! doc comment that explains the module's purpose and utility.

  • Comments and docs must follow en-GB-oxendict (-ize / -our) spelling and grammar

  • Lints must not be silenced except as a last resort.

    • #[allow] is forbidden.
    • Only narrowly scoped #[expect(lint, reason = "...")] is allowed.
    • No lint groups, no blanket or file-wide suppression.
    • Include FIXME: with link if a fix is expected.
  • Use rstest fixtures for shared setup and to avoid repetition between tests.

  • Replace duplicated tests with #[rstest(...)] parameterised cases.

  • Prefer mockall for mocks/stubs.

  • Prefer .expect() over .unwrap()

  • Ensure that any API or behavioural changes are reflected in the documentation in docs/

  • Ensure that any completed roadmap steps are recorded in the appropriate roadmap in docs/

  • Files must not exceed 400 lines in length

    • Large modules must be decomposed
    • Long match statements or dispatch tables should be decomposed by domain and collocated with targets
    • Large blocks of inline data (e.g., test fixtures, constants or templates) must be moved to external files and inlined at compile-time or loaded at run-time.

Files:

  • src/server/error.rs
  • examples/echo.rs
  • examples/packet_enum.rs
  • src/server/test_util.rs
  • examples/ping_pong.rs
  • src/server/runtime.rs
  • src/server/config/mod.rs
  • src/server/config/binding.rs
🧬 Code Graph Analysis (1)
src/server/test_util.rs (1)
src/server/config/tests.rs (2)
  • WireframeServer (60-60)
  • WireframeServer (135-137)
🔍 MCP Research (2 servers)

Deepwiki:

  • The binding configuration is split into a dedicated module implementing binding methods for WireframeServer<F, T, Unbound> and WireframeServer<F, T, Bound>. The unbound server provides local_addr returning None, and bind and bind_listener methods to bind the server and transition to the bound state. The bound server provides local_addr returning the bound address and allows rebinding via bind and bind_listener. All binding methods return a Result with a custom ServerError type for error handling. This modularization supports the typestate pattern and clean separation of binding logic. (src/server/config/binding.rs)

  • A new ServerError enum was introduced to replace io::Error in server binding and runtime operations. It has variants Bind(io::Error) for binding or listener configuration errors and Accept(io::Error) for connection acceptance failures. This explicit error type improves error handling clarity in the server's binding and runtime code. (src/server/error.rs)

  • The run and run_with_shutdown methods on WireframeServer now require the server to be in the Bound state and return Result<(), ServerError> instead of io::Result<()>. The listener is extracted from the Bound state struct rather than an optional field. This change aligns with the typestate pattern and custom error handling introduced in the PR. (src/server/runtime.rs)

  • The WireframeServer struct uses a generic parameter S representing the server state, with marker structs Unbound and Bound to represent binding states. The Unbound state has no listener, while the Bound state holds an Arc<TcpListener>. The bind method transitions the server from Unbound to Bound by creating and wrapping a TCP listener. The run and run_with_shutdown methods require the server to be in the Bound state. This typestate pattern enforces at compile time that the server must be bound before running. (Wiki page "WireframeServer")

Context7:

  • The WireframeServer struct was extended with a new generic parameter S constrained by a new trait ServerState. The previous optional listener field of type Option<Arc<TcpListener>> was replaced by a single state field of type S. Two new marker structs, Unbound and Bound, were introduced to represent server binding states. Bound holds a listener of type Arc<TcpListener>, while Unbound is an empty marker. The ServerState trait is implemented for both Unbound and Bound. These changes introduce a type-level distinction between bound and unbound server states, encapsulating the listener presence within the state field rather than an optional listener field. (src/server/mod.rs)

  • The server configuration is modularized by splitting binding and preamble logic into separate submodules (binding and preamble). The WireframeServer configuration interface is simplified by removing binding and preamble callback methods from the main config module and moving them to dedicated modules. The new constructor now returns an unbound server explicitly. This modularization clarifies responsibilities and improves maintainability. (src/server/config/mod.rs)

  • A new Rust module src/server/error.rs was added to define error types related to WireframeServer operations. It introduces a public enum ServerError that derives Debug and thiserror::Error. The enum currently has two variants: Bind and Accept, both wrapping an io::Error. The Bind variant represents errors occurring during binding or configuring the listener, with an error message formatted as "bind error: {0}". The Accept variant represents failures during connection acceptance, with an error message formatted as "accept error: {0}". Both variants use the #[source] attribute to indicate the underlying source error. (src/server/error.rs)

  • The WireframeServer implementation was updated to include a third generic parameter Bound. The run and run_with_shutdown methods' return types were changed from io::Result<()> to Result<(), ServerError>, replacing standard IO error handling with a custom ServerError type. The internal destructuring in run_with_shutdown was modified to extract the listener from a Bound struct (state: Bound { listener }) instead of directly from a listener field. The previous explicit check and error return for an unbound listener (listener.ok_or_else(...)) was removed. (src/server/runtime.rs)

🔇 Additional comments (21)
Cargo.toml (1)

30-30: LGTM! Dependency addition aligns with error handling refactoring.

The addition of thiserror 2.0.12 supports the new ServerError enum introduced in the codebase and addresses the previous feedback about using the latest version.

examples/echo.rs (3)

8-8: LGTM! Proper integration with new error handling.

The import correctly brings in ServerError to align with the updated server error handling system.


12-12: LGTM! Return type updated correctly.

The function signature properly reflects the new error handling pattern using ServerError instead of io::Error.


31-32: LGTM! Error propagation implemented correctly.

The use of the ? operator after .await properly propagates ServerError, and the explicit Ok(()) return satisfies the new return type.

examples/packet_enum.rs (4)

6-6: LGTM! Import cleanup and explicit HashMap import.

Removing unused std::io and explicitly importing HashMap improves code clarity.


14-14: LGTM! Proper ServerError import.

The import correctly brings in the new error type for consistent error handling across the server API.


79-79: LGTM! Function signature updated appropriately.

The return type change to Result<(), ServerError> aligns with the new error handling system.


95-96: LGTM! Error propagation implemented correctly.

The ? operator after .await properly propagates errors, and the explicit Ok(()) return satisfies the function signature.

examples/ping_pong.rs (4)

6-6: LGTM! Import statement cleaned up.

Removing unused std::io and keeping only necessary imports improves code clarity.


14-14: LGTM! Consistent error type import.

The ServerError import aligns with the updated server error handling across all examples.


139-139: LGTM! Return type updated correctly.

The function signature properly adopts the new ServerError type for consistent error handling.


146-148: LGTM! Streamlined error handling in example.

The use of expect for address parsing is appropriate for example code, and the method chaining with proper error propagation demonstrates the updated server API effectively.

src/server/error.rs (3)

1-2: LGTM! Proper module documentation.

The module-level documentation clearly explains the purpose and follows the coding guideline requirement for //! doc comments.


3-6: LGTM! Appropriate dependencies imported.

The imports are minimal and necessary for the error handling implementation using thiserror.


7-17: LGTM! Well-designed error enum with clear separation of concerns.

The ServerError enum provides distinct variants for binding and acceptance failures, uses proper error message formatting, and correctly implements the #[source] attribute for error chaining. The design aligns well with the typestate pattern implementation in the broader codebase.

src/server/test_util.rs (1)

36-43: Return type correctly reflects typestate pattern.

The updated return type WireframeServer<F, (), Bound> properly enforces that bind_server returns a bound server, aligning with the typestate pattern implementation.

src/server/runtime.rs (2)

27-58: Typestate implementation correctly enforces binding requirement.

The constraint to WireframeServer<F, T, Bound> ensures compile-time verification that the server is bound before running, and the ServerError return type provides clearer error semantics.


92-104: State destructuring correctly leverages typestate guarantees.

The extraction of the listener from Bound { listener } eliminates the need for runtime checks, as the typestate pattern guarantees the listener's presence at compile time.

src/server/config/mod.rs (1)

15-16: Modularization properly separates binding and preamble concerns.

The introduction of dedicated binding and preamble submodules improves code organization and maintainability, aligning with the single responsibility principle.

src/server/config/binding.rs (2)

14-94: Unbound state implementation correctly handles binding transitions.

The methods properly transition from Unbound to Bound state, preserve configuration across transitions, and use appropriate error handling with ServerError::Bind.


96-179: Bound state implementation provides flexible rebinding capabilities.

The rebinding methods maintain the Bound state while allowing address changes, providing flexibility without sacrificing type safety.

Comment thread src/server/config/mod.rs Outdated
Copy link
Copy Markdown
Contributor

@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: 2

🔭 Outside diff range comments (1)
src/server/config/mod.rs (1)

71-74: Encode non-zero worker invariant at the type level (optional).

Avoid runtime clamping by modelling workers as NonZeroUsize and accepting that in workers(...). This tightens invariants and can catch misuse at compile time.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6eb9e9c and 4816d26.

📒 Files selected for processing (1)
  • src/server/config/mod.rs (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit Inference Engine (AGENTS.md)

**/*.rs: Function documentation must include clear examples demonstrating the usage and outcome of the function. Test documentation should omit examples where the example serves only to reiterate the test logic.
No single code file may be longer than 400 lines. Long switch statements or dispatch tables should be broken up by feature and constituents colocated with targets. Large blocks of test data should be moved to external data files.
Clippy warnings MUST be disallowed.
Fix any warnings emitted during tests in the code itself rather than silencing them.
Where a function is too long, extract meaningfully named helper functions adhering to separation of concerns and CQRS.
Where a function has too many parameters, group related parameters in meaningfully named structs.
Where a function is returning a large error consider using Arc to reduce the amount of data returned.
Write unit and behavioural tests for new functionality. Run both before and after making any change.
Every module must begin with a module level (//! ) comment explaining the module's purpose and utility.
Document public APIs using Rustdoc comments (///) so documentation can be generated with cargo doc.
Prefer immutable data and avoid unnecessary mut bindings.
Handle errors with the Result type instead of panicking where feasible.
Avoid unsafe code unless absolutely necessary and document any usage clearly.
Place function attributes after doc comments.
Do not use return in single-line functions.
Use predicate functions for conditional criteria with more than two branches.
Lints must not be silenced except as a last resort.
Lint rule suppressions must be tightly scoped and include a clear reason.
Prefer expect over allow.
Prefer .expect() over .unwrap().
Use concat!() to combine long string literals rather than escaping newlines with a backslash.
Prefer semantic error enums. Derive std::error::Error (via the thiserror crate) for any condition the caller might inspect, retry, or map to an HTTP status....

Files:

  • src/server/config/mod.rs

⚙️ CodeRabbit Configuration File

**/*.rs: * Seek to keep the cyclomatic complexity of functions no more than 12.

  • Adhere to single responsibility and CQRS

  • Place function attributes after doc comments.

  • Do not use return in single-line functions.

  • Move conditionals with >2 branches into a predicate function.

  • Avoid unsafe unless absolutely necessary.

  • Every module must begin with a //! doc comment that explains the module's purpose and utility.

  • Comments and docs must follow en-GB-oxendict (-ize / -our) spelling and grammar

  • Lints must not be silenced except as a last resort.

    • #[allow] is forbidden.
    • Only narrowly scoped #[expect(lint, reason = "...")] is allowed.
    • No lint groups, no blanket or file-wide suppression.
    • Include FIXME: with link if a fix is expected.
  • Use rstest fixtures for shared setup and to avoid repetition between tests.

  • Replace duplicated tests with #[rstest(...)] parameterised cases.

  • Prefer mockall for mocks/stubs.

  • Prefer .expect() over .unwrap()

  • Ensure that any API or behavioural changes are reflected in the documentation in docs/

  • Ensure that any completed roadmap steps are recorded in the appropriate roadmap in docs/

  • Files must not exceed 400 lines in length

    • Large modules must be decomposed
    • Long match statements or dispatch tables should be decomposed by domain and collocated with targets
    • Large blocks of inline data (e.g., test fixtures, constants or templates) must be moved to external files and inlined at compile-time or loaded at run-time.

Files:

  • src/server/config/mod.rs
🔍 MCP Research (1 server)

Deepwiki:

  • The WireframeServer configuration module was refactored to remove all direct handling of TCP listener binding and preamble callback registration from the main builder interface. The generic parameter S: ServerState is added to the WireframeServer impl, and the new constructor now returns a server explicitly in the Unbound state instead of holding an optional listener. All methods related to preamble customization (with_preamble), preamble decode success and failure callbacks (on_preamble_decode_success, on_preamble_decode_failure), and TCP binding (bind, bind_listener, local_addr) have been removed from this module. Correspondingly, imports related to standard IO errors, socket addresses, TCP listeners, futures, and synchronization primitives like Arc have been removed. The module now only imports tokio::sync::oneshot and internal state types. Two new submodules, binding and preamble, have been introduced to encapsulate the removed functionality. The remaining builder methods focus solely on worker count configuration and ready-signal channel setup. Documentation comments have been updated to reflect that TCP binding and preamble behavior customization are now handled externally via the new submodules. Overall, the configuration API in this file is narrowed to basic server setup without direct TCP binding or preamble callback configuration. (src/server/config/mod.rs)

  • This addition implements binding configuration methods for the WireframeServer type parameterized by a factory F and a preamble type T, supporting both unbound and bound server states. For the unbound server (WireframeServer<F, T, Unbound>), it provides:

    • A local_addr method that always returns None since the server is not yet bound.
    • A bind method that binds the server to a specified socket address by creating a new standard TCP listener and delegating to bind_listener.
    • A bind_listener method that accepts an existing standard TCP listener, sets it to non-blocking mode, converts it to a Tokio TCP listener, and returns a new WireframeServer instance in the bound state with the listener wrapped in an Arc.
      For the bound server (WireframeServer<F, T, Bound>), it provides:
    • A local_addr method that returns the socket address the server is bound to, or None if retrieval fails.
    • A bind method that allows rebinding to a new socket address by creating a new standard TCP listener and delegating to bind_listener.
    • A bind_listener method that allows rebinding using an existing standard TCP listener, similarly setting it to non-blocking, converting to Tokio listener, and returning a new bound server instance.
      All binding methods return a Result with a ServerError variant to handle errors during binding or listener configuration. The server's internal state transitions from unbound to bound by wrapping the Tokio listener in an Arc and storing it in the Bound state. The factory, worker count, preamble handlers, and readiness channel are preserved across these transitions. The code includes documentation and usage examples for each method. (src/server/config/binding.rs)
  • This addition introduces preamble configuration methods for the WireframeServer struct, enabling customization of the connection preamble type and handling. It adds a generic implementation block for WireframeServer parameterized over a factory F, a preamble type T, and a server state S. The new methods include:

    • with_preamble<P>(): Converts the server instance to use a specified preamble type P that implements the Preamble trait, resetting any previously set preamble decode callbacks.
    • on_preamble_decode_success<H>(handler): Registers an asynchronous callback invoked when the connection preamble decodes successfully. The handler receives a reference to the decoded preamble and a mutable reference to the TCP stream, returning a boxed future resolving to an io::Result<()>.
    • on_preamble_decode_failure<H>(handler): Registers a synchronous callback invoked when the preamble decoding fails, receiving a reference to the DecodeError.
      All callbacks are stored internally as Arc-wrapped closures to allow shared ownership and thread safety. The methods use builder-style chaining by returning self or a new WireframeServer instance with updated generic parameters. The code includes documentation and usage examples demonstrating how to specify a custom preamble type and register success and failure handlers. (src/server/config/preamble.rs)
  • A new Rust module src/server/error.rs was added to define error types related to WireframeServer operations. It introduces a public enum ServerError that derives Debug and thiserror::Error. The enum currently has two variants: Bind and Accept, both wrapping an io::Error. The Bind variant represents errors occurring during binding or configuring the listener, with an error message formatted as "bind error: {0}". The Accept variant represents failures during connection acceptance, with an error message formatted as "accept error: {0}". Both variants use the #[source] attribute to indicate the underlying source error. (src/server/error.rs)

🔇 Additional comments (5)
src/server/config/mod.rs (5)

12-18: Module split and imports: LGTM.

Expose binding and preamble as public submodules and restrict imports to what this module uses. This aligns with the typestate split and Deepwiki decisions.


48-49: Initialise typestate to Unbound: LGTM.

Restore explicit typestate instead of optional listener. This is consistent with the compile-time state model.


54-59: Generic state bound over S: ServerState: LGTM.

Expose builder methods for all states via S: ServerState. This matches the intended typestate design.


17-18: No action needed: module-level docs present
Remove this review comment. Both src/server/config/binding.rs and src/server/config/preamble.rs begin with //! module‐level documentation as required.


20-20: Document default preamble in new()

Update the new() method’s documentation in src/server/config/mod.rs to state that it returns a server configured with the unit type (()) as the default preamble.

Verify that () implements the Preamble trait (which requires BorrowDecode<'de, ()>) in this crate.

Comment thread src/server/config/mod.rs Outdated
Comment thread src/server/config/mod.rs Outdated
Copy link
Copy Markdown
Contributor

@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: 2

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4816d26 and f8f61b0.

📒 Files selected for processing (1)
  • src/server/config/mod.rs (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit Inference Engine (AGENTS.md)

**/*.rs: Function documentation must include clear examples demonstrating the usage and outcome of the function. Test documentation should omit examples where the example serves only to reiterate the test logic.
No single code file may be longer than 400 lines. Long switch statements or dispatch tables should be broken up by feature and constituents colocated with targets. Large blocks of test data should be moved to external data files.
Clippy warnings MUST be disallowed.
Fix any warnings emitted during tests in the code itself rather than silencing them.
Where a function is too long, extract meaningfully named helper functions adhering to separation of concerns and CQRS.
Where a function has too many parameters, group related parameters in meaningfully named structs.
Where a function is returning a large error consider using Arc to reduce the amount of data returned.
Write unit and behavioural tests for new functionality. Run both before and after making any change.
Every module must begin with a module level (//! ) comment explaining the module's purpose and utility.
Document public APIs using Rustdoc comments (///) so documentation can be generated with cargo doc.
Prefer immutable data and avoid unnecessary mut bindings.
Handle errors with the Result type instead of panicking where feasible.
Avoid unsafe code unless absolutely necessary and document any usage clearly.
Place function attributes after doc comments.
Do not use return in single-line functions.
Use predicate functions for conditional criteria with more than two branches.
Lints must not be silenced except as a last resort.
Lint rule suppressions must be tightly scoped and include a clear reason.
Prefer expect over allow.
Prefer .expect() over .unwrap().
Use concat!() to combine long string literals rather than escaping newlines with a backslash.
Prefer semantic error enums. Derive std::error::Error (via the thiserror crate) for any condition the caller might inspect, retry, or map to an HTTP status....

Files:

  • src/server/config/mod.rs

⚙️ CodeRabbit Configuration File

**/*.rs: * Seek to keep the cyclomatic complexity of functions no more than 12.

  • Adhere to single responsibility and CQRS

  • Place function attributes after doc comments.

  • Do not use return in single-line functions.

  • Move conditionals with >2 branches into a predicate function.

  • Avoid unsafe unless absolutely necessary.

  • Every module must begin with a //! doc comment that explains the module's purpose and utility.

  • Comments and docs must follow en-GB-oxendict (-ize / -our) spelling and grammar

  • Lints must not be silenced except as a last resort.

    • #[allow] is forbidden.
    • Only narrowly scoped #[expect(lint, reason = "...")] is allowed.
    • No lint groups, no blanket or file-wide suppression.
    • Include FIXME: with link if a fix is expected.
  • Use rstest fixtures for shared setup and to avoid repetition between tests.

  • Replace duplicated tests with #[rstest(...)] parameterised cases.

  • Prefer mockall for mocks/stubs.

  • Prefer .expect() over .unwrap()

  • Ensure that any API or behavioural changes are reflected in the documentation in docs/

  • Ensure that any completed roadmap steps are recorded in the appropriate roadmap in docs/

  • Files must not exceed 400 lines in length

    • Large modules must be decomposed
    • Long match statements or dispatch tables should be decomposed by domain and collocated with targets
    • Large blocks of inline data (e.g., test fixtures, constants or templates) must be moved to external files and inlined at compile-time or loaded at run-time.

Files:

  • src/server/config/mod.rs
🔍 MCP Research (1 server)

Deepwiki:

  • The WireframeServer configuration module (src/server/config/mod.rs) has been simplified by removing all direct handling of TCP listener binding and preamble callback registration from the main builder interface. The generic parameter S: ServerState was added to the WireframeServer impl, and the new constructor now returns a server explicitly in the Unbound state instead of holding an optional listener. Methods related to preamble customization and TCP binding (with_preamble, on_preamble_decode_success, on_preamble_decode_failure, local_addr, bind, bind_listener) were removed. Two new public submodules, binding and preamble, were introduced to encapsulate the removed functionality. Remaining builder methods focus on worker count configuration and ready-signal channel setup. (src/server/config/mod.rs)

  • The src/server/config/binding.rs module adds binding configuration methods for WireframeServer parameterized by factory F and preamble type T, supporting both unbound and bound server states. For unbound servers, it provides local_addr (always None), bind (binds to a socket address), and bind_listener (binds using an existing standard TCP listener). For bound servers, it provides local_addr (returns bound socket address), bind (rebinds to new address), and bind_listener (rebinds using existing listener). All binding methods return Result with a ServerError variant. The server's internal state transitions from unbound to bound by wrapping the Tokio listener in an Arc and storing it in the Bound state. (src/server/config/binding.rs)

  • The src/server/config/preamble.rs module introduces preamble configuration methods for WireframeServer, enabling customization of the connection preamble type and handling. It adds methods with_preamble<P>(), on_preamble_decode_success(handler), and on_preamble_decode_failure(handler). The success callback is asynchronous and receives a reference to the decoded preamble and a mutable TcpStream, returning a boxed future resolving to io::Result. The failure callback is synchronous and receives a reference to the DecodeError. Callbacks are stored internally as Arc-wrapped closures. (src/server/config/preamble.rs)

  • The src/server/config/mod.rs changes include removal of imports related to standard IO errors, socket addresses, TCP listeners, futures, and synchronization primitives like Arc. The module now only imports tokio::sync::oneshot and internal state types. Documentation comments were updated to reflect that TCP binding and preamble behavior customization are now handled externally via the new submodules. (src/server/config/mod.rs)

🔇 Additional comments (4)
src/server/config/mod.rs (4)

20-23: Approve typestate-aware default constructor target.

Defaulting to WireframeServer<F, (), Unbound> is correct and clearly encodes the initial unbound state in the type.


48-48: Approve typestate initialisation.

Initialise state with Unbound to enforce the correct initial typestate.


54-59: Approve impl bounds and generalisation.

Constrain S: ServerState on the generic impl to make builder methods available across server states without leaking binding concerns.


17-18: No action required—both binding.rs and preamble.rs include top-of-file //! comments.

Comment thread src/server/config/mod.rs Outdated
Comment thread src/server/config/mod.rs Outdated
Copy link
Copy Markdown
Contributor

@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: 6

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f8f61b0 and 77245d2.

📒 Files selected for processing (2)
  • src/server/config/mod.rs (2 hunks)
  • src/server/config/preamble.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit Inference Engine (AGENTS.md)

**/*.rs: Function documentation must include clear examples demonstrating the usage and outcome of the function. Test documentation should omit examples where the example serves only to reiterate the test logic.
No single code file may be longer than 400 lines. Long switch statements or dispatch tables should be broken up by feature and constituents colocated with targets. Large blocks of test data should be moved to external data files.
Clippy warnings MUST be disallowed.
Fix any warnings emitted during tests in the code itself rather than silencing them.
Where a function is too long, extract meaningfully named helper functions adhering to separation of concerns and CQRS.
Where a function has too many parameters, group related parameters in meaningfully named structs.
Where a function is returning a large error consider using Arc to reduce the amount of data returned.
Write unit and behavioural tests for new functionality. Run both before and after making any change.
Every module must begin with a module level (//! ) comment explaining the module's purpose and utility.
Document public APIs using Rustdoc comments (///) so documentation can be generated with cargo doc.
Prefer immutable data and avoid unnecessary mut bindings.
Handle errors with the Result type instead of panicking where feasible.
Avoid unsafe code unless absolutely necessary and document any usage clearly.
Place function attributes after doc comments.
Do not use return in single-line functions.
Use predicate functions for conditional criteria with more than two branches.
Lints must not be silenced except as a last resort.
Lint rule suppressions must be tightly scoped and include a clear reason.
Prefer expect over allow.
Prefer .expect() over .unwrap().
Use concat!() to combine long string literals rather than escaping newlines with a backslash.
Prefer semantic error enums. Derive std::error::Error (via the thiserror crate) for any condition the caller might inspect, retry, or map to an HTTP status....

Files:

  • src/server/config/mod.rs
  • src/server/config/preamble.rs

⚙️ CodeRabbit Configuration File

**/*.rs: * Seek to keep the cyclomatic complexity of functions no more than 12.

  • Adhere to single responsibility and CQRS

  • Place function attributes after doc comments.

  • Do not use return in single-line functions.

  • Move conditionals with >2 branches into a predicate function.

  • Avoid unsafe unless absolutely necessary.

  • Every module must begin with a //! doc comment that explains the module's purpose and utility.

  • Comments and docs must follow en-GB-oxendict (-ize / -our) spelling and grammar

  • Lints must not be silenced except as a last resort.

    • #[allow] is forbidden.
    • Only narrowly scoped #[expect(lint, reason = "...")] is allowed.
    • No lint groups, no blanket or file-wide suppression.
    • Include FIXME: with link if a fix is expected.
  • Use rstest fixtures for shared setup and to avoid repetition between tests.

  • Replace duplicated tests with #[rstest(...)] parameterised cases.

  • Prefer mockall for mocks/stubs.

  • Prefer .expect() over .unwrap()

  • Ensure that any API or behavioural changes are reflected in the documentation in docs/

  • Ensure that any completed roadmap steps are recorded in the appropriate roadmap in docs/

  • Files must not exceed 400 lines in length

    • Large modules must be decomposed
    • Long match statements or dispatch tables should be decomposed by domain and collocated with targets
    • Large blocks of inline data (e.g., test fixtures, constants or templates) must be moved to external files and inlined at compile-time or loaded at run-time.

Files:

  • src/server/config/mod.rs
  • src/server/config/preamble.rs
🧬 Code Graph Analysis (1)
src/server/config/preamble.rs (1)
src/server/test_util.rs (1)
  • WireframeServer (54-54)
🔍 MCP Research (1 server)

Deepwiki:

  • The WireframeServer configuration module was refactored to remove all direct TCP listener binding and preamble callback registration from the main builder interface. The WireframeServer struct now has a generic parameter S: ServerState representing the server's binding state. The new constructor returns a server in the Unbound state. Methods related to preamble customization and TCP binding (with_preamble, on_preamble_decode_success, on_preamble_decode_failure, local_addr, bind, bind_listener) were removed from this module. Two new public submodules, binding and preamble, were introduced to encapsulate the removed functionality. The remaining builder methods focus on worker count and ready-signal channel setup, implemented via macros. This narrows the configuration API to basic server setup without direct TCP binding or preamble callback configuration. (src/server/config/mod.rs)

  • This addition introduces preamble configuration methods for WireframeServer, enabling customization of the connection preamble type and handling. It adds generic implementations for WireframeServer<F, T, S> with methods:

    • with_preamble<P>() to specify a preamble type implementing the Preamble trait, resetting any previously set preamble decode callbacks.
    • on_preamble_decode_success<H>(handler) to register an async callback invoked on successful preamble decode.
    • on_preamble_decode_failure<H>(handler) to register a synchronous callback invoked on preamble decode failure.
      All callbacks are stored as Arc-wrapped closures for thread safety. The methods use builder-style chaining and include documentation and usage examples. (src/server/config/preamble.rs)
  • This addition implements binding configuration methods for WireframeServer<F, T, Unbound> and WireframeServer<F, T, Bound>. For the unbound server, it provides:

    • local_addr() returning None since not bound.
    • bind(addr) to bind to a socket address by creating a standard TCP listener and delegating to bind_listener.
    • bind_listener(std) to accept an existing standard TCP listener, set it non-blocking, convert to Tokio TCP listener, and return a new bound server instance.
      For the bound server, it provides:
    • local_addr() returning the bound socket address or None on failure.
    • bind(addr) and bind_listener(std) to rebind to a new address or listener.
      All binding methods return Result with a ServerError variant for error handling. The server transitions from unbound to bound state by wrapping the Tokio listener in an Arc. The factory, worker count, preamble handlers, and readiness channel are preserved across transitions. Documentation and usage examples are included. (src/server/config/binding.rs)
  • A new module defining the ServerError enum was added. It derives Debug and thiserror::Error and has two variants:

    • Bind(io::Error) representing errors during binding or listener configuration, with error message "bind error: {0}".
    • Accept(io::Error) representing failures during connection acceptance, with error message "accept error: {0}".
      Both variants use the #[source] attribute to indicate the underlying source error. (src/server/error.rs)
🔇 Additional comments (7)
src/server/config/preamble.rs (2)

1-1: Module-level docs meet guidelines

Keep this. It satisfies the “every module must begin with //!” rule and succinctly scopes the module.


34-48: with_preamble: correct state-preserving conversion; reset callbacks as intended

The typestate-preserving rebuild is correct and the reset of both callbacks is appropriate.

src/server/config/mod.rs (5)

4-9: Docs: clear, linked, and en‑GB compliant

The module‑level docs clearly separate responsibilities, use intra‑doc links, and follow the -ize/-our rule. Keep this.


18-27: Builder setter macro: OK

The setter macro is minimal, attributes are placed after doc comments, and it returns Self for fluent chaining.


46-79: Constructor: typestate initialisation and defaults look correct

Initialise to Unbound, clamp workers via available_parallelism with safe fallback, and default callback fields and ready_tx to None. Matches the typestate design.


101-114: ready_signal(): clear API and example

Accept oneshot::Sender<()> and store as Some(tx); this is straightforward and documented.


4-9: Remove the verification request – intra-doc links resolve correctly
The bind and bind_listener methods on WireframeServer<_,_,Unbound> live in src/server/config/binding.rs and the Unbound typestate lives in src/server/mod.rs. Rustdoc will correctly resolve bind, bind_listener, and [Unbound].

Comment thread src/server/config/mod.rs
Comment thread src/server/config/mod.rs
Comment thread src/server/config/preamble.rs
Comment thread src/server/config/preamble.rs Outdated
Comment thread src/server/config/preamble.rs
Comment thread src/server/config/preamble.rs
Copy link
Copy Markdown
Contributor

@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: 5

♻️ Duplicate comments (2)
src/server/config/preamble.rs (1)

74-75: Reuse the PreambleSuccessHandler alias.
Replace the long for<'a> Fn … bound with the crate::server::PreambleSuccessHandler<T> alias to keep the API surface tidy and avoid future drift.

src/server/config/mod.rs (1)

29-41: Fully qualify Arc in macro expansion

Good fix; this de-couples call sites from needing use Arc.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 77245d2 and 7f167c0.

📒 Files selected for processing (4)
  • src/server/config/mod.rs (2 hunks)
  • src/server/config/preamble.rs (1 hunks)
  • src/server/mod.rs (3 hunks)
  • tests/preamble.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit Inference Engine (AGENTS.md)

**/*.rs: Function documentation must include clear examples demonstrating the usage and outcome of the function. Test documentation should omit examples where the example serves only to reiterate the test logic.
No single code file may be longer than 400 lines. Long switch statements or dispatch tables should be broken up by feature and constituents colocated with targets. Large blocks of test data should be moved to external data files.
Clippy warnings MUST be disallowed.
Fix any warnings emitted during tests in the code itself rather than silencing them.
Where a function is too long, extract meaningfully named helper functions adhering to separation of concerns and CQRS.
Where a function has too many parameters, group related parameters in meaningfully named structs.
Where a function is returning a large error consider using Arc to reduce the amount of data returned.
Write unit and behavioural tests for new functionality. Run both before and after making any change.
Every module must begin with a module level (//! ) comment explaining the module's purpose and utility.
Document public APIs using Rustdoc comments (///) so documentation can be generated with cargo doc.
Prefer immutable data and avoid unnecessary mut bindings.
Handle errors with the Result type instead of panicking where feasible.
Avoid unsafe code unless absolutely necessary and document any usage clearly.
Place function attributes after doc comments.
Do not use return in single-line functions.
Use predicate functions for conditional criteria with more than two branches.
Lints must not be silenced except as a last resort.
Lint rule suppressions must be tightly scoped and include a clear reason.
Prefer expect over allow.
Prefer .expect() over .unwrap().
Use concat!() to combine long string literals rather than escaping newlines with a backslash.
Prefer semantic error enums. Derive std::error::Error (via the thiserror crate) for any condition the caller might inspect, retry, or map to an HTTP status....

Files:

  • tests/preamble.rs
  • src/server/mod.rs
  • src/server/config/preamble.rs
  • src/server/config/mod.rs

⚙️ CodeRabbit Configuration File

**/*.rs: * Seek to keep the cyclomatic complexity of functions no more than 12.

  • Adhere to single responsibility and CQRS

  • Place function attributes after doc comments.

  • Do not use return in single-line functions.

  • Move conditionals with >2 branches into a predicate function.

  • Avoid unsafe unless absolutely necessary.

  • Every module must begin with a //! doc comment that explains the module's purpose and utility.

  • Comments and docs must follow en-GB-oxendict (-ize / -our) spelling and grammar

  • Lints must not be silenced except as a last resort.

    • #[allow] is forbidden.
    • Only narrowly scoped #[expect(lint, reason = "...")] is allowed.
    • No lint groups, no blanket or file-wide suppression.
    • Include FIXME: with link if a fix is expected.
  • Use rstest fixtures for shared setup and to avoid repetition between tests.

  • Replace duplicated tests with #[rstest(...)] parameterised cases.

  • Prefer mockall for mocks/stubs.

  • Prefer .expect() over .unwrap()

  • Ensure that any API or behavioural changes are reflected in the documentation in docs/

  • Ensure that any completed roadmap steps are recorded in the appropriate roadmap in docs/

  • Files must not exceed 400 lines in length

    • Large modules must be decomposed
    • Long match statements or dispatch tables should be decomposed by domain and collocated with targets
    • Large blocks of inline data (e.g., test fixtures, constants or templates) must be moved to external files and inlined at compile-time or loaded at run-time.

Files:

  • tests/preamble.rs
  • src/server/mod.rs
  • src/server/config/preamble.rs
  • src/server/config/mod.rs
🧬 Code Graph Analysis (3)
src/server/mod.rs (1)
tests/preamble.rs (2)
  • WireframeServer (53-55)
  • WireframeServer (234-256)
src/server/config/preamble.rs (2)
tests/preamble.rs (6)
  • WireframeServer (53-55)
  • WireframeServer (234-256)
  • tokio (129-129)
  • tokio (130-130)
  • tokio (228-228)
  • tokio (229-229)
src/server/test_util.rs (1)
  • WireframeServer (54-54)
src/server/config/mod.rs (2)
tests/preamble.rs (7)
  • tokio (129-129)
  • tokio (130-130)
  • tokio (228-228)
  • tokio (229-229)
  • oneshot (71-71)
  • WireframeServer (53-55)
  • WireframeServer (234-256)
src/server/config/tests.rs (2)
  • WireframeServer (60-60)
  • WireframeServer (135-137)
🔍 MCP Research (1 server)

Deepwiki:

  • The WireframeServer configuration module was refactored to remove direct TCP binding and preamble callback registration from the main builder interface, moving these into new public submodules binding and preamble. The server now uses a generic parameter S: ServerState to represent binding state, with the constructor returning an unbound server. (src/server/config/mod.rs)

  • The addition of src/server/config/preamble.rs introduces preamble configuration methods for WireframeServer, allowing specification of the preamble type and registration of asynchronous success and synchronous failure callbacks stored as Arc closures, supporting builder-style chaining and resetting previous callbacks when changing the preamble type. (src/server/config/preamble.rs)

  • The addition of src/server/config/binding.rs implements binding configuration methods for WireframeServer supporting unbound and bound server states, with methods like bind and bind_listener transitioning the server state and returning Result with a new ServerError type for error handling. (src/server/config/binding.rs)

  • The WireframeServer struct was extended with a generic parameter S: ServerState representing binding state, replacing the optional listener field with a state field holding either Unbound or Bound marker structs. The preamble success callback type alias was split into a new async handler type alias. A new error module was added, and runtime methods now return Result<(), ServerError>. (src/server/mod.rs)

🔇 Additional comments (7)
src/server/config/mod.rs (7)

4-9: Module-level docs: clear responsibilities and correct intra-doc links

Keep this; the module docs correctly link to binding/preamble and use en-GB with -ize/-our spelling.


18-27: Builder setter macro: sound and idiomatic

Retain this; #[must_use] on fluent setters is correct and assignment via $assign keeps call sites concise.


43-44: Expose binding and preamble as public submodules

Good split that aligns with the typestate design and documented responsibilities.


53-56: Constructor docs: link Unbound and binding methods

Docs precisely describe the initial typestate and provide navigable links to bind/bind_listener.


68-76: Initialise workers and typestate robustly

Using available_parallelism().map_or(1, NonZeroUsize::get) guarantees a sensible default; setting state: Unbound matches the constructor docs.


106-119: ready_signal(): focused API and example

The API surface is clear; the example uses tokio::sync::oneshot as intended. Keep as-is.


131-134: worker_count(): const, inline, and side-effect free

The accessor meets style guidance (no return in single-line functions) and is marked #[must_use]. LGTM.

Comment thread src/server/config/mod.rs Outdated
Comment thread src/server/config/mod.rs
Comment thread src/server/mod.rs Outdated
Comment thread tests/preamble.rs
Comment thread tests/preamble.rs
Copy link
Copy Markdown

@codescene-delta-analysis codescene-delta-analysis Bot left a comment

Choose a reason for hiding this comment

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

Gates Failed
Prevent hotspot decline (1 hotspot with Large Method)
Enforce advisory code health rules (1 file with Large Method)

Gates Passed
4 Quality Gates Passed

See analysis details in CodeScene

Reason for failure
Prevent hotspot decline Violations Code Health Impact
preamble.rs 1 rule in this hotspot 10.00 → 9.51 Suppress
Enforce advisory code health rules Violations Code Health Impact
preamble.rs 1 advisory rule 10.00 → 9.51 Suppress

Quality Gate Profile: Pay Down Tech Debt
Want more control? Customize Code Health rules or catch issues early with our IDE extension and CLI tool.

Comment thread tests/preamble.rs
Comment thread tests/preamble.rs
Copy link
Copy Markdown
Contributor

@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: 2

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7f167c0 and dabe6cc.

📒 Files selected for processing (3)
  • src/server/config/preamble.rs (1 hunks)
  • src/server/mod.rs (3 hunks)
  • tests/preamble.rs (3 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit Inference Engine (AGENTS.md)

**/*.rs: Function documentation must include clear examples demonstrating the usage and outcome of the function. Test documentation should omit examples where the example serves only to reiterate the test logic.
No single code file may be longer than 400 lines. Long switch statements or dispatch tables should be broken up by feature and constituents colocated with targets. Large blocks of test data should be moved to external data files.
Clippy warnings MUST be disallowed.
Fix any warnings emitted during tests in the code itself rather than silencing them.
Where a function is too long, extract meaningfully named helper functions adhering to separation of concerns and CQRS.
Where a function has too many parameters, group related parameters in meaningfully named structs.
Where a function is returning a large error consider using Arc to reduce the amount of data returned.
Write unit and behavioural tests for new functionality. Run both before and after making any change.
Every module must begin with a module level (//! ) comment explaining the module's purpose and utility.
Document public APIs using Rustdoc comments (///) so documentation can be generated with cargo doc.
Prefer immutable data and avoid unnecessary mut bindings.
Handle errors with the Result type instead of panicking where feasible.
Avoid unsafe code unless absolutely necessary and document any usage clearly.
Place function attributes after doc comments.
Do not use return in single-line functions.
Use predicate functions for conditional criteria with more than two branches.
Lints must not be silenced except as a last resort.
Lint rule suppressions must be tightly scoped and include a clear reason.
Prefer expect over allow.
Prefer .expect() over .unwrap().
Use concat!() to combine long string literals rather than escaping newlines with a backslash.
Prefer semantic error enums. Derive std::error::Error (via the thiserror crate) for any condition the caller might inspect, retry, or map to an HTTP status....

Files:

  • tests/preamble.rs
  • src/server/config/preamble.rs
  • src/server/mod.rs

⚙️ CodeRabbit Configuration File

**/*.rs: * Seek to keep the cyclomatic complexity of functions no more than 12.

  • Adhere to single responsibility and CQRS

  • Place function attributes after doc comments.

  • Do not use return in single-line functions.

  • Move conditionals with >2 branches into a predicate function.

  • Avoid unsafe unless absolutely necessary.

  • Every module must begin with a //! doc comment that explains the module's purpose and utility.

  • Comments and docs must follow en-GB-oxendict (-ize / -our) spelling and grammar

  • Lints must not be silenced except as a last resort.

    • #[allow] is forbidden.
    • Only narrowly scoped #[expect(lint, reason = "...")] is allowed.
    • No lint groups, no blanket or file-wide suppression.
    • Include FIXME: with link if a fix is expected.
  • Use rstest fixtures for shared setup and to avoid repetition between tests.

  • Replace duplicated tests with #[rstest(...)] parameterised cases.

  • Prefer mockall for mocks/stubs.

  • Prefer .expect() over .unwrap()

  • Ensure that any API or behavioural changes are reflected in the documentation in docs/

  • Ensure that any completed roadmap steps are recorded in the appropriate roadmap in docs/

  • Files must not exceed 400 lines in length

    • Large modules must be decomposed
    • Long match statements or dispatch tables should be decomposed by domain and collocated with targets
    • Large blocks of inline data (e.g., test fixtures, constants or templates) must be moved to external files and inlined at compile-time or loaded at run-time.

Files:

  • tests/preamble.rs
  • src/server/config/preamble.rs
  • src/server/mod.rs
🧬 Code Graph Analysis (2)
src/server/config/preamble.rs (2)
tests/preamble.rs (2)
  • WireframeServer (53-55)
  • WireframeServer (238-260)
src/server/test_util.rs (1)
  • WireframeServer (54-54)
src/server/mod.rs (3)
tests/preamble.rs (2)
  • WireframeServer (53-55)
  • WireframeServer (238-260)
src/server/config/tests.rs (2)
  • WireframeServer (60-60)
  • WireframeServer (135-137)
src/server/test_util.rs (1)
  • WireframeServer (54-54)
🔍 MCP Research (2 servers)

Deepwiki:

  • Document src/server/config/preamble.rs introduces preamble configuration methods for WireframeServer, enabling customization of connection preamble type and handling. It adds methods with_preamble<P>() to specify a preamble type, on_preamble_decode_success<H>(handler) to register async callbacks on successful preamble decode, and on_preamble_decode_failure<H>(handler) to register sync callbacks on decode failure. Callbacks are stored as Arc closures for thread safety. (src/server/config/preamble.rs)

  • Document src/server/mod.rs shows that WireframeServer struct is extended with a generic parameter S: ServerState representing binding state, replacing the optional listener field with a state field. Marker structs Unbound and Bound represent server states, with Bound holding the listener. The PreambleCallback type alias is replaced by a trait PreambleSuccessHandler<T>. The module adds a new error module and re-exports config submodules binding and preamble. (src/server/mod.rs)

  • Document src/server/config/binding.rs implements binding configuration methods for WireframeServer<F, T, Unbound> and WireframeServer<F, T, Bound>. For unbound servers, local_addr() returns None, bind() binds to a socket address creating a standard TCP listener, and bind_listener() accepts an existing listener, sets non-blocking mode, converts to Tokio listener, and returns a bound server instance. For bound servers, local_addr() returns the bound address, and bind() and bind_listener() allow rebinding. All methods return Result with ServerError for error handling. (src/server/config/binding.rs)

  • Document src/server/error.rs adds a new enum ServerError with variants Bind(io::Error) for binding/configuration errors and Accept(io::Error) for connection acceptance failures. It derives thiserror::Error for error handling. (src/server/error.rs)

Context7:

  • The server configuration module was refactored to remove direct TCP listener binding and preamble callback registration from the main builder interface, introducing generic server state tracking with Unbound and Bound typestates. Binding and preamble logic were moved to new submodules binding and preamble, respectively, narrowing the configuration API to basic server setup without direct binding or preamble callback configuration. This modularization improves clarity and enforces compile-time state correctness. (src/server/config/mod.rs)

  • The preamble configuration API was extended with methods to specify a custom preamble type and register asynchronous success and synchronous failure callbacks. These callbacks are stored as Arc-wrapped closures for thread safety. The API uses builder-style chaining and supports resetting callbacks when changing preamble types. (src/server/config/preamble.rs)

  • A new ServerError enum was introduced to replace io::Error in server operations, with variants for binding and accepting errors. This change is reflected in runtime methods, which now return Result<(), ServerError> instead of io::Result<()>. (src/server/error.rs, src/server/runtime.rs)

  • The WireframeServer struct was extended with a generic parameter S constrained by a ServerState trait, replacing the optional listener field with a state field of type S. Marker structs Unbound and Bound represent the server's binding state, with Bound containing the listener wrapped in an Arc. This typestate pattern enforces compile-time correctness of server binding state. (src/server/mod.rs)

  • Tests in tests/preamble.rs were enhanced to verify that callbacks associated with overridden preamble types are properly dropped, ensuring correct callback invocation behavior when changing preamble configurations. (tests/preamble.rs)

⏰ Context from checks skipped due to timeout of 120000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-test
🔇 Additional comments (8)
tests/preamble.rs (2)

173-176: Raise negative-assertion timeout to 500 ms — LGTM

Increase the window for the absent-callback assertion to reduce CI flakiness. This aligns with prior feedback.


184-187: Raise negative-assertion timeout to 500 ms — LGTM

Harden the test against scheduler jitter by widening the timeout for the opposite callback. Good change.

src/server/config/preamble.rs (3)

20-52: with_preamble: correct typestate-preserving swap and explicit callback reset docs — LGTM

Preserve the binding state S, reset both callbacks, and document usage with an example. Attribute placement and module docs meet guidelines.


54-77: on_preamble_decode_success: clean handler bound and example — LGTM

Use the PreambleSuccessHandler<T> trait to reduce type noise and document the async handler shape clearly. Matches the refactor intent.


79-99: on_preamble_decode_failure: link the error type and show usage — LGTM

Document the sync failure handler with an intra-doc link to bincode::error::DecodeError. Compliant with doc and example requirements.

src/server/mod.rs (3)

16-35: Define an object-safe async handler trait for preamble success — LGTM

Keep the handler object-safe and sendable via Arc<dyn …>. Docs clarify permitted I/O before handoff.


78-91: Document typestate markers and trait — LGTM

Describe Unbound, Bound, and ServerState clearly; this satisfies public-API documentation requirements and improves discoverability.


93-95: Re-export binding and preamble config modules — LGTM

Expose the split configuration surface from server, aligning with the modular design.

Comment thread src/server/mod.rs
Comment thread tests/preamble.rs
Copy link
Copy Markdown
Contributor

@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

♻️ Duplicate comments (3)
src/server/mod.rs (1)

49-58: Verify default T=() satisfies the Preamble bound; adjust if not

The comment asserts that () already satisfies Preamble via bincode, but this depends on the presence of the required BorrowDecode/blanket impls. Validate to avoid surprises when constructing WireframeServer::new(factory) without .with_preamble().

Run:

#!/bin/bash
# 1) Find the Preamble trait and any blanket impls that might cover `()`.
rg -n $'trait\\s+Preamble\\b' -A 20
rg -n $'impl<[^>]*>\\s+Preamble\\b' -A 10

# 2) Check whether bincode provides BorrowDecode or Decode for unit that your Preamble bound relies on.
rg -n $'impl\\s+BorrowDecode\\b.*for\\s*\\(\\)' -A 2
rg -n $'impl\\s+Decode\\b.*for\\s*\\(\\)' -A 2

# 3) Grep for local impls that might cover unit.
rg -n $'impl\\s+Preamble\\s+for\\s*\\(\\)' -A 2

If () does not satisfy the bound:

  • Option A (preferred): Introduce a zero-sized NoPreamble type in your preamble module that implements Preamble, and change the default to T = NoPreamble.
  • Option B: Provide an explicit impl Preamble for () { /* … */ } if allowed by your trait’s requirements.

I can supply a patch for Option A on request.

tests/preamble.rs (2)

176-179: Approve increased timeouts to de-flake tests

Raising the “should not receive” timeouts to 500 ms matches earlier feedback and improves robustness under scheduler jitter.

Also applies to: 187-190


258-310: Approve: deterministic synchronisation and clear assertions

Await the success signal inside with_running_server to avoid arbitrary sleeps; then assert that all stale/incorrect callbacks were not invoked. This is precise and deterministic.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dabe6cc and c479a3d.

📒 Files selected for processing (2)
  • src/server/mod.rs (3 hunks)
  • tests/preamble.rs (4 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit Inference Engine (AGENTS.md)

**/*.rs: Function documentation must include clear examples demonstrating the usage and outcome of the function. Test documentation should omit examples where the example serves only to reiterate the test logic.
No single code file may be longer than 400 lines. Long switch statements or dispatch tables should be broken up by feature and constituents colocated with targets. Large blocks of test data should be moved to external data files.
Clippy warnings MUST be disallowed.
Fix any warnings emitted during tests in the code itself rather than silencing them.
Where a function is too long, extract meaningfully named helper functions adhering to separation of concerns and CQRS.
Where a function has too many parameters, group related parameters in meaningfully named structs.
Where a function is returning a large error consider using Arc to reduce the amount of data returned.
Write unit and behavioural tests for new functionality. Run both before and after making any change.
Every module must begin with a module level (//! ) comment explaining the module's purpose and utility.
Document public APIs using Rustdoc comments (///) so documentation can be generated with cargo doc.
Prefer immutable data and avoid unnecessary mut bindings.
Handle errors with the Result type instead of panicking where feasible.
Avoid unsafe code unless absolutely necessary and document any usage clearly.
Place function attributes after doc comments.
Do not use return in single-line functions.
Use predicate functions for conditional criteria with more than two branches.
Lints must not be silenced except as a last resort.
Lint rule suppressions must be tightly scoped and include a clear reason.
Prefer expect over allow.
Prefer .expect() over .unwrap().
Use concat!() to combine long string literals rather than escaping newlines with a backslash.
Prefer semantic error enums. Derive std::error::Error (via the thiserror crate) for any condition the caller might inspect, retry, or map to an HTTP status....

Files:

  • tests/preamble.rs
  • src/server/mod.rs

⚙️ CodeRabbit Configuration File

**/*.rs: * Seek to keep the cyclomatic complexity of functions no more than 12.

  • Adhere to single responsibility and CQRS

  • Place function attributes after doc comments.

  • Do not use return in single-line functions.

  • Move conditionals with >2 branches into a predicate function.

  • Avoid unsafe unless absolutely necessary.

  • Every module must begin with a //! doc comment that explains the module's purpose and utility.

  • Comments and docs must follow en-GB-oxendict (-ize / -our) spelling and grammar

  • Lints must not be silenced except as a last resort.

    • #[allow] is forbidden.
    • Only narrowly scoped #[expect(lint, reason = "...")] is allowed.
    • No lint groups, no blanket or file-wide suppression.
    • Include FIXME: with link if a fix is expected.
  • Use rstest fixtures for shared setup and to avoid repetition between tests.

  • Replace duplicated tests with #[rstest(...)] parameterised cases.

  • Prefer mockall for mocks/stubs.

  • Prefer .expect() over .unwrap()

  • Ensure that any API or behavioural changes are reflected in the documentation in docs/

  • Ensure that any completed roadmap steps are recorded in the appropriate roadmap in docs/

  • Files must not exceed 400 lines in length

    • Large modules must be decomposed
    • Long match statements or dispatch tables should be decomposed by domain and collocated with targets
    • Large blocks of inline data (e.g., test fixtures, constants or templates) must be moved to external files and inlined at compile-time or loaded at run-time.

Files:

  • tests/preamble.rs
  • src/server/mod.rs
🧬 Code Graph Analysis (1)
src/server/mod.rs (3)
tests/preamble.rs (4)
  • tokio (132-132)
  • tokio (133-133)
  • WireframeServer (56-58)
  • WireframeServer (268-272)
src/server/test_util.rs (1)
  • WireframeServer (54-54)
src/server/config/tests.rs (2)
  • WireframeServer (60-60)
  • WireframeServer (135-137)
🔍 MCP Research (1 server)

Deepwiki:

  • The WireframeServer struct was extended with a new generic parameter S constrained by a new trait ServerState. The previous optional listener field was replaced by a state field of type S. Two new marker structs, Unbound and Bound, were introduced to represent the server's binding state, with Bound containing the listener. The ServerState trait is implemented for both marker structs. The type alias PreambleCallback<T> was replaced by a new trait PreambleSuccessHandler<T>, which defines the signature for handlers invoked upon successful preamble decoding. This trait requires implementors to be async functions taking a reference to T and a mutable TCP stream, returning a boxed future of an I/O result, and to be Send, Sync, and 'static. The original PreambleCallback<T> is now an Arc wrapping a dyn PreambleSuccessHandler<T>. The documentation was updated to refer to "handler" and "implementors" instead of "callback." A new public module error was added, and the config module's binding and preamble submodules were re-exported. (src/server/mod.rs)

  • The WireframeServer configuration module was refactored to remove all direct handling of TCP listener binding and preamble callback registration from the main builder interface. The generic parameter S: ServerState is added to the WireframeServer impl, and the new constructor now returns a server explicitly in the Unbound state instead of holding an optional listener. All methods related to preamble customization (with_preamble), preamble decode success and failure callbacks (on_preamble_decode_success, on_preamble_decode_failure), and TCP binding (bind, bind_listener, local_addr) have been removed from this module. Correspondingly, imports related to standard IO errors, socket addresses, TCP listeners, futures, and synchronization primitives like Arc have been removed. The module now only imports tokio::sync::oneshot and internal state types. Two new public submodules, binding and preamble, have been introduced to encapsulate the removed functionality. The remaining builder methods focus solely on worker count configuration and ready-signal channel setup, implemented via macros for setter generation. Documentation comments have been updated to reflect that TCP binding and preamble behavior customization are now handled externally via the new submodules. Overall, the configuration API in this file is narrowed to basic server setup without direct TCP binding or preamble callback configuration. (src/server/config/mod.rs)

  • This addition implements binding configuration methods for the WireframeServer type parameterized by a factory F and a preamble type T, supporting both unbound and bound server states. For the unbound server (WireframeServer<F, T, Unbound>), it provides:

    • A local_addr method that always returns None since the server is not yet bound.
    • A bind method that binds the server to a specified socket address by creating a new standard TCP listener and delegating to bind_listener.
    • A bind_listener method that accepts an existing standard TCP listener, sets it to non-blocking mode, converts it to a Tokio TCP listener, and returns a new WireframeServer instance in the bound state with the listener wrapped in an Arc.
      For the bound server (WireframeServer<F, T, Bound>), it provides:
    • A local_addr method that returns the socket address the server is bound to, or None if retrieval fails.
    • A bind method that allows rebinding to a new socket address by creating a new standard TCP listener and delegating to bind_listener.
    • A bind_listener method that allows rebinding using an existing standard TCP listener, similarly setting it to non-blocking, converting to Tokio listener, and returning a new bound server instance.
      All binding methods return a Result with a ServerError variant to handle errors during binding or listener configuration. The server's internal state transitions from unbound to bound by wrapping the Tokio listener in an Arc and storing it in the Bound state. The factory, worker count, preamble handlers, and readiness channel are preserved across these transitions. The code includes documentation and usage examples for each method. (src/server/config/binding.rs)
  • This addition introduces preamble configuration methods for the WireframeServer struct, enabling customization of the connection preamble type and handling. It adds a generic implementation block for WireframeServer parameterized over a factory F, a preamble type T, and a server state S. The new methods include:

    • with_preamble<P>(): Converts the server instance to use a specified preamble type P that implements the Preamble trait, resetting any previously set preamble decode callbacks.
    • on_preamble_decode_success<H>(handler): Registers an asynchronous callback invoked when the connection preamble decodes successfully. The handler receives a reference to the decoded preamble and a mutable reference to the TCP stream, returning a boxed future resolving to an io::Result<()>.
    • on_preamble_decode_failure<H>(handler): Registers a synchronous callback invoked when the preamble decoding fails, receiving a reference to the DecodeError.
      All callbacks are stored internally as Arc-wrapped closures to allow shared ownership and thread safety. The methods use builder-style chaining by returning self or a new WireframeServer instance with updated generic parameters. The code includes documentation and usage examples demonstrating how to specify a custom preamble type and register success and failure handlers. (src/server/config/preamble.rs)
🔇 Additional comments (8)
src/server/mod.rs (7)

28-35: LGTM: blanket impl for handler trait is correct

The blanket impl correctly mirrors the trait bounds and remains object-safe via the Fn bound.


36-37: LGTM: alias preserves ergonomic storage

Wrapping the handler trait in Arc keeps registration ergonomic and thread-safe.


76-76: LGTM: typestate field integrates cleanly

state: S correctly replaces the optional listener and pins the typestate at the type level.


80-87: LGTM: marker types are minimal and documented

Unbound/Bound are clear; wrapping the listener in Arc<TcpListener> aligns with shared runtime access.


88-93: LGTM: ServerState trait and impls complete the typestate pattern

The zero-method trait keeps the API lean while enforcing state tracking at compile time.


95-95: LGTM: re-export configuration modules

Re-exporting binding and preamble clarifies the public API surface and supports discoverability.


97-97: LGTM: public error module enables semantic errors

Exposing error matches the guideline to prefer semantic error enums and thiserror derivations.

tests/preamble.rs (1)

223-231: LGTM: helper types and closures reduce duplication and keep assertions crisp

OtherPreamble, Holder, channel_holder, success_cb, and failure_cb neatly encapsulate boilerplate; the closures meet the required bounds and use .expect() per policy.

Also applies to: 233-246, 248-256

Comment thread src/server/mod.rs
@leynos leynos force-pushed the codex/address-code-review-comments branch from 428862b to da6dd67 Compare August 9, 2025 18:30
Copy link
Copy Markdown
Contributor

@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: 6

🔭 Outside diff range comments (2)
src/server/config/tests.rs (1)

98-118: Eliminate runtime panics by typing the test case instead of using &str.

Replace the stringly typed handler_type: &str with a small enum to remove the default arm and unreachable/panic paths.

Apply this diff:

-async fn test_preamble_handler_registration(
-    factory: impl Fn() -> WireframeApp + Send + Sync + Clone + 'static,
-    #[case] handler_type: &str,
-) {
+async fn test_preamble_handler_registration(
+    factory: impl Fn() -> WireframeApp + Send + Sync + Clone + 'static,
+    #[case] handler: HandlerKind,
+) {
@@
-    let server = match handler_type {
+    let server = match handler {
-        "success" => server.on_preamble_decode_success(move |_p: &TestPreamble, _| {
+        HandlerKind::Success => server.on_preamble_decode_success(move |_p: &TestPreamble, _| {
@@
-        "failure" => server.on_preamble_decode_failure(move |_err: &DecodeError| {
+        HandlerKind::Failure => server.on_preamble_decode_failure(move |_err: &DecodeError| {
@@
-        _ => panic!("Invalid handler type"),
     };
@@
-    match handler_type {
-        "success" => assert!(server.on_preamble_success.is_some()),
-        "failure" => assert!(server.on_preamble_failure.is_some()),
-        _ => unreachable!(),
+    match handler {
+        HandlerKind::Success => assert!(server.on_preamble_success.is_some()),
+        HandlerKind::Failure => assert!(server.on_preamble_failure.is_some()),
     }

Add this outside the shown hunk:

#[derive(Clone, Copy)]
enum HandlerKind { Success, Failure }

#[rstest]
#[case(HandlerKind::Success)]
#[case(HandlerKind::Failure)]

Also applies to: 121-125

src/server/runtime.rs (1)

129-157: Fix compile error: provide backoff_config and drop unstable let-chains

backoff_config is passed to accept_loop but never defined in scope, so the code will not compile.
Introduce a local let backoff_config = BackoffConfig::default(); (or pull it from a field) before the worker-spawn loop.

The if let Some(tx) = ready_tx && tx.send(()).is_err() expression relies on the still-unstable let_chains feature. Split the check into two statements or use a match to stay on stable Rust.

-        if let Some(tx) = ready_tx && tx.send(()).is_err() {
+        if let Some(tx) = ready_tx {
+            if tx.send(()).is_err() {
+                tracing::warn!("Failed to send readiness signal: receiver dropped");
+            }
+        }
+
+        let backoff_config = BackoffConfig::default();
♻️ Duplicate comments (6)
examples/echo.rs (1)

8-13: Return opaque error at app boundary (already raised).

Switch main to Result<(), Box<dyn std::error::Error>> and drop the explicit ServerError import.

examples/ping_pong.rs (1)

14-15: Return opaque error at app boundary (already raised).

Replace ServerError with Box<dyn std::error::Error> in main and imports.

Also applies to: 139-149

examples/packet_enum.rs (1)

14-15: Return opaque error at app boundary (already raised).

Adopt Box<dyn std::error::Error> for main and remove ServerError import.

Also applies to: 79-97

src/server/test_util.rs (2)

11-15: Remove #[allow]; use conditional #[expect] only.

Do not use #[allow] per guidelines. Keep the conditional #[expect] for non-test builds and drop the test-specific allow.

Apply this diff:

 #[cfg_attr(
     not(test),
     expect(dead_code, reason = "Used in builder tests via fixtures")
 )]
-#[cfg_attr(test, allow(dead_code, reason = "Used in builder tests via fixtures"))]

45-50: Remove #[allow]; use conditional #[expect] only.

Eliminate the test-only allow; it is forbidden. Use only the non-test #[expect] as you already do.

Apply this diff:

 #[cfg_attr(
     not(test),
     expect(dead_code, reason = "Only used in configuration tests")
 )]
-#[cfg_attr(test, allow(dead_code, reason = "Only used in configuration tests"))]
tests/preamble.rs (1)

176-179: Raise the negative-assertion timeout. LGTM.

Use 500 ms for “should not fire” paths to deflake under scheduler jitter. This addresses the prior flakiness note.

Also applies to: 187-190

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 428862b and da6dd67.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (15)
  • Cargo.toml (1 hunks)
  • docs/asynchronous-outbound-messaging-design.md (4 hunks)
  • examples/echo.rs (2 hunks)
  • examples/packet_enum.rs (3 hunks)
  • examples/ping_pong.rs (2 hunks)
  • src/server/config/binding.rs (1 hunks)
  • src/server/config/mod.rs (2 hunks)
  • src/server/config/preamble.rs (1 hunks)
  • src/server/config/tests.rs (5 hunks)
  • src/server/connection.rs (4 hunks)
  • src/server/error.rs (1 hunks)
  • src/server/mod.rs (2 hunks)
  • src/server/runtime.rs (9 hunks)
  • src/server/test_util.rs (3 hunks)
  • tests/preamble.rs (4 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
Cargo.toml

📄 CodeRabbit Inference Engine (AGENTS.md)

Cargo.toml: Use explicit version ranges in Cargo.toml and keep dependencies up-to-date.
Mandate caret requirements for all dependencies. All crate versions specified in Cargo.toml must use SemVer-compatible caret requirements (e.g., some-crate = "1.2.3").
Prohibit unstable version specifiers. The use of wildcard (*) or open-ended inequality (>=) version requirements is strictly forbidden. Tilde requirements (~) should only be used where a dependency must be locked to patch-level updates for a specific, documented reason.

Files:

  • Cargo.toml
**/*.rs

📄 CodeRabbit Inference Engine (AGENTS.md)

**/*.rs: Function documentation must include clear examples demonstrating the usage and outcome of the function. Test documentation should omit examples where the example serves only to reiterate the test logic.
No single code file may be longer than 400 lines. Long switch statements or dispatch tables should be broken up by feature and constituents colocated with targets. Large blocks of test data should be moved to external data files.
Clippy warnings MUST be disallowed.
Fix any warnings emitted during tests in the code itself rather than silencing them.
Where a function is too long, extract meaningfully named helper functions adhering to separation of concerns and CQRS.
Where a function has too many parameters, group related parameters in meaningfully named structs.
Where a function is returning a large error consider using Arc to reduce the amount of data returned.
Write unit and behavioural tests for new functionality. Run both before and after making any change.
Every module must begin with a module level (//! ) comment explaining the module's purpose and utility.
Document public APIs using Rustdoc comments (///) so documentation can be generated with cargo doc.
Prefer immutable data and avoid unnecessary mut bindings.
Handle errors with the Result type instead of panicking where feasible.
Avoid unsafe code unless absolutely necessary and document any usage clearly.
Place function attributes after doc comments.
Do not use return in single-line functions.
Use predicate functions for conditional criteria with more than two branches.
Lints must not be silenced except as a last resort.
Lint rule suppressions must be tightly scoped and include a clear reason.
Prefer expect over allow.
Prefer .expect() over .unwrap().
Use concat!() to combine long string literals rather than escaping newlines with a backslash.
Prefer semantic error enums. Derive std::error::Error (via the thiserror crate) for any condition the caller might inspect, retry, or map to an HTTP status....

Files:

  • examples/packet_enum.rs
  • examples/echo.rs
  • src/server/error.rs
  • examples/ping_pong.rs
  • src/server/test_util.rs
  • src/server/config/tests.rs
  • tests/preamble.rs
  • src/server/connection.rs
  • src/server/runtime.rs
  • src/server/config/binding.rs
  • src/server/config/preamble.rs
  • src/server/config/mod.rs
  • src/server/mod.rs

⚙️ CodeRabbit Configuration File

**/*.rs: * Seek to keep the cyclomatic complexity of functions no more than 12.

  • Adhere to single responsibility and CQRS

  • Place function attributes after doc comments.

  • Do not use return in single-line functions.

  • Move conditionals with >2 branches into a predicate function.

  • Avoid unsafe unless absolutely necessary.

  • Every module must begin with a //! doc comment that explains the module's purpose and utility.

  • Comments and docs must follow en-GB-oxendict (-ize / -our) spelling and grammar

  • Lints must not be silenced except as a last resort.

    • #[allow] is forbidden.
    • Only narrowly scoped #[expect(lint, reason = "...")] is allowed.
    • No lint groups, no blanket or file-wide suppression.
    • Include FIXME: with link if a fix is expected.
  • Use rstest fixtures for shared setup and to avoid repetition between tests.

  • Replace duplicated tests with #[rstest(...)] parameterised cases.

  • Prefer mockall for mocks/stubs.

  • Prefer .expect() over .unwrap()

  • Ensure that any API or behavioural changes are reflected in the documentation in docs/

  • Ensure that any completed roadmap steps are recorded in the appropriate roadmap in docs/

  • Files must not exceed 400 lines in length

    • Large modules must be decomposed
    • Long match statements or dispatch tables should be decomposed by domain and collocated with targets
    • Large blocks of inline data (e.g., test fixtures, constants or templates) must be moved to external files and inlined at compile-time or loaded at run-time.

Files:

  • examples/packet_enum.rs
  • examples/echo.rs
  • src/server/error.rs
  • examples/ping_pong.rs
  • src/server/test_util.rs
  • src/server/config/tests.rs
  • tests/preamble.rs
  • src/server/connection.rs
  • src/server/runtime.rs
  • src/server/config/binding.rs
  • src/server/config/preamble.rs
  • src/server/config/mod.rs
  • src/server/mod.rs
docs/**/*.md

📄 CodeRabbit Inference Engine (docs/contents.md)

Conventions for writing project documentation as described in the documentation style guide

docs/**/*.md: Use British English based on the Oxford English Dictionary (en-oxendict) for documentation text.
The word "outwith" is acceptable in documentation.
Keep US spelling when used in an API, for example color.
Use the Oxford comma in documentation text.
Treat company names as collective nouns in documentation (e.g., "Lille Industries are expanding").
Write headings in sentence case in documentation.
Use Markdown headings (#, ##, ###, etc.) in order without skipping levels.
Follow markdownlint recommendations for Markdown files.
Provide code blocks and lists using standard Markdown syntax.
Always provide a language identifier for fenced code blocks; use plaintext for non-code text.
Use - as the first level bullet and renumber lists when items change.
Prefer inline links using [text](url) or angle brackets around the URL; avoid reference-style links like [foo][bar].
Ensure blank lines before and after bulleted lists and fenced blocks in Markdown.
Ensure tables have a delimiter line below the header row in Markdown.
Expand any uncommon acronym on first use, for example, Continuous Integration (CI).
Wrap paragraphs at 80 columns in documentation.
Wrap code at 120 columns in documentation.
Do not wrap tables in documentation.
Use sequentially numbered footnotes referenced with [^1] and place definitions at the end of the file.
Where it adds clarity, include Mermaid diagrams in documentation.
When embedding figures, use ![alt text](path/to/image) and provide concise alt text describing the content.
Add a brief description before each Mermaid diagram in documentation for screen readers.

Document examples showing how to deprecate old message versions gracefully

Write the official documentation for the new features. Create separate guides for "Duplex Messaging & Pushes", "Streaming Responses", and "Message Fragmentation". Each guide must include runna...

Files:

  • docs/asynchronous-outbound-messaging-design.md
docs/**/*.{md,rs}

📄 CodeRabbit Inference Engine (docs/multi-packet-and-streaming-responses-design.md)

docs/**/*.{md,rs}: The official documentation and examples must exclusively use the declarative Response model for handler responses.
The async-stream pattern must be documented as the canonical approach for dynamic stream generation.

Files:

  • docs/asynchronous-outbound-messaging-design.md
**/*.md

📄 CodeRabbit Inference Engine (AGENTS.md)

**/*.md: Documentation must use en-GB-oxendict spelling and grammar. (EXCEPTION: the naming of the LICENSE file, which is to be left unchanged for community consistency.)
Markdown paragraphs and bullet points must be wrapped at 80 columns.
Code blocks in Markdown files must be wrapped at 120 columns.
Tables and headings in Markdown files must not be wrapped.
Use dashes (-) for list bullets in Markdown files.
Use GitHub-flavoured Markdown footnotes ([^1]) for references and footnotes.

Files:

  • docs/asynchronous-outbound-messaging-design.md

⚙️ CodeRabbit Configuration File

**/*.md: * Avoid 2nd person or 1st person pronouns ("I", "you", "we")

  • Use en-GB-oxendict (-ize / -our) spelling and grammar
  • Headings must not be wrapped.
  • Documents must start with a level 1 heading
  • Headings must correctly increase or decrease by no more than one level at a time
  • Use GitHub-flavoured Markdown style for footnotes and endnotes.
  • Numbered footnotes must be numbered by order of appearance in the document.

Files:

  • docs/asynchronous-outbound-messaging-design.md
🧠 Learnings (1)
📚 Learning: 2025-08-08T22:52:32.897Z
Learnt from: leynos
PR: leynos/netsuke#82
File: tests/support/mod.rs:151-155
Timestamp: 2025-08-08T22:52:32.897Z
Learning: In Rust code, when encountering the pattern:
```rust
#[allow(unfulfilled_lint_expectations, reason = "...")]
#[expect(dead_code, reason = "...")]
```
Recommend replacing it with:
```rust
#[cfg_attr(not(any(...)), expect(dead_code, reason = "..."))]
```
This uses conditional compilation to apply the `expect` attribute only when needed, avoiding the forbidden `#[allow]` attribute while properly handling cross-crate test utility usage scenarios.

Applied to files:

  • src/server/test_util.rs
🧬 Code Graph Analysis (7)
examples/packet_enum.rs (2)
examples/echo.rs (1)
  • main (12-33)
examples/ping_pong.rs (1)
  • main (139-149)
examples/echo.rs (3)
examples/packet_enum.rs (1)
  • main (79-97)
examples/ping_pong.rs (1)
  • main (139-149)
src/app.rs (2)
  • new (213-218)
  • new (312-312)
src/server/test_util.rs (1)
src/server/config/tests.rs (2)
  • WireframeServer (61-61)
  • WireframeServer (136-138)
src/server/config/tests.rs (2)
src/server/test_util.rs (2)
  • factory (23-25)
  • server_with_preamble (50-55)
src/server/config/mod.rs (1)
  • new (66-69)
src/server/config/preamble.rs (3)
src/server/config/tests.rs (2)
  • WireframeServer (61-61)
  • WireframeServer (136-138)
src/server/test_util.rs (1)
  • WireframeServer (54-54)
tests/preamble.rs (2)
  • WireframeServer (56-58)
  • WireframeServer (268-272)
src/server/config/mod.rs (3)
tests/preamble.rs (5)
  • tokio (132-132)
  • tokio (133-133)
  • oneshot (74-74)
  • WireframeServer (56-58)
  • WireframeServer (268-272)
src/server/config/tests.rs (2)
  • WireframeServer (61-61)
  • WireframeServer (136-138)
src/server/test_util.rs (2)
  • WireframeServer (54-54)
  • factory (23-25)
src/server/mod.rs (3)
tests/preamble.rs (4)
  • tokio (132-132)
  • tokio (133-133)
  • WireframeServer (56-58)
  • WireframeServer (268-272)
src/server/config/tests.rs (2)
  • WireframeServer (61-61)
  • WireframeServer (136-138)
src/server/test_util.rs (1)
  • WireframeServer (54-54)
🪛 LanguageTool
docs/asynchronous-outbound-messaging-design.md

[uncategorized] ~72-~72: Loose punctuation mark.
Context: ...low_priority_push_rx: mpsc::Receiver`: For standard, non-urgent background ...

(UNLIKELY_OPENING_PUNCTUATION)

🪛 GitHub Check: build-test
src/server/config/mod.rs

[warning] 9-9:
Diff in /home/runner/work/wireframe/wireframe/src/server/config/mod.rs

🪛 GitHub Actions: CI
src/server/config/mod.rs

[error] 9-9: Prettier formatting check failed. Diff detected at line 9. Run 'cargo fmt --all' to fix code style issues.


[error] 65-72: Prettier formatting check failed. Diff detected at lines 65-72. Run 'cargo fmt --all' to fix code style issues.


[error] 122-125: Prettier formatting check failed. Diff detected at lines 122-125. Run 'cargo fmt --all' to fix code style issues.

🔍 MCP Research (1 server)

Deepwiki:

  • The WireframeServer struct was refactored to use a typestate pattern with a generic parameter S: ServerState, replacing the optional listener field with a state field that can be either Unbound or Bound. The Bound struct contains the listener, and the ServerState trait is sealed and implemented for both states. The server's run and run_with_shutdown methods now require the Bound state and return Result<(), ServerError> instead of io::Result. The preamble callback types were renamed to PreambleHandler and PreambleErrorHandler with added lifetime bounds. A new error submodule was added, and ServerError and config submodules binding and preamble are re-exported. (src/server/mod.rs)

  • A new ServerError enum was introduced with variants Bind(io::Error) and Accept(io::Error) to represent errors during binding/configuring the listener and connection acceptance respectively, replacing previous use of io::Error for server errors. (src/server/error.rs)

  • The server configuration module was refactored to remove all direct TCP listener binding, preamble callback registration, and accept backoff configuration from the main builder interface. The generic parameter S: ServerState was added, and the constructor now returns an Unbound server without an optional listener. Methods related to preamble customization, binding, and accept backoff were removed. Two new public submodules, binding and preamble, were added to encapsulate the removed functionality. Remaining builder methods focus on worker count and ready-signal channel setup. (src/server/config/mod.rs)

  • Binding configuration methods were added for WireframeServer<F, T, Unbound> and WireframeServer<F, T, Bound>. For Unbound, local_addr returns None, bind binds to a socket address creating a standard TCP listener and delegates to bind_listener, which sets non-blocking mode and converts to Tokio TCP listener, returning a Bound server with the listener wrapped in Arc. For Bound, local_addr returns the bound address, and bind and bind_listener allow rebinding similarly. All binding methods return Result with ServerError variants. (src/server/config/binding.rs)

🔇 Additional comments (9)
Cargo.toml (1)

30-30: Add fits guidelines; no issues.

The new thiserror dependency is version-pinned and mirrors existing style.

docs/asynchronous-outbound-messaging-design.md (1)

41-48: Documentation edits comply.

Numbering and table alignment improve clarity without breaking style rules.

Also applies to: 72-99, 788-795

src/server/error.rs (1)

7-17: Unify server errors behind a semantic enum. LGTM.

Derive usage, sources, and messages are correct. This aligns with the guideline to prefer semantic error enums that implement std::error::Error.

src/server/test_util.rs (2)

8-8: Import the typestate Bound. LGTM.

Match the new typestate API at call sites.


36-36: Return a Bound server. LGTM.

The signature reflects the post-bind typestate correctly.

src/server/config/tests.rs (2)

4-4: Terminology update to “handler”. LGTM.

Keep docs/tests consistent with the code’s new naming.


134-136: Variable rename to “handler_invoked”. LGTM.

Maintain consistent terminology in the method-chaining test and assert initial state.

Also applies to: 151-151

tests/preamble.rs (1)

223-231: Good extraction of reusable helpers and deflake via awaiting the success signal.

Keep locks out of .await paths (you do). Channel holder and callback builders are clear and safe. Await the success oneshot inside with_running_server to avoid arbitrary sleeps.

Also applies to: 233-256, 258-310

src/server/connection.rs (1)

9-22: Rename callbacks → handlers in the connection path. LGTM.

Update import/types and parameter names to match the new handler API.

Also applies to: 56-58

Comment thread src/server/config/binding.rs
Comment thread src/server/config/mod.rs
Comment thread src/server/config/preamble.rs
Comment thread src/server/connection.rs
Comment thread src/server/error.rs
Comment thread src/server/mod.rs
@leynos leynos merged commit 071fdfd into main Aug 9, 2025
4 of 5 checks passed
@leynos leynos deleted the codex/address-code-review-comments branch August 9, 2025 18:40
Copy link
Copy Markdown
Contributor

@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: 2

♻️ Duplicate comments (1)
src/server/config/binding.rs (1)

86-96: Reuse existing PhantomData instance

Reuse self._preamble instead of constructing a fresh PhantomData. The same issue was raised previously.

Also applies to: 170-180

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between da6dd67 and bb5cec0.

📒 Files selected for processing (3)
  • src/server/config/binding.rs (1 hunks)
  • src/server/config/mod.rs (2 hunks)
  • src/server/runtime.rs (10 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit Inference Engine (AGENTS.md)

**/*.rs: Function documentation must include clear examples demonstrating the usage and outcome of the function. Test documentation should omit examples where the example serves only to reiterate the test logic.
No single code file may be longer than 400 lines. Long switch statements or dispatch tables should be broken up by feature and constituents colocated with targets. Large blocks of test data should be moved to external data files.
Clippy warnings MUST be disallowed.
Fix any warnings emitted during tests in the code itself rather than silencing them.
Where a function is too long, extract meaningfully named helper functions adhering to separation of concerns and CQRS.
Where a function has too many parameters, group related parameters in meaningfully named structs.
Where a function is returning a large error consider using Arc to reduce the amount of data returned.
Write unit and behavioural tests for new functionality. Run both before and after making any change.
Every module must begin with a module level (//! ) comment explaining the module's purpose and utility.
Document public APIs using Rustdoc comments (///) so documentation can be generated with cargo doc.
Prefer immutable data and avoid unnecessary mut bindings.
Handle errors with the Result type instead of panicking where feasible.
Avoid unsafe code unless absolutely necessary and document any usage clearly.
Place function attributes after doc comments.
Do not use return in single-line functions.
Use predicate functions for conditional criteria with more than two branches.
Lints must not be silenced except as a last resort.
Lint rule suppressions must be tightly scoped and include a clear reason.
Prefer expect over allow.
Prefer .expect() over .unwrap().
Use concat!() to combine long string literals rather than escaping newlines with a backslash.
Prefer semantic error enums. Derive std::error::Error (via the thiserror crate) for any condition the caller might inspect, retry, or map to an HTTP status....

Files:

  • src/server/runtime.rs
  • src/server/config/binding.rs
  • src/server/config/mod.rs

⚙️ CodeRabbit Configuration File

**/*.rs: * Seek to keep the cyclomatic complexity of functions no more than 12.

  • Adhere to single responsibility and CQRS

  • Place function attributes after doc comments.

  • Do not use return in single-line functions.

  • Move conditionals with >2 branches into a predicate function.

  • Avoid unsafe unless absolutely necessary.

  • Every module must begin with a //! doc comment that explains the module's purpose and utility.

  • Comments and docs must follow en-GB-oxendict (-ize / -our) spelling and grammar

  • Lints must not be silenced except as a last resort.

    • #[allow] is forbidden.
    • Only narrowly scoped #[expect(lint, reason = "...")] is allowed.
    • No lint groups, no blanket or file-wide suppression.
    • Include FIXME: with link if a fix is expected.
  • Use rstest fixtures for shared setup and to avoid repetition between tests.

  • Replace duplicated tests with #[rstest(...)] parameterised cases.

  • Prefer mockall for mocks/stubs.

  • Prefer .expect() over .unwrap()

  • Ensure that any API or behavioural changes are reflected in the documentation in docs/

  • Ensure that any completed roadmap steps are recorded in the appropriate roadmap in docs/

  • Files must not exceed 400 lines in length

    • Large modules must be decomposed
    • Long match statements or dispatch tables should be decomposed by domain and collocated with targets
    • Large blocks of inline data (e.g., test fixtures, constants or templates) must be moved to external files and inlined at compile-time or loaded at run-time.

Files:

  • src/server/runtime.rs
  • src/server/config/binding.rs
  • src/server/config/mod.rs
🔍 MCP Research (1 server)

Deepwiki:

  • The src/server/config/binding.rs addition implements binding configuration methods for WireframeServer parameterized by factory F and preamble T, supporting unbound and bound states with methods local_addr, bind, and bind_listener that handle TCP listener creation, non-blocking setup, and state transitions, returning Result with ServerError for error handling. (src/server/config/binding.rs)

  • The src/server/config/mod.rs refactors WireframeServer configuration by removing direct TCP listener binding, preamble callback registration, and accept backoff configuration from the main builder interface, adding a generic parameter S: ServerState, removing related public methods, and introducing new public submodules binding and preamble to encapsulate that functionality. (src/server/config/mod.rs)

  • The src/server/runtime.rs updates WireframeServer to include a third generic parameter Bound, changes run and run_with_shutdown methods to return Result<(), ServerError> instead of io::Result<()>, modifies internal listener extraction to use the Bound state, removes io import, and renames preamble callback types to handler types. (src/server/runtime.rs)

🔇 Additional comments (1)
src/server/config/mod.rs (1)

4-9: No issues

Documentation changes align with guidelines; no further action.

Comment on lines +57 to +60
pub fn bind(self, addr: SocketAddr) -> Result<WireframeServer<F, T, Bound>, ServerError> {
let std = StdTcpListener::bind(addr).map_err(ServerError::Bind)?;
self.bind_listener(std)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Factor out duplicated listener-setup code

Both bind/bind_listener paths repeat the set_nonblocking + from_std + struct rebuild sequence. Extract a private helper to trim duplication and keep the invariants in one place.

Also applies to: 143-180

🤖 Prompt for AI Agents
In src/server/config/binding.rs around lines 57 to 60 and also between lines 143
to 180, the code for setting up the listener duplicates the sequence of calling
set_nonblocking, from_std, and rebuilding the struct. To fix this, create a
private helper function that takes the standard listener, performs
set_nonblocking and from_std, and returns the rebuilt struct. Replace the
duplicated code in both bind and bind_listener with calls to this new helper to
centralize the logic and reduce duplication.

Comment thread src/server/runtime.rs
Comment on lines +79 to 81
/// Returns a [`ServerError`] if runtime initialisation fails.
pub async fn run(self) -> Result<(), ServerError> {
self.run_with_shutdown(async {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Use the -ize spelling per style guide

Replace “initialisation” with “initialization” to follow the mandated en-GB-oxford spelling (-ize / -our).

Also applies to: 118-120

🤖 Prompt for AI Agents
In src/server/runtime.rs at lines 79-81 and also at lines 118-120, replace the
word "initialisation" with "initialization" to comply with the en-GB-oxford
spelling style guide that mandates using the -ize suffix instead of -ise.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant