Skip to content

Add AppDataStore and byte_order utilities; refactor app data sharing#455

Merged
leynos merged 5 commits intomainfrom
refactor-app-data-store-furyr1
Feb 16, 2026
Merged

Add AppDataStore and byte_order utilities; refactor app data sharing#455
leynos merged 5 commits intomainfrom
refactor-app-data-store-furyr1

Conversation

@leynos
Copy link
Copy Markdown
Owner

@leynos leynos commented Feb 5, 2026

Summary

  • Adds AppDataStore, a type-erased, thread-safe store for application-wide state keyed by concrete types.
  • Introduces src/byte_order.rs with read_network_u32 and write_network_u32 (and existing u16/u64 helpers) for consistent network byte order handling.
  • Refactors code to use AppDataStore instead of a HashMap-based app_data for sharing state (WireframeApp, MessageRequest, and related extractors).
  • Centralizes multi-field type-transition reconstructions in the app builder (rebuild_with_params) and updates documentation to reflect new patterns.
  • Publicly exports AppDataStore in lib.rs for downstream use.
  • Aligns endianness handling across codec and frame layers by leveraging shared byte_order helpers.

Changes

New

  • src/app_data_store.rs: Implemented AppDataStore with insert and get, backed by a HashMap<TypeId, Arc<dyn Any + Send + Sync>>. Includes tests.
  • src/byte_order.rs: Added network-order helpers (read_network_u32, write_network_u32; plus existing u16/u64 helpers).
  • pub use AppDataStore in lib.rs for external consumption.

Core Refactors

  • src/app/builder.rs: Replaced app_data: HashMap<...> with AppDataStore; default initialization now AppDataStore::default(); app data insert uses AppDataStore::insert(state); Expanded doc on rebuild_with_params as per conventions.
  • src/extractor.rs: Replaced HashMap-based app_data with AppDataStore in MessageRequest; updated access patterns to use AppDataStore API.
  • src/frame/conversion.rs: Replaced direct u64_from_be_bytes usage with read_network_u64 for big-endian decoding.
  • src/codec.rs: Removed legacy parse_length_header helper; EOF error path now uses read_network_u32(bytes) for length header parsing.
  • tests/fixtures/codec_error/decoder_ops.rs: Updated length-prefix usage to utilize read_network_u32 for consistency with new helpers.
  • src/lib.rs: Publicly export AppDataStore.

Documentation

  • docs/builder-pattern-conventions.md: New guide describing builder patterns and when to use helper methods vs macros, referencing centralization in WireframeApp.
  • docs/contents.md: Linked the new Builder pattern conventions doc.
  • src/client/builder.rs: Expanded comments to reference new conventions and differentiate macro-based vs helper-based approaches.

Public API

  • AppDataStore is now part of the public API (exported from lib.rs) and can be used to share typed state across request processing.

Testing

  • Added unit tests for AppDataStore covering multi-type storage, overwrite behavior, and Send+Sync guarantees.
  • Updated existing tests/fixtures to align with new read_network_u32 usage and updated endianness helpers.

Migration / Compatibility

  • Breaking change: code previously using a raw HashMap-based app_data must migrate to AppDataStore with insert/get API. Public API now exposes AppDataStore.

📎 Task: https://www.devboxer.com/task/156ddc30-5dfb-47f9-865c-1eb7d6667f0d

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Feb 5, 2026

Reviewer's Guide

Introduces a reusable AppDataStore abstraction for type-erased, thread-safe application state and refactors builders, extractors, and codecs to use it and shared byte-order helpers, while documenting builder-pattern conventions.

Sequence diagram for request handling using AppDataStore

sequenceDiagram
    actor Client
    participant WireframeAppBuilder
    participant AppDataStore
    participant WireframeApp
    participant MessageRequest
    participant Handler

    Client->>WireframeAppBuilder: with_state_MyConfig_(config)
    WireframeAppBuilder->>AppDataStore: insert_MyConfig_(config)
    WireframeAppBuilder-->>Client: WireframeApp instance

    Client->>WireframeApp: handle_incoming_frame(frame)
    WireframeApp->>MessageRequest: new(app_data_clone, frame)
    WireframeApp-->>Handler: MessageRequest passed to handler

    Handler->>MessageRequest: shared_state_MyConfig_()
    MessageRequest->>AppDataStore: get_MyConfig_()
    AppDataStore-->>MessageRequest: Option_Arc_MyConfig_
    MessageRequest-->>Handler: Option_SharedState_MyConfig_

    Handler-->>Client: response frame
Loading

Class diagram for AppDataStore integration with WireframeApp and MessageRequest

classDiagram
    class AppDataStore {
        +values: HashMap_TypeId_ArcAnySendSync_
        +insert_T_(value: T)
        +get_T_() Option_ArcT_
    }

    class WireframeApp_E_S_F_C_ {
        +routes: OnceCell_Arc_HashMap_u32_HandlerService_E___
        +middleware: Vec_Box_Middleware_E__
        +serializer: S
        +app_data: AppDataStore
        +on_connect: Option_Arc_ConnectionSetup_C__
        +on_disconnect: Option_Arc_ConnectionTeardown_C__
        +protocol: Option_Arc_WireframeProtocol_Frame_EQ_F::Frame_ProtocolError_EQ____
        +fragmenter: Option_Arc_Fragmenter_F::Frame__
        +with_state_T_(state: T) WireframeApp_E_S_F_C_
        +rebuild_with_params_S2_F2_(self_ref: WireframeApp_E_S_F_C_, serializer: S2, frame: F2, protocol: Option_Arc_WireframeProtocol_Frame_EQ_F2::Frame_ProtocolError_EQ____, fragmenter: Option_Arc_Fragmenter_F2::Frame__) WireframeApp_E_S2_F2_C_
    }

    class MessageRequest {
        +peer_addr: Option_SocketAddr_
        +app_data: AppDataStore
        +body: Option_StreamingBody_
        +shared_state_T_() Option_SharedState_T__
        +insert_state_T_(state: T)
        +set_body(body: StreamingBody)
    }

    class SharedState_T_ {
        +value: Arc_T_
    }

    AppDataStore "1" <-- "1" WireframeApp_E_S_F_C_ : owns
    AppDataStore "1" <-- "1" MessageRequest : owns
    SharedState_T_ "1" --> "1" T : wraps
Loading

File-Level Changes

Change Details Files
Add AppDataStore as a dedicated, reusable store for type-erased application state and expose it as public API.
  • Implement AppDataStore backed by HashMap<TypeId, Arc<dyn Any + Send + Sync>> with typed insert and get accessors and unit tests for multi-type storage, overwrites, and Send+Sync guarantees.
  • Refactor WireframeApp and MessageRequest to store app_data as AppDataStore instead of a raw HashMap, updating insertion and retrieval sites to use the new API.
  • Export AppDataStore from lib.rs for downstream use as the canonical app data sharing mechanism.
src/app_data_store.rs
src/app/builder.rs
src/extractor.rs
src/lib.rs
Standardize network byte-order helpers and refactor codecs and frame conversion to use shared utilities.
  • Extend byte_order module with read/write helpers for u32 and u64 in network (big-endian) order, plus round-trip tests for u16/u32/u64.
  • Replace local big-endian parsing helpers in codec and frame conversion with read_network_u32/read_network_u64, and remove the legacy parse_length_header function.
  • Update codec error fixtures to build and decode length prefixes via the shared byte-order helpers for consistency.
src/byte_order.rs
src/codec.rs
src/frame/conversion.rs
tests/fixtures/codec_error/decoder_ops.rs
Document and align builder patterns for type-transitioning builders across server and client.
  • Expand WireframeApp::rebuild_with_params docs and clippy annotation to emphasize its role in centralizing multi-field type transitions across 13 builder fields.
  • Clarify macro-based reconstruction guidance in the client builder, pointing to the new conventions and contrasting macro vs helper-method approaches.
  • Add a builder-pattern-conventions guide and link it from the documentation contents index to standardize reconstruction patterns project-wide.
src/app/builder.rs
src/client/builder.rs
docs/builder-pattern-conventions.md
docs/contents.md

Assessment against linked issues

Issue Objective Addressed Explanation
#432 Consolidate the duplicated TypeId→Any app-data store between WireframeApp and MessageRequest into an AppDataStore newtype with insert()/get() methods, and use it in both locations.
#432 Standardize the builder type-transition pattern (between helper-function and macro approaches) to reduce boilerplate and make future splits easier, including documenting the chosen conventions.
#432 Extend centralized endianness helpers to cover u32/u64 and reuse them across codec logic and tests instead of local big-endian parsing helpers.

Possibly linked issues

  • #(not specified): PR introduces AppDataStore, unifies builder transition patterns, and extends byte_order to u32/u64, matching the issue’s goals.

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 Feb 5, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Summarise the refactor: add a concurrent AppDataStore for per-type app state, extend byte-order helpers to u32/u64 and replace local helpers, and standardise builder reconstruction using a RebuildParams struct; update codec, frame conversion, request extractor, tests and documentation accordingly.

Changes

Cohort / File(s) Summary
Documentation
docs/builder-pattern-conventions.md, docs/contents.md
Add builder-pattern-conventions guide and register it in contents; update server configuration description.
Application data store
src/app_data_store.rs, src/lib.rs
Introduce public AppDataStore (DashMap<TypeId, Arc<dyn Any + Send + Sync>>), derive Clone/Default, and export from crate root.
Request extractor & usage
src/extractor/request.rs, src/app/builder/state.rs, src/app/builder/core.rs
Replace HashMap<TypeId,...> storage with AppDataStore; change insertion/retrieval APIs to use app_data.insert/get; change app_data builder method to consume self; wire AppDataStore into WireframeApp and defaults.
Builder reconstruction
src/app/builder/core.rs, src/app/builder/codec.rs
Introduce internal RebuildParams struct and change rebuild_with_params to accept it; replace multi-arg calls with a single RebuildParams value.
Byte-order utilities
src/byte_order.rs, tests/fixtures/codec_error/decoder_ops.rs
Add write_network_u32/read_network_u32 and write_network_u64/read_network_u64 with tests and update doc examples; update tests/fixtures to use new helpers.
Frame/codec integration
src/frame/conversion.rs, src/codec.rs
Remove local BE helpers; use new byte-order helpers (read_network_u64, write_network_u16/32/64); refactor write_bytes_with_endianness to delegate to private prefix helpers.
Client builder docs & tests
src/client/builder/mod.rs, tests/app_data.rs, tests/extractor.rs
Add doc comments for builder_field_update! macro; adjust test parameter mutability (tests may need fix due to immutability change).

Sequence Diagram(s)

(Skipped — changes are refactors and API additions that do not create a new multi-actor runtime control flow requiring a sequence diagram.)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related issues

Poem

🛠️ Types now rest in one shared store, robust and neat,
Big-endian bytes march tidy, u32 and u64 meet,
Builders rebuild from one compact frame,
Tests and docs aligned to the new name,
Refactor hums, the codebase finds new feet.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title directly and specifically describes the main changes: adding AppDataStore and byte_order utilities plus refactoring app data sharing, which are the primary objectives of the changeset.
Description check ✅ Passed The description comprehensively covers all aspects of the changeset: the new AppDataStore implementation, byte_order utilities, refactoring of app data sharing across multiple modules, documentation updates, and testing changes.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

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

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor-app-data-store-furyr1

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

@leynos leynos marked this pull request as ready for review February 8, 2026 01:56
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 - I've found 2 issues, and left some high level feedback:

  • The AppDataStore docs and PR description call it "thread-safe", but the implementation only guarantees safe concurrent reads (mutations still require &mut self); consider clarifying the concurrency model in the docs or adding internal synchronization if concurrent mutation from multiple threads is expected.
  • If you expect downstream users to need more than insert/get semantics on AppDataStore, it may be worth adding a contains::<T>() or remove::<T>() API now to avoid them reaching into the underlying map later.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `AppDataStore` docs and PR description call it "thread-safe", but the implementation only guarantees safe concurrent reads (mutations still require `&mut self`); consider clarifying the concurrency model in the docs or adding internal synchronization if concurrent mutation from multiple threads is expected.
- If you expect downstream users to need more than insert/get semantics on `AppDataStore`, it may be worth adding a `contains::<T>()` or `remove::<T>()` API now to avoid them reaching into the underlying map later.

## Individual Comments

### Comment 1
<location> `src/byte_order.rs:132` </location>
<code_context>
+        write_network_u64,
+    };
+
+    #[test]
+    fn u16_round_trip() {
+        let value = 0x1234;
</code_context>

<issue_to_address>
**issue (review_instructions):** The new round-trip tests duplicate the same pattern across u16/u32/u64 without using rstest parameterisation.

The three `*_round_trip` tests share identical structure (construct value, serialise, assert equality, then parse and assert equality). Per the testing instructions, these should be consolidated into a `#[rstest]` with parameters for the type/constructor/value rather than three separate tests.

Example (sketch):

```rust
#[rstest]
#[case::u16(0x1234u16, write_network_u16, read_network_u16, [0x12, 0x34])] 
#[case::u32(0x1234_5678u32, write_network_u32, read_network_u32, [0x12, 0x34, 0x56, 0x78])] 
#[case::u64(0x1122_3344_5566_7788u64, write_network_u64, read_network_u64, [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88])] 
fn round_trip_cases<...>(...) { ... }
```

That would satisfy the requirement to replace duplicated tests with parameterised rstest cases.

<details>
<summary>Review instructions:</summary>

**Path patterns:** `**/*.rs`

**Instructions:**
* Use `rstest` fixtures for shared setup.
* Replace duplicated tests with `#[rstest(...)]` parameterised cases.

</details>
</issue_to_address>

### Comment 2
<location> `src/app_data_store.rs:98` </location>
<code_context>
+        write_network_u64,
+    };
+
+    #[test]
+    fn u16_round_trip() {
+        let value = 0x1234;
</code_context>

<issue_to_address>
**issue (review_instructions):** The new AppDataStore tests share setup but do not use rstest fixtures or parameterised cases.

Several tests (`insert_and_get_multiple_types`, `insert_overwrites_existing_value`, `missing_type_returns_none`) all start from `AppDataStore::default()` and then vary the operations/assertions. The guidelines ask to use `rstest` fixtures for shared setup and parameterise duplicated tests.

Consider introducing a `#[fixture] fn empty_store() -> AppDataStore` and, where appropriate, using `#[rstest]` parameterised cases rather than repeating very similar patterns by hand.

<details>
<summary>Review instructions:</summary>

**Path patterns:** `**/*.rs`

**Instructions:**
* Use `rstest` fixtures for shared setup.
* Replace duplicated tests with `#[rstest(...)]` parameterised cases.

</details>
</issue_to_address>

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.

Comment thread src/byte_order.rs Outdated
Comment thread src/app_data_store.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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/frame/conversion.rs (1)

110-127: 🧹 Nitpick | 🔵 Trivial

Note: write_bytes_with_endianness could use the network-order write helpers.

The read path (line 83) now uses read_network_u64, but the write path still uses manual byte shifting. For consistency, the Endianness::Big branch here could delegate to write_network_u32/write_network_u64 when the size matches. This is not blocking—the current implementation is correct—but raises the question of symmetry.

#!/bin/bash
# Check if write_network_u32/u64 are used elsewhere in the codebase for encoding
rg -n 'write_network_u(32|64)' --type rust
src/app/builder.rs (1)

127-146: ⚠️ Potential issue | 🟠 Major

Group rebuild parameters and remove the lint expectation.

The rebuild_with_params function has 5 parameters exceeding the configured clippy threshold of 4. Wrap the serializer, codec, protocol, fragmentation and message_assembler inputs in a RebuildParams struct to bring the function signature to 2 parameters (self + params struct), eliminating the need for #[expect(clippy::too_many_arguments)]. Both call sites at lines 181 and 260–266 use consistent parameter patterns, so refactoring is straightforward.

♻️ Suggested refactor sketch
@@
-    #[expect(
-        clippy::too_many_arguments,
-        reason = "Helper handles multi-field type transitions; see builder-pattern-conventions.md."
-    )]
-    fn rebuild_with_params<S2, F2>(
-        self,
-        serializer: S2,
-        codec: F2,
-        protocol: Option<Arc<dyn WireframeProtocol<Frame = F2::Frame, ProtocolError = ()>>>,
-        fragmentation: Option<FragmentationConfig>,
-        message_assembler: Option<Arc<dyn MessageAssembler>>,
-    ) -> WireframeApp<S2, C, E, F2>
+    fn rebuild_with_params<S2, F2>(
+        self,
+        params: RebuildParams<S2, F2>,
+    ) -> WireframeApp<S2, C, E, F2>
@@
-            serializer,
+            serializer: params.serializer,
@@
-            codec,
+            codec: params.codec,
@@
-            protocol,
+            protocol: params.protocol,
@@
-            fragmentation,
-            message_assembler,
+            fragmentation: params.fragmentation,
+            message_assembler: params.message_assembler,
         }
     }
// Add near the impl block (module scope).
struct RebuildParams<S2, F2> {
    serializer: S2,
    codec: F2,
    protocol: Option<Arc<dyn WireframeProtocol<Frame = F2::Frame, ProtocolError = ()>>>,
    fragmentation: Option<FragmentationConfig>,
    message_assembler: Option<Arc<dyn MessageAssembler>>,
}
🤖 Fix all issues with AI agents
In `@src/app_data_store.rs`:
- Around line 86-143: Create an rstest fixture that yields a fresh AppDataStore
and use it in the tests to remove repeated AppDataStore::default() calls: add a
fixture function (e.g., fn app_data_store() -> AppDataStore) annotated with
#[fixture] in the tests module, then update insert_and_get_multiple_types,
insert_overwrites_existing_value, and missing_type_returns_none to accept that
fixture (e.g., app: AppDataStore) instead of creating a new store locally;
ensure you keep the existing assertions and the store_is_send_and_sync test
unchanged.

In `@src/client/builder.rs`:
- Around line 34-40: Update the comment text to use British English by replacing
the word "centralized" with "centralised" in the docstring that references
WireframeApp::rebuild_with_params and docs/builder-pattern-conventions.md;
ensure the sentence now reads "...keep the reconstruction logic centralised and
easier to audit" so the spelling follows the en-GB-oxendict guideline.

Comment thread src/app_data_store.rs
Comment thread src/client/builder.rs Outdated
@leynos leynos changed the title Introduce AppDataStore and refactor builders for modularization Add AppDataStore and byte_order utilities; refactor app data sharing Feb 16, 2026
@coderabbitai coderabbitai Bot added the codex label Feb 16, 2026
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

🤖 Fix all issues with AI agents
In `@src/frame/conversion.rs`:
- Around line 147-153: The cast in write_little_endian_prefix triggers Clippy's
cast_possible_truncation even though the value is masked; add a narrowly-scoped
attribute on the assignment line to suppress this lint by inserting
#[expect(clippy::cast_possible_truncation, reason = "mask `& 0xff` ensures value
fits in u8")] immediately above the `*byte = ((value >> shift) & 0xff) as u8;`
statement in fn write_little_endian_prefix so the suppression mirrors the
existing pattern used in write_big_endian_prefix.

Comment thread src/frame/conversion.rs
@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Feb 16, 2026

@coderabbitai have the following now been resolved?

Please address the comments from this code review:

## Overall Comments
- The `AppDataStore` docs and PR description call it "thread-safe", but the implementation only guarantees safe concurrent reads (mutations still require `&mut self`); consider clarifying the concurrency model in the docs or adding internal synchronization if concurrent mutation from multiple threads is expected.
- If you expect downstream users to need more than insert/get semantics on `AppDataStore`, it may be worth adding a `contains::<T>()` or `remove::<T>()` API now to avoid them reaching into the underlying map later.

## Individual Comments

### Comment 1
<location> `src/byte_order.rs:132` </location>
<code_context>
+        write_network_u64,
+    };
+
+    #[test]
+    fn u16_round_trip() {
+        let value = 0x1234;
</code_context>

<issue_to_address>
**issue (review_instructions):** The new round-trip tests duplicate the same pattern across u16/u32/u64 without using rstest parameterisation.

The three `*_round_trip` tests share identical structure (construct value, serialise, assert equality, then parse and assert equality). Per the testing instructions, these should be consolidated into a `#[rstest]` with parameters for the type/constructor/value rather than three separate tests.

Example (sketch):

```rust
#[rstest]
#[case::u16(0x1234u16, write_network_u16, read_network_u16, [0x12, 0x34])] 
#[case::u32(0x1234_5678u32, write_network_u32, read_network_u32, [0x12, 0x34, 0x56, 0x78])] 
#[case::u64(0x1122_3344_5566_7788u64, write_network_u64, read_network_u64, [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88])] 
fn round_trip_cases<...>(...) { ... }
```

That would satisfy the requirement to replace duplicated tests with parameterised rstest cases.

<details>
<summary>Review instructions:</summary>

**Path patterns:** `**/*.rs`

**Instructions:**
* Use `rstest` fixtures for shared setup.
* Replace duplicated tests with `#[rstest(...)]` parameterised cases.

</details>
</issue_to_address>

### Comment 2
<location> `src/app_data_store.rs:98` </location>
<code_context>
+        write_network_u64,
+    };
+
+    #[test]
+    fn u16_round_trip() {
+        let value = 0x1234;
</code_context>

<issue_to_address>
**issue (review_instructions):** The new AppDataStore tests share setup but do not use rstest fixtures or parameterised cases.

Several tests (`insert_and_get_multiple_types`, `insert_overwrites_existing_value`, `missing_type_returns_none`) all start from `AppDataStore::default()` and then vary the operations/assertions. The guidelines ask to use `rstest` fixtures for shared setup and parameterise duplicated tests.

Consider introducing a `#[fixture] fn empty_store() -> AppDataStore` and, where appropriate, using `#[rstest]` parameterised cases rather than repeating very similar patterns by hand.

<details>
<summary>Review instructions:</summary>

**Path patterns:** `**/*.rs`

**Instructions:**
* Use `rstest` fixtures for shared setup.
* Replace duplicated tests with `#[rstest(...)]` parameterised cases.

</details>
</issue_to_address>

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 16, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check the AppDataStore implementation for DashMap usage and API methods
echo "=== AppDataStore implementation ==="
cat src/app_data_store.rs

Length of output: 9454


🏁 Script executed:

#!/bin/bash
# Check the byte_order.rs tests section
echo "=== byte_order.rs tests ==="
sed -n '/^#\[cfg(test)\]/,$p' src/byte_order.rs

Length of output: 1214


@leynos Yes, all the review comments have been resolved:

✅ Overall Comments

AppDataStore thread-safety: The implementation now uses DashMap for interior mutability, allowing concurrent mutation via &self methods. The documentation explicitly states "The underlying DashMap provides lock-free concurrent reads and sharded writes, enabling multiple threads to insert and retrieve state simultaneously without external synchronisation."

API extensions: Both contains::<T>() and remove::<T>() methods have been added to the public API, providing complete CRUD operations beyond just insert/get.

✅ Individual Comments

Comment 1 (byte_order.rs tests): The three separate *_round_trip tests have been consolidated into a single parameterised #[rstest] test named network_byte_order_round_trip with #[case::u16], #[case::u32], and #[case::u64] cases.

Comment 2 (app_data_store.rs tests): The tests now use a #[fixture] fn empty_store() -> AppDataStore and all test functions are decorated with #[rstest] accepting empty_store: AppDataStore as a parameter. Tests like insert_and_get_multiple_types, insert_overwrites_existing_value, missing_type_returns_none, contains_returns_true_for_present_type, and remove_returns_and_deletes_value all follow this pattern.

leynos and others added 3 commits February 16, 2026 19:16
…tate

Introduce AppDataStore to manage application-scoped data with type-safe
accessors, replacing HashMap<TypeId, Arc<dyn Any + Send + Sync>> usage.
Refactor WireframeApp and MessageRequest to use AppDataStore for improved
encapsulation and simpler API. Add documentation on builder pattern conventions
and update related client and app builders accordingly.

Also add network byte order serialization helpers for u32 and u64 to byte_order
module and replace ad-hoc conversions in codec and frame conversion code.
Add tests for byte order utilities and AppDataStore.

Co-authored-by: devboxerhub[bot] <devboxerhub[bot]@users.noreply.github.com>
…ntainment

Replaced the underlying HashMap in AppDataStore with a DashMap to
support concurrent insertions and retrievals without external locking.
Added contains<T> and remove<T> methods to query and delete stored data
concurrently. Updated insert and get to be thread-safe by removing mutable
requirements. Added tests verifying concurrent inserts, gets, and removals.

Also refactored WireframeApp builder to consolidate parameters into a struct.
Minor extractor API change to allow insert_state without mutable self.
Improved frame/conversion write functions for endianness handling.

Co-authored-by: devboxerhub[bot] <devboxerhub[bot]@users.noreply.github.com>
…d tests

- Replace multiple `#[test]` functions with `#[rstest]` in `app_data_store.rs` improving test reuse and readability
- Add a reusable `empty_store` fixture for simplified test setup in `AppDataStore` tests
- Convert byte order tests to parameterized tests using `rstest` in `byte_order.rs`
- Minor test code cleanups such as macro lint expectations and consistent use of fixtures
- Fix typos and unify test documentation style

This refactor improves test quality and maintainability without changing functionality.

Co-authored-by: devboxerhub[bot] <devboxerhub[bot]@users.noreply.github.com>
@devboxerhub devboxerhub Bot force-pushed the refactor-app-data-store-furyr1 branch from ff81d13 to 84d225c Compare February 16, 2026 19:20
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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/codec.rs (1)

198-202: ⚠️ Potential issue | 🟠 Major

Use fallible conversion to handle potential truncation of the length header.

The cast as usize triggers clippy::cast_possible_truncation (enabled via pedantic linting with -D warnings) and truncates on 16-bit targets. Use usize::try_from() instead, which correctly returns None when the network-supplied length header value exceeds the platform's maximum usize.

Proposed fix
    let expected = src
        .get(..LENGTH_HEADER_SIZE)
        .and_then(|slice| <[u8; LENGTH_HEADER_SIZE]>::try_from(slice).ok())
-       .map(|bytes| read_network_u32(bytes) as usize);
+       .and_then(|bytes| usize::try_from(read_network_u32(bytes)).ok());
🤖 Fix all issues with AI agents
In `@docs/builder-pattern-conventions.md`:
- Around line 26-27: Update the docs to point to the correct source file for the
macro: replace the path `src/client/builder.rs` with `src/client/builder/mod.rs`
where `builder_field_update!` is referenced (the macro named
`builder_field_update!` in the builder documentation), so the documented path
matches the actual definition in `src/client/builder/mod.rs`.

In `@src/app_data_store.rs`:
- Around line 138-162: Add a module-level doc comment at the top of the tests
module (use an internal `//!` comment) describing the purpose of these tests,
and remove the module-level #[expect(...)] attribute; instead apply the
#[expect(unused_braces, reason = concat!(...))] directly to the test item that
triggers it (the `empty_store` fixture) using concat!() to build the long reason
string rather than a backslash-continued literal; locate the `mod tests { ... }`
block and move the lint attribute to the `fn empty_store() -> AppDataStore`
fixture, replacing the escaped newline reason with concat!() and keeping the
rest of the test contents (including `CustomState` and `AppDataStore`
references) unchanged.

In `@src/byte_order.rs`:
- Around line 121-123: Add a module-level documentation comment for the test
module: update the #[cfg(test)] mod tests block by inserting a top-of-module //!
comment that briefly describes the purpose of the tests (what behaviors or
functions are being validated) and any notes about test utilities used (e.g.,
rstest). Ensure the comment sits immediately before the mod tests declaration so
the module has a proper module-level docstring.

Comment thread docs/builder-pattern-conventions.md Outdated
Comment thread src/app_data_store.rs
Comment thread src/byte_order.rs
Converted the u32 value read from network byte order to usize safely using try_from to prevent potential truncation or conversion issues. Also added documentation comments to tests, and updated module paths and attributes for clarity and lint handling.

Co-authored-by: devboxerhub[bot] <devboxerhub[bot]@users.noreply.github.com>
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

🤖 Fix all issues with AI agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.

In `@src/app_data_store.rs`:
- Around line 26-33: Remove the unnecessary `no_run` marker from the doctest
code fences for the AppDataStore examples that exercise insert and get: update
the triple-backtick fence for the doctests associated with the insert(...)
example and the get::<T>() example (the doctests referencing
AppDataStore::insert and AppDataStore::get) so they use ```rust instead of
```rust,no_run, allowing the tests to execute.

Comment thread src/app_data_store.rs Outdated
…ation

Co-authored-by: devboxerhub[bot] <devboxerhub[bot]@users.noreply.github.com>
@leynos leynos merged commit 018486a into main Feb 16, 2026
6 checks passed
@leynos leynos deleted the refactor-app-data-store-furyr1 branch February 16, 2026 21:11
devboxerhub Bot added a commit that referenced this pull request Feb 18, 2026
…455)

* feat(app_data_store): add AppDataStore for typed shared application state

Introduce AppDataStore to manage application-scoped data with type-safe
accessors, replacing HashMap<TypeId, Arc<dyn Any + Send + Sync>> usage.
Refactor WireframeApp and MessageRequest to use AppDataStore for improved
encapsulation and simpler API. Add documentation on builder pattern conventions
and update related client and app builders accordingly.

Also add network byte order serialization helpers for u32 and u64 to byte_order
module and replace ad-hoc conversions in codec and frame conversion code.
Add tests for byte order utilities and AppDataStore.

Co-authored-by: devboxerhub[bot] <devboxerhub[bot]@users.noreply.github.com>

* feat(app_data_store): make AppDataStore concurrent and add removal/containment

Replaced the underlying HashMap in AppDataStore with a DashMap to
support concurrent insertions and retrievals without external locking.
Added contains<T> and remove<T> methods to query and delete stored data
concurrently. Updated insert and get to be thread-safe by removing mutable
requirements. Added tests verifying concurrent inserts, gets, and removals.

Also refactored WireframeApp builder to consolidate parameters into a struct.
Minor extractor API change to allow insert_state without mutable self.
Improved frame/conversion write functions for endianness handling.

Co-authored-by: devboxerhub[bot] <devboxerhub[bot]@users.noreply.github.com>

* test(app_data_store,byte_order): add rstest fixtures and parameterized tests

- Replace multiple `#[test]` functions with `#[rstest]` in `app_data_store.rs` improving test reuse and readability
- Add a reusable `empty_store` fixture for simplified test setup in `AppDataStore` tests
- Convert byte order tests to parameterized tests using `rstest` in `byte_order.rs`
- Minor test code cleanups such as macro lint expectations and consistent use of fixtures
- Fix typos and unify test documentation style

This refactor improves test quality and maintainability without changing functionality.

Co-authored-by: devboxerhub[bot] <devboxerhub[bot]@users.noreply.github.com>

* fix(codec): fix usize conversion for network u32 read in codec

Converted the u32 value read from network byte order to usize safely using try_from to prevent potential truncation or conversion issues. Also added documentation comments to tests, and updated module paths and attributes for clarity and lint handling.

Co-authored-by: devboxerhub[bot] <devboxerhub[bot]@users.noreply.github.com>

* docs(app_data_store): remove no_run from Rust code blocks in documentation

Co-authored-by: devboxerhub[bot] <devboxerhub[bot]@users.noreply.github.com>

---------

Co-authored-by: devboxerhub[bot] <devboxerhub[bot]@users.noreply.github.com>
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