From 153fb543cf30a7a5791a32336fb2764b3b68e3aa Mon Sep 17 00:00:00 2001 From: Leynos Date: Thu, 19 Feb 2026 18:55:06 +0000 Subject: [PATCH 1/4] refactor(api): reorganize public API surface and improve import ergonomics The crate root exports are minimized to only canonical error/result types. Detailed APIs are moved to dedicated modules such as `client`, `response`, `serializer`, `hooks`, etc. Introduced an optional `prelude` module for common ergonomic imports. Tightened visibility of test-support items to avoid exposure in production builds. Updated documentation, examples, and tests to reflect new module paths and import styles. This restructuring promotes clearer public API boundaries and progressive API discovery, improving maintainability and user experience. Co-authored-by: devboxerhub[bot] --- docs/execplans/public-api-surface.md | 58 +++++++++--- docs/users-guide.md | 29 ++++-- docs/v0-1-0-to-v0-2-0-migration-guide.md | 90 +++++++++++++++++++ docs/wireframe-client-design.md | 5 +- examples/hotline_codec.rs | 2 +- examples/multi_packet.rs | 2 +- examples/mysql_codec.rs | 2 +- examples/resp_codec.rs | 2 +- src/app/envelope.rs | 3 +- src/client/builder/connect.rs | 2 +- src/client/builder/serializer.rs | 2 +- src/client/error.rs | 5 +- src/client/messaging.rs | 19 +++- src/client/response_stream.rs | 5 +- src/client/runtime.rs | 22 ++--- src/client/streaming.rs | 10 ++- src/client/tests/error_handling.rs | 3 +- src/client/tests/helpers.rs | 4 +- src/client/tests/messaging.rs | 3 +- src/client/tests/streaming.rs | 6 +- src/client/tests/streaming_infra.rs | 5 +- src/connection/mod.rs | 4 +- src/connection/test_support.rs | 4 +- src/extractor/streaming.rs | 3 +- src/hooks.rs | 7 +- src/lib.rs | 93 ++------------------ src/prelude.rs | 24 +++++ src/request/mod.rs | 5 +- src/response.rs | 8 +- tests/client_lifecycle.rs | 4 +- tests/client_preamble.rs | 3 +- tests/common/fragment_helpers.rs | 3 +- tests/common/unified_codec_transport.rs | 5 +- tests/connection.rs | 3 +- tests/connection_actor_errors.rs | 3 +- tests/connection_fragmentation.rs | 2 +- tests/correlation_id.rs | 2 +- tests/example_codecs.rs | 3 +- tests/fixtures/client_lifecycle.rs | 2 +- tests/fixtures/client_messaging.rs | 2 +- tests/fixtures/client_preamble.rs | 2 +- tests/fixtures/client_runtime.rs | 2 +- tests/fixtures/client_streaming.rs | 3 +- tests/fixtures/client_streaming/types.rs | 3 +- tests/fixtures/codec_error/decoder_ops.rs | 3 +- tests/fixtures/codec_stateful.rs | 3 +- tests/fixtures/message_assembly_inbound.rs | 3 +- tests/fixtures/multi_packet.rs | 2 +- tests/fixtures/unified_codec/transport.rs | 3 +- tests/fragment_transport.rs | 3 +- tests/frame_codec.rs | 3 +- tests/multi_packet.rs | 6 +- tests/response.rs | 3 +- tests/routes.rs | 6 +- tests/steps/client_lifecycle_steps.rs | 2 +- tests/steps/fragment_steps.rs | 2 +- tests/wireframe_protocol.rs | 3 +- wireframe_testing/src/echo_server.rs | 3 +- wireframe_testing/src/integration_helpers.rs | 5 +- wireframe_testing/src/multi_packet.rs | 4 +- 60 files changed, 317 insertions(+), 206 deletions(-) create mode 100644 src/prelude.rs diff --git a/docs/execplans/public-api-surface.md b/docs/execplans/public-api-surface.md index d6d8ec9c..f0dc8c9d 100644 --- a/docs/execplans/public-api-surface.md +++ b/docs/execplans/public-api-surface.md @@ -4,7 +4,7 @@ This ExecPlan is a living document. The sections `Constraints`, `Tolerances`, `Risks`, `Progress`, `Surprises & Discoveries`, `Decision Log`, and `Outcomes & Retrospective` must be kept up to date as work proceeds. -Status: DRAFT +Status: COMPLETE `PLANS.md` is not present in this repository at the time this plan was drafted. @@ -57,17 +57,26 @@ optional convenience prelude. Test-only helpers become private to tests (or to ## Progress - [x] (2026-02-18) Drafted ExecPlan for public API surface cleanup. -- [ ] Define target root API map and progressive discovery tiers. -- [ ] Refactor `src/lib.rs` exports to the target map. -- [ ] Tighten module visibility (`pub` to `pub(crate)` where applicable). -- [ ] Remove public test-only reachability from production builds. -- [ ] Update migration guide and user docs. -- [ ] Run full quality gates. +- [x] Define target root API map and progressive discovery tiers. +- [x] Refactor `src/lib.rs` exports to the target map. +- [x] Tighten module visibility (`pub` to `pub(crate)` where applicable). +- [x] Remove public test-only reachability from production builds. +- [x] Update migration guide and user docs. +- [x] Run full quality gates. ## Surprises & Discoveries -- Observation: None yet. - Evidence: Plan-only phase. Impact: None yet. +- Observation: Root re-export pruning required broad import rewrites across + tests, examples, and client test modules. Evidence: + `git diff --name-only | wc -l` returned `60` touched files. Impact: At the + tolerance boundary, and required iterative compile repair loops before moving + to full quality gates. + +- Observation: `connection::test_support` was publicly reachable in non-test + builds via `cfg(not(loom))`. Evidence: `src/connection/mod.rs` exported + `pub mod test_support` with only `not(loom)` gating. Impact: Tightened to + `cfg(all(not(loom), any(test, feature = "test-support")))` to keep it out of + normal production builds. ## Decision Log @@ -79,9 +88,36 @@ optional convenience prelude. Test-only helpers become private to tests (or to Rationale: Module paths communicate conceptual ownership and reduce root clutter. Date/Author: 2026-02-18 / Codex. +- Decision: Keep crate-root exports to canonical error/result aliases and move + high-frequency ergonomics to `wireframe::prelude`. Rationale: This preserves + a stable minimal root while still offering optional convenience imports. + Date/Author: 2026-02-19 / Codex. + +- Decision: Preserve the `test-support` feature for integration-test workflows + while removing default-build exposure of connection test helpers. Rationale: + Internal and companion tests continue to work without exposing test-only + helpers in standard library builds. Date/Author: 2026-02-19 / Codex. + ## Outcomes & Retrospective -Not started. Populate after implementation milestones complete. +Completed implementation outcomes: + +- Root API was reduced to canonical error/result aliases with detailed APIs + now discovered through module namespaces. +- `wireframe::prelude` was introduced as an optional ergonomics layer for + common imports. +- `connection::test_support` is no longer reachable in normal builds. +- Migration and user documentation now describe module-based imports and + include explicit before/after mappings for removed root re-exports. + +Validation outcomes: + +- `make fmt` passed. +- `make check-fmt` passed. +- `make lint` passed. +- `make test` passed. +- `make markdownlint` passed. +- `make nixie` passed. ## Context and orientation @@ -185,7 +221,7 @@ No new external dependencies are planned. Expected interface shape: -- `wireframe::` root exposes only canonical high-level entry points. +- `wireframe::` root exposes only canonical error/result aliases. - `wireframe::::...` is the default path for specialized APIs. - `wireframe::prelude::*` is optional convenience, not mandatory coupling. diff --git a/docs/users-guide.md b/docs/users-guide.md index 5dae20d4..586b2803 100644 --- a/docs/users-guide.md +++ b/docs/users-guide.md @@ -5,6 +5,16 @@ with pluggable routing, middleware, and connection utilities.[^1] The guide below walks through the components that exist today and explains how they work together when assembling an application. +## API discovery and imports + +Wireframe uses progressive discovery for public APIs: + +- `wireframe::` root is intentionally small and stable, exposing canonical + `Result` and `WireframeError`. +- `wireframe::::...` is the default path for specialised APIs. +- `wireframe::prelude::*` is an optional convenience import for common + workflows. + ## Quick start: building an application A `WireframeApp` collects route handlers and middleware. Each handler is stored @@ -290,7 +300,10 @@ The `WireframeProtocol` trait includes an `on_eof` hook for handling EOF conditions during frame decoding: ```rust,ignore -use wireframe::{ConnectionContext, EofError, WireframeProtocol}; +use wireframe::{ + codec::EofError, + hooks::{ConnectionContext, WireframeProtocol}, +}; impl WireframeProtocol for MyProtocol { type Frame = Vec; @@ -1081,7 +1094,7 @@ system, enabling consistent instrumentation across both client and server.[^48] use std::{net::SocketAddr, sync::Arc}; use std::sync::atomic::{AtomicUsize, Ordering}; -use wireframe::WireframeClient; +use wireframe::client::WireframeClient; struct SessionState { request_count: AtomicUsize, @@ -1144,10 +1157,10 @@ use std::net::SocketAddr; use wireframe::{ app::{Envelope, Packet}, - WireframeClient, + client::{ClientError, WireframeClient}, }; -# async fn example() -> Result<(), wireframe::ClientError> { +# async fn example() -> Result<(), ClientError> { let addr: SocketAddr = "127.0.0.1:7878".parse().expect("valid socket address"); let mut client = WireframeClient::builder() .connect(addr) @@ -1171,8 +1184,8 @@ separately: ```rust,no_run use wireframe::app::{Envelope, Packet}; -# use wireframe::WireframeClient; -# async fn example(client: &mut WireframeClient) -> Result<(), wireframe::ClientError> { +# use wireframe::client::{ClientError, WireframeClient}; +# async fn example(client: &mut WireframeClient) -> Result<(), ClientError> { // Auto-generate correlation ID when sending. let envelope = Envelope::new(1, None, b"payload".to_vec()); @@ -1429,7 +1442,7 @@ also prevents other client I/O until the stream is dropped or drained. ```rust,no_run use futures::StreamExt; use std::net::SocketAddr; -use wireframe::{ClientError, WireframeClient, app::Envelope}; +use wireframe::{app::Envelope, client::{ClientError, WireframeClient}}; # #[tokio::main] # async fn main() -> Result<(), ClientError> { @@ -1459,7 +1472,7 @@ consumed: ```rust,no_run use futures::StreamExt; use std::net::SocketAddr; -use wireframe::{ClientError, WireframeClient, app::Envelope}; +use wireframe::{app::Envelope, client::{ClientError, WireframeClient}}; # #[tokio::main] # async fn main() -> Result<(), ClientError> { diff --git a/docs/v0-1-0-to-v0-2-0-migration-guide.md b/docs/v0-1-0-to-v0-2-0-migration-guide.md index 7dc6caee..6bb2352b 100644 --- a/docs/v0-1-0-to-v0-2-0-migration-guide.md +++ b/docs/v0-1-0-to-v0-2-0-migration-guide.md @@ -75,3 +75,93 @@ use wireframe::response::WireframeError as StreamError; use wireframe::WireframeError; use wireframe::Result; ``` + +## Public API surface reorganization + +The crate root is now intentionally minimal. Detailed APIs moved to their +owning modules, and root re-exports were removed. + +- Root now exposes canonical `wireframe::Result` and + `wireframe::WireframeError`. +- Use `wireframe::::...` for specialised APIs. +- `wireframe::prelude::*` is available as an optional convenience import for + high-frequency types. + +### Removed root re-exports and their new module paths + +- `wireframe::AppDataStore` -> + `wireframe::app_data_store::AppDataStore` +- `wireframe::BincodeSerializer`, `wireframe::Serializer` -> + `wireframe::serializer::{BincodeSerializer, Serializer}` +- `wireframe::ConnectionActor` -> + `wireframe::connection::ConnectionActor` +- `wireframe::CorrelatableFrame` -> + `wireframe::correlation::CorrelatableFrame` +- `wireframe::ConnectionContext`, `wireframe::ProtocolHooks`, + `wireframe::WireframeProtocol` -> + `wireframe::hooks::{ConnectionContext, ProtocolHooks, WireframeProtocol}` +- `wireframe::ClientCodecConfig`, `wireframe::ClientError`, + `wireframe::ClientProtocolError`, `wireframe::ClientWireframeError`, + `wireframe::SocketOptions`, `wireframe::WireframeClient` -> + `wireframe::client::{...}` +- `wireframe::CodecError`, `wireframe::CodecErrorContext`, + `wireframe::DefaultRecoveryPolicy`, `wireframe::EofError`, + `wireframe::FrameCodec`, `wireframe::FramingError`, + `wireframe::LengthDelimitedFrameCodec`, `wireframe::MAX_FRAME_LENGTH`, + `wireframe::MIN_FRAME_LENGTH`, `wireframe::ProtocolError`, + `wireframe::RecoveryConfig`, `wireframe::RecoveryPolicy`, + `wireframe::RecoveryPolicyHook` -> `wireframe::codec::{...}` +- `wireframe::DefaultFragmentAdapter`, `wireframe::FRAGMENT_MAGIC`, + `wireframe::FragmentAdapter`, `wireframe::FragmentAdapterError`, + `wireframe::FragmentBatch`, `wireframe::FragmentError`, + `wireframe::FragmentFrame`, `wireframe::FragmentHeader`, + `wireframe::FragmentIndex`, `wireframe::FragmentSeries`, + `wireframe::FragmentStatus`, `wireframe::FragmentationConfig`, + `wireframe::FragmentationError`, `wireframe::Fragmenter`, + `wireframe::MessageId`, `wireframe::ReassembledMessage`, + `wireframe::Reassembler`, `wireframe::ReassemblyError`, + `wireframe::decode_fragment_payload`, `wireframe::encode_fragment_payload`, + `wireframe::fragment_overhead` -> `wireframe::fragment::{...}` +- `wireframe::AssembledMessage`, `wireframe::ContinuationFrameHeader`, + `wireframe::FirstFrameHeader`, `wireframe::FirstFrameInput`, + `wireframe::FirstFrameInputError`, `wireframe::FrameHeader`, + `wireframe::FrameSequence`, `wireframe::MessageAssembler`, + `wireframe::MessageAssemblyError`, `wireframe::MessageAssemblyState`, + `wireframe::MessageKey`, `wireframe::MessageSeries`, + `wireframe::MessageSeriesError`, `wireframe::MessageSeriesStatus`, + `wireframe::ParsedFrameHeader` -> `wireframe::message_assembler::{...}` +- `wireframe::CODEC_ERRORS`, `wireframe::CONNECTIONS_ACTIVE`, + `wireframe::Direction`, `wireframe::ERRORS_TOTAL`, + `wireframe::FRAMES_PROCESSED` -> `wireframe::metrics::{...}` +- `wireframe::DEFAULT_BODY_CHANNEL_CAPACITY`, + `wireframe::RequestBodyReader`, `wireframe::RequestBodyStream`, + `wireframe::RequestParts`, `wireframe::body_channel` -> + `wireframe::request::{...}` +- `wireframe::FrameStream`, `wireframe::Response` -> + `wireframe::response::{FrameStream, Response}` +- `wireframe::ConnectionId`, `wireframe::SessionRegistry` -> + `wireframe::session::{ConnectionId, SessionRegistry}` + +Example migration: + +```rust +// Before +use wireframe::{Response, Serializer, WireframeClient}; + +// After +use wireframe::{ + client::WireframeClient, + response::Response, + serializer::Serializer, +}; +``` + +## Test support visibility changes + +Connection actor test helpers are no longer reachable in normal builds. + +- `wireframe::connection::test_support` now requires + `cfg(any(test, feature = "test-support"))` in addition to `cfg(not(loom))`. +- Production consumers should not depend on `connection::test_support`. +- Internal and integration test suites can continue to use the `test-support` + feature where required. diff --git a/docs/wireframe-client-design.md b/docs/wireframe-client-design.md index 886e2491..db5d679b 100644 --- a/docs/wireframe-client-design.md +++ b/docs/wireframe-client-design.md @@ -38,7 +38,10 @@ A `WireframeClient::builder()` method configures the client: ```rust use std::net::SocketAddr; -use wireframe::{BincodeSerializer, WireframeClient}; +use wireframe::{ + client::WireframeClient, + serializer::BincodeSerializer, +}; let addr: SocketAddr = "127.0.0.1:7878".parse()?; let client = WireframeClient::builder() diff --git a/examples/hotline_codec.rs b/examples/hotline_codec.rs index 6c9f2fd0..8239b624 100644 --- a/examples/hotline_codec.rs +++ b/examples/hotline_codec.rs @@ -8,9 +8,9 @@ use std::io; use wireframe::{ - BincodeSerializer, app::{Envelope, WireframeApp}, codec::examples::HotlineFrameCodec, + serializer::BincodeSerializer, }; fn main() -> io::Result<()> { diff --git a/examples/multi_packet.rs b/examples/multi_packet.rs index d0ffae46..1e55b6a5 100644 --- a/examples/multi_packet.rs +++ b/examples/multi_packet.rs @@ -10,7 +10,7 @@ use std::time::Duration; use futures::TryStreamExt; use tokio::time::sleep; use tracing::info; -use wireframe::{Response, WireframeError}; +use wireframe::{WireframeError, response::Response}; const TRANSCRIPT: &[&str] = &[ "Client: HELLO", diff --git a/examples/mysql_codec.rs b/examples/mysql_codec.rs index 8691f87b..2e8012a2 100644 --- a/examples/mysql_codec.rs +++ b/examples/mysql_codec.rs @@ -8,9 +8,9 @@ use std::io; use wireframe::{ - BincodeSerializer, app::{Envelope, WireframeApp}, codec::examples::MysqlFrameCodec, + serializer::BincodeSerializer, }; fn main() -> io::Result<()> { diff --git a/examples/resp_codec.rs b/examples/resp_codec.rs index 5c7e2907..ab505564 100644 --- a/examples/resp_codec.rs +++ b/examples/resp_codec.rs @@ -17,8 +17,8 @@ mod resp_codec_impl; pub use resp_codec_impl::{codec::RespFrameCodec, frame::RespFrame}; use wireframe::{ - BincodeSerializer, app::{Envelope, WireframeApp}, + serializer::BincodeSerializer, }; fn main() -> io::Result<()> { diff --git a/src/app/envelope.rs b/src/app/envelope.rs index 02702abd..a778a068 100644 --- a/src/app/envelope.rs +++ b/src/app/envelope.rs @@ -76,7 +76,8 @@ pub trait Packet: CorrelatableFrame + Message + Send + Sync + 'static { /// The default implementation returns `false`. Protocol implementations /// should override this to detect the protocol-specific terminator format /// emitted by the server's - /// [`stream_end_frame`](crate::WireframeProtocol::stream_end_frame) hook. + /// [`stream_end_frame`](crate::hooks::WireframeProtocol::stream_end_frame) + /// hook. /// /// # Examples /// diff --git a/src/client/builder/connect.rs b/src/client/builder/connect.rs index f72ed4b8..d7bc3a10 100644 --- a/src/client/builder/connect.rs +++ b/src/client/builder/connect.rs @@ -39,7 +39,7 @@ where /// ```no_run /// use std::net::SocketAddr; /// - /// use wireframe::{ClientError, WireframeClient}; + /// use wireframe::client::{ClientError, WireframeClient}; /// /// # #[tokio::main] /// # async fn main() -> Result<(), ClientError> { diff --git a/src/client/builder/serializer.rs b/src/client/builder/serializer.rs index be646f27..d64a3de0 100644 --- a/src/client/builder/serializer.rs +++ b/src/client/builder/serializer.rs @@ -12,7 +12,7 @@ where /// # Examples /// /// ``` - /// use wireframe::{BincodeSerializer, client::WireframeClientBuilder}; + /// use wireframe::{client::WireframeClientBuilder, serializer::BincodeSerializer}; /// /// let builder = WireframeClientBuilder::new().serializer(BincodeSerializer); /// let _ = builder; diff --git a/src/client/error.rs b/src/client/error.rs index fdadbca8..48ac7108 100644 --- a/src/client/error.rs +++ b/src/client/error.rs @@ -22,7 +22,7 @@ pub enum ClientProtocolError { /// [`ClientProtocolError`]. pub type ClientWireframeError = WireframeError; -/// Errors emitted by [`crate::WireframeClient`]. +/// Errors emitted by [`crate::client::WireframeClient`]. #[derive(Debug, thiserror::Error)] pub enum ClientError { /// Request/response transport or protocol failure. @@ -45,7 +45,8 @@ pub enum ClientError { PreambleTimeout, /// Response correlation ID does not match the request. /// - /// This error is returned by [`crate::WireframeClient::call_correlated`] + /// This error is returned by + /// [`crate::client::WireframeClient::call_correlated`] /// when the response envelope's correlation ID differs from the request's. #[error("correlation ID mismatch: expected {expected:?}, received {received:?}")] CorrelationMismatch { diff --git a/src/client/messaging.rs b/src/client/messaging.rs index 357e18aa..305dd6ae 100644 --- a/src/client/messaging.rs +++ b/src/client/messaging.rs @@ -46,7 +46,7 @@ where /// ```no_run /// use std::net::SocketAddr; /// - /// use wireframe::{ClientError, WireframeClient}; + /// use wireframe::client::{ClientError, WireframeClient}; /// /// # #[tokio::main] /// # async fn main() -> Result<(), ClientError> { @@ -86,7 +86,11 @@ where /// ```no_run /// use std::net::SocketAddr; /// - /// use wireframe::{ClientError, CorrelatableFrame, WireframeClient, app::Envelope}; + /// use wireframe::{ + /// app::Envelope, + /// client::{ClientError, WireframeClient}, + /// correlation::CorrelatableFrame, + /// }; /// /// # #[tokio::main] /// # async fn main() -> Result<(), ClientError> { @@ -144,7 +148,11 @@ where /// ```no_run /// use std::net::SocketAddr; /// - /// use wireframe::{ClientError, CorrelatableFrame, WireframeClient, app::Envelope}; + /// use wireframe::{ + /// app::Envelope, + /// client::{ClientError, WireframeClient}, + /// correlation::CorrelatableFrame, + /// }; /// /// # #[tokio::main] /// # async fn main() -> Result<(), ClientError> { @@ -179,7 +187,10 @@ where /// ```no_run /// use std::net::SocketAddr; /// - /// use wireframe::{ClientError, WireframeClient, app::Envelope}; + /// use wireframe::{ + /// app::Envelope, + /// client::{ClientError, WireframeClient}, + /// }; /// /// # #[tokio::main] /// # async fn main() -> Result<(), ClientError> { diff --git a/src/client/response_stream.rs b/src/client/response_stream.rs index 24caeef6..3215049c 100644 --- a/src/client/response_stream.rs +++ b/src/client/response_stream.rs @@ -37,7 +37,10 @@ use crate::{app::Packet, serializer::Serializer}; /// use std::net::SocketAddr; /// /// use futures::StreamExt; -/// use wireframe::{ClientError, WireframeClient, app::Envelope}; +/// use wireframe::{ +/// app::Envelope, +/// client::{ClientError, WireframeClient}, +/// }; /// /// # #[tokio::main] /// # async fn main() -> Result<(), ClientError> { diff --git a/src/client/runtime.rs b/src/client/runtime.rs index c2d33910..12c3673b 100644 --- a/src/client/runtime.rs +++ b/src/client/runtime.rs @@ -45,10 +45,10 @@ impl ClientStream for T where T: AsyncRead + AsyncWrite + Unpin {} /// ```no_run /// use std::net::SocketAddr; /// -/// use wireframe::WireframeClient; +/// use wireframe::client::WireframeClient; /// /// # #[tokio::main] -/// # async fn main() -> Result<(), wireframe::ClientError> { +/// # async fn main() -> Result<(), wireframe::client::ClientError> { /// let addr: SocketAddr = "127.0.0.1:9000".parse().expect("valid socket address"); /// let _client = WireframeClient::builder().connect(addr).await?; /// # Ok(()) @@ -87,10 +87,10 @@ impl WireframeClient { /// ```no_run /// use std::net::SocketAddr; /// - /// use wireframe::WireframeClient; + /// use wireframe::client::WireframeClient; /// /// # #[tokio::main] - /// # async fn main() -> Result<(), wireframe::ClientError> { + /// # async fn main() -> Result<(), wireframe::client::ClientError> { /// let addr: SocketAddr = "127.0.0.1:9000".parse().expect("valid socket address"); /// let _client = WireframeClient::builder().connect(addr).await?; /// # Ok(()) @@ -123,7 +123,7 @@ where /// ```no_run /// use std::net::SocketAddr; /// - /// use wireframe::{ClientError, WireframeClient}; + /// use wireframe::client::{ClientError, WireframeClient}; /// /// #[derive(bincode::Encode, bincode::BorrowDecode)] /// struct Ping(u8); @@ -169,7 +169,7 @@ where /// ```no_run /// use std::net::SocketAddr; /// - /// use wireframe::{ClientError, WireframeClient}; + /// use wireframe::client::{ClientError, WireframeClient}; /// /// #[derive(bincode::Encode, bincode::BorrowDecode, Debug, PartialEq)] /// struct Pong(u8); @@ -202,7 +202,7 @@ where /// ```no_run /// use std::net::SocketAddr; /// - /// use wireframe::{ClientError, WireframeClient}; + /// use wireframe::client::{ClientError, WireframeClient}; /// /// #[derive(bincode::Encode, bincode::BorrowDecode)] /// struct Login { @@ -240,7 +240,7 @@ where /// ```no_run /// use std::net::SocketAddr; /// - /// use wireframe::{ClientError, WireframeClient}; + /// use wireframe::client::{ClientError, WireframeClient}; /// /// # #[tokio::main] /// # async fn main() -> Result<(), ClientError> { @@ -261,7 +261,7 @@ where /// ```no_run /// use std::net::SocketAddr; /// - /// use wireframe::{ClientError, WireframeClient}; + /// use wireframe::client::{ClientError, WireframeClient}; /// /// # #[tokio::main] /// # async fn main() -> Result<(), ClientError> { @@ -287,7 +287,7 @@ where /// ```no_run /// use std::net::SocketAddr; /// - /// use wireframe::{ClientError, WireframeClient}; + /// use wireframe::client::{ClientError, WireframeClient}; /// /// # #[tokio::main] /// # async fn main() -> Result<(), ClientError> { @@ -319,7 +319,7 @@ where /// ```no_run /// use std::net::SocketAddr; /// - /// use wireframe::{ClientError, WireframeClient}; + /// use wireframe::client::{ClientError, WireframeClient}; /// /// struct Session { /// id: u64, diff --git a/src/client/streaming.rs b/src/client/streaming.rs index 82b53af3..ab7943f3 100644 --- a/src/client/streaming.rs +++ b/src/client/streaming.rs @@ -46,7 +46,10 @@ where /// use std::net::SocketAddr; /// /// use futures::StreamExt; - /// use wireframe::{ClientError, WireframeClient, app::Envelope}; + /// use wireframe::{ + /// app::Envelope, + /// client::{ClientError, WireframeClient}, + /// }; /// /// # #[tokio::main] /// # async fn main() -> Result<(), ClientError> { @@ -109,7 +112,10 @@ where /// use std::net::SocketAddr; /// /// use futures::StreamExt; - /// use wireframe::{ClientError, WireframeClient, app::Envelope}; + /// use wireframe::{ + /// app::Envelope, + /// client::{ClientError, WireframeClient}, + /// }; /// /// # #[tokio::main] /// # async fn main() -> Result<(), ClientError> { diff --git a/src/client/tests/error_handling.rs b/src/client/tests/error_handling.rs index 9d87ddde..0b64d275 100644 --- a/src/client/tests/error_handling.rs +++ b/src/client/tests/error_handling.rs @@ -23,6 +23,7 @@ use crate::{ WireframeError, client::{ClientError, ClientProtocolError, WireframeClient, WireframeClientBuilder}, rewind_stream::RewindStream, + serializer::Serializer, }; /// Connects a client and returns both the client and server stream for custom server behaviour. @@ -33,7 +34,7 @@ async fn connect_with_server( configure_builder: F, ) -> (WireframeClient, C>, TcpStream) where - S: crate::Serializer + Send + Sync + 'static, + S: Serializer + Send + Sync + 'static, F: FnOnce(WireframeClientBuilder) -> WireframeClientBuilder, C: Send + 'static, { diff --git a/src/client/tests/helpers.rs b/src/client/tests/helpers.rs index fc74ec2b..b6d7be36 100644 --- a/src/client/tests/helpers.rs +++ b/src/client/tests/helpers.rs @@ -13,8 +13,8 @@ use std::{ use tokio::net::{TcpListener, TcpStream}; use crate::{ - BincodeSerializer, client::{ClientError, WireframeClient, WireframeClientBuilder}, + serializer::{BincodeSerializer, Serializer}, }; /// Type alias for async hooks that return their input after performing side effects. @@ -131,7 +131,7 @@ where /// A serializer that always fails to serialize, used for testing error hooks. pub struct FailingSerializer; -impl crate::Serializer for FailingSerializer { +impl Serializer for FailingSerializer { fn serialize( &self, _value: &M, diff --git a/src/client/tests/messaging.rs b/src/client/tests/messaging.rs index e22039d1..5514cbf8 100644 --- a/src/client/tests/messaging.rs +++ b/src/client/tests/messaging.rs @@ -13,10 +13,9 @@ use tokio_util::codec::{Framed, LengthDelimitedCodec}; use wireframe_testing::{ServerMode, process_frame}; use crate::{ - WireframeClient, WireframeError, app::{Envelope, Packet}, - client::ClientError, + client::{ClientError, WireframeClient}, correlation::CorrelatableFrame, }; diff --git a/src/client/tests/streaming.rs b/src/client/tests/streaming.rs index d5a30144..7171865a 100644 --- a/src/client/tests/streaming.rs +++ b/src/client/tests/streaming.rs @@ -19,7 +19,11 @@ use super::streaming_infra::{ spawn_mismatch_server, spawn_test_server, }; -use crate::{BincodeSerializer, Serializer, client::ClientError, correlation::CorrelatableFrame}; +use crate::{ + client::ClientError, + correlation::CorrelatableFrame, + serializer::{BincodeSerializer, Serializer}, +}; /// Verify a stream yields exactly one data frame with the expected payload /// and then terminates cleanly. diff --git a/src/client/tests/streaming_infra.rs b/src/client/tests/streaming_infra.rs index 20c2c702..83601b0d 100644 --- a/src/client/tests/streaming_infra.rs +++ b/src/client/tests/streaming_infra.rs @@ -13,12 +13,11 @@ use tokio::net::TcpListener; use tokio_util::codec::{Framed, LengthDelimitedCodec}; use crate::{ - BincodeSerializer, - Serializer, - WireframeClient, app::Packet, + client::WireframeClient, correlation::CorrelatableFrame, rewind_stream::RewindStream, + serializer::{BincodeSerializer, Serializer}, }; // --------------------------------------------------------------------------- diff --git a/src/connection/mod.rs b/src/connection/mod.rs index 1a00206a..7a016811 100644 --- a/src/connection/mod.rs +++ b/src/connection/mod.rs @@ -230,7 +230,7 @@ where /// ```no_run /// # use tokio::sync::mpsc; /// # use tokio_util::sync::CancellationToken; - /// # use wireframe::{ConnectionActor, push::PushQueues}; + /// # use wireframe::{connection::ConnectionActor, push::PushQueues}; /// # let (queues, handle) = PushQueues::::builder() /// # .high_capacity(1) /// # .low_capacity(1) @@ -370,5 +370,5 @@ where } } -#[cfg(not(loom))] +#[cfg(all(not(loom), any(test, feature = "test-support")))] pub mod test_support; diff --git a/src/connection/test_support.rs b/src/connection/test_support.rs index b3f57bf9..e797e929 100644 --- a/src/connection/test_support.rs +++ b/src/connection/test_support.rs @@ -1,7 +1,7 @@ //! Helpers for exercising private connection actor paths in integration tests. -// These helpers compile for all non-Loom builds so integration tests can -// exercise private connection actor paths. +// These helpers compile only for crate tests or the `test-support` feature so +// integration tests can exercise private connection actor paths. use tokio::sync::mpsc; use tokio_util::sync::CancellationToken; diff --git a/src/extractor/streaming.rs b/src/extractor/streaming.rs index 6bcd70db..51fd6d18 100644 --- a/src/extractor/streaming.rs +++ b/src/extractor/streaming.rs @@ -8,7 +8,8 @@ use super::{ExtractError, FromMessageRequest, MessageRequest, Payload}; /// takes ownership of a streaming body channel. Handlers opting into /// streaming receive chunks incrementally via a [`RequestBodyStream`]. /// -/// This type is the inbound counterpart to [`crate::Response::Stream`]. +/// This type is the inbound counterpart to +/// [`crate::response::Response::Stream`]. /// /// # Examples /// diff --git a/src/hooks.rs b/src/hooks.rs index 4b7f1381..f1e2d135 100644 --- a/src/hooks.rs +++ b/src/hooks.rs @@ -48,7 +48,7 @@ pub trait WireframeProtocol: Send + Sync + 'static { /// Called when a handler returns a [`crate::WireframeError::Protocol`]. /// /// ```rust,ignore - /// use wireframe::{ConnectionContext, WireframeProtocol}; + /// use wireframe::hooks::{ConnectionContext, WireframeProtocol}; /// /// struct MyProtocol; /// @@ -84,7 +84,10 @@ pub trait WireframeProtocol: Send + Sync + 'static { /// # Examples /// /// ```rust,ignore - /// use wireframe::{ConnectionContext, EofError, WireframeProtocol}; + /// use wireframe::{ + /// codec::EofError, + /// hooks::{ConnectionContext, WireframeProtocol}, + /// }; /// /// struct MyProtocol; /// diff --git a/src/lib.rs b/src/lib.rs index 720afd4c..9d628902 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,35 +3,22 @@ //! //! This crate provides building blocks for asynchronous binary protocol //! servers, including routing, middleware, and connection utilities. +//! +//! Public API discovery is tiered: +//! - Root exports stay intentionally small and stable. +//! - Domain modules hold detailed APIs (`app`, `server`, `client`, and so on). +//! - [`prelude`] offers optional convenience imports for common workflows. extern crate self as wireframe; pub mod app; pub mod app_data_store; pub mod byte_order; -pub mod codec; -pub mod error; -pub use app_data_store::AppDataStore; #[cfg(not(loom))] pub mod client; -pub mod serializer; -pub use codec::{ - CodecError, - CodecErrorContext, - DefaultRecoveryPolicy, - EofError, - FrameCodec, - FramingError, - LengthDelimitedFrameCodec, - MAX_FRAME_LENGTH, - MIN_FRAME_LENGTH, - ProtocolError, - RecoveryConfig, - RecoveryPolicy, - RecoveryPolicyHook, -}; +pub mod codec; +pub mod error; pub use error::{Result, WireframeError}; -pub use serializer::{BincodeSerializer, Serializer}; pub mod connection; pub mod correlation; #[cfg(not(loom))] @@ -46,77 +33,15 @@ pub mod metrics; pub mod middleware; pub mod panic; pub mod preamble; +pub mod prelude; pub mod push; #[cfg(not(loom))] pub mod request; pub mod response; pub mod rewind_stream; +pub mod serializer; #[cfg(not(loom))] pub mod server; pub mod session; #[cfg(any(test, feature = "test-support"))] pub mod test_helpers; - -#[cfg(not(loom))] -pub use client::{ - ClientCodecConfig, - ClientError, - ClientProtocolError, - ClientWireframeError, - SocketOptions, - WireframeClient, -}; -pub use connection::ConnectionActor; -pub use correlation::CorrelatableFrame; -pub use fragment::{ - DefaultFragmentAdapter, - FRAGMENT_MAGIC, - FragmentAdapter, - FragmentAdapterError, - FragmentBatch, - FragmentError, - FragmentFrame, - FragmentHeader, - FragmentIndex, - FragmentSeries, - FragmentStatus, - FragmentationConfig, - FragmentationError, - Fragmenter, - MessageId, - ReassembledMessage, - Reassembler, - ReassemblyError, - decode_fragment_payload, - encode_fragment_payload, - fragment_overhead, -}; -pub use hooks::{ConnectionContext, ProtocolHooks, WireframeProtocol}; -pub use message_assembler::{ - AssembledMessage, - ContinuationFrameHeader, - FirstFrameHeader, - FirstFrameInput, - FirstFrameInputError, - FrameHeader, - FrameSequence, - MessageAssembler, - MessageAssemblyError, - MessageAssemblyState, - MessageKey, - MessageSeries, - MessageSeriesError, - MessageSeriesStatus, - ParsedFrameHeader, -}; -pub use metrics::{CODEC_ERRORS, CONNECTIONS_ACTIVE, Direction, ERRORS_TOTAL, FRAMES_PROCESSED}; -#[cfg(not(loom))] -pub use request::{ - DEFAULT_BODY_CHANNEL_CAPACITY, - RequestBodyReader, - RequestBodyStream, - RequestParts, - body_channel, -}; -pub use response::{FrameStream, Response}; -pub use session::{ConnectionId, SessionRegistry}; diff --git a/src/prelude.rs b/src/prelude.rs new file mode 100644 index 00000000..c0958898 --- /dev/null +++ b/src/prelude.rs @@ -0,0 +1,24 @@ +//! Optional convenience imports for common Wireframe workflows. +//! +//! This module is intentionally small and focused on high-frequency types. +//! Prefer importing specialised APIs directly from their owning modules. +//! +//! # Examples +//! +//! ```rust,no_run +//! use wireframe::prelude::*; +//! +//! fn build() -> Result { WireframeApp::new() } +//! ``` + +#[cfg(not(loom))] +pub use crate::client::{ClientError, WireframeClient}; +#[cfg(not(loom))] +pub use crate::server::{ServerError, WireframeServer}; +pub use crate::{ + app::{Envelope, Handler, Middleware, WireframeApp}, + error::{Result, WireframeError}, + message::Message, + response::Response, + serializer::{BincodeSerializer, Serializer}, +}; diff --git a/src/request/mod.rs b/src/request/mod.rs index 7378afec..331a0ce7 100644 --- a/src/request/mod.rs +++ b/src/request/mod.rs @@ -38,7 +38,8 @@ use tokio_util::io::StreamReader; /// full body reassembly. Each item yields either a chunk of bytes or an /// I/O error. /// -/// This type is symmetric with [`crate::FrameStream`] for streaming responses. +/// This type is symmetric with [`crate::response::FrameStream`] for streaming +/// responses. /// See ADR 0002 for design rationale. /// /// # Examples @@ -198,7 +199,7 @@ impl AsyncRead for RequestBodyReader { /// `RequestParts` separates routing and protocol metadata from the request /// payload, enabling handlers to begin processing before the full body /// arrives. This struct is the counterpart to streaming response types -/// ([`crate::Response::Stream`]) for the inbound direction. +/// ([`crate::response::Response::Stream`]) for the inbound direction. /// /// # Differences from [`crate::app::PacketParts`] /// diff --git a/src/response.rs b/src/response.rs index e5ce0eb3..b544dab3 100644 --- a/src/response.rs +++ b/src/response.rs @@ -8,7 +8,7 @@ //! //! ``` //! use futures::{StreamExt, stream}; -//! use wireframe::Response; +//! use wireframe::response::Response; //! //! # type Frame = u8; //! # type Error = (); @@ -78,7 +78,7 @@ pub enum Response { /// /// ```rust,no_run /// use tokio::sync::mpsc; - /// use wireframe::Response; + /// use wireframe::response::Response; /// /// async fn demo() { /// let (tx, rx) = mpsc::channel(1); @@ -134,7 +134,7 @@ impl Response { /// /// ```rust,no_run /// use tokio::spawn; - /// use wireframe::Response; + /// use wireframe::response::Response; /// /// async fn stream_frames() -> (tokio::sync::mpsc::Sender, Response) { /// let (sender, response) = Response::with_channel(8); @@ -168,7 +168,7 @@ impl Response { /// /// ``` /// use futures::TryStreamExt; - /// use wireframe::Response; + /// use wireframe::response::Response; /// /// # async fn demo() { /// let (tx, rx) = tokio::sync::mpsc::channel(1); diff --git a/tests/client_lifecycle.rs b/tests/client_lifecycle.rs index 8826e856..af73b7a1 100644 --- a/tests/client_lifecycle.rs +++ b/tests/client_lifecycle.rs @@ -14,7 +14,7 @@ use std::sync::{ }; use tokio::net::TcpListener; -use wireframe::WireframeClient; +use wireframe::client::WireframeClient; use wireframe_testing::TestResult; /// Test that setup and teardown callbacks are both invoked for a full @@ -107,7 +107,7 @@ async fn client_error_hook_invoked_on_disconnect() -> TestResult<()> { server.await?; // Try to receive - should fail and invoke error hook - let result: Result, wireframe::ClientError> = client.receive().await; + let result: Result, wireframe::client::ClientError> = client.receive().await; assert!(result.is_err(), "receive should fail after disconnect"); assert_eq!( diff --git a/tests/client_preamble.rs b/tests/client_preamble.rs index eab24e85..78bd33d4 100644 --- a/tests/client_preamble.rs +++ b/tests/client_preamble.rs @@ -12,8 +12,7 @@ use futures::FutureExt; use rstest::rstest; use tokio::{io::AsyncReadExt, net::TcpListener, sync::oneshot, time::timeout}; use wireframe::{ - ClientError, - client::WireframeClient, + client::{ClientError, WireframeClient}, preamble::{read_preamble, write_preamble}, }; use wireframe_testing::TestResult; diff --git a/tests/common/fragment_helpers.rs b/tests/common/fragment_helpers.rs index 9a78014b..ea576a94 100644 --- a/tests/common/fragment_helpers.rs +++ b/tests/common/fragment_helpers.rs @@ -13,7 +13,6 @@ use tokio::{ }; use tokio_util::codec::{Framed, LengthDelimitedCodec}; use wireframe::{ - Serializer, app::{Envelope, Handler, Packet, WireframeApp}, fragment::{ FragmentationConfig, @@ -23,7 +22,7 @@ use wireframe::{ decode_fragment_payload, encode_fragment_payload, }, - serializer::BincodeSerializer, + serializer::{BincodeSerializer, Serializer}, }; pub type TestResult = Result; diff --git a/tests/common/unified_codec_transport.rs b/tests/common/unified_codec_transport.rs index af7c4336..48aece37 100644 --- a/tests/common/unified_codec_transport.rs +++ b/tests/common/unified_codec_transport.rs @@ -8,7 +8,10 @@ use std::time::Duration; use futures::{SinkExt, StreamExt}; use tokio::time::timeout; use tokio_util::codec::{Framed, LengthDelimitedCodec}; -use wireframe::{Serializer, app::Envelope, serializer::BincodeSerializer}; +use wireframe::{ + app::Envelope, + serializer::{BincodeSerializer, Serializer}, +}; /// Shared result type for helper functions in this module. pub type SharedTestResult = Result>; diff --git a/tests/connection.rs b/tests/connection.rs index 4216f5f5..fffaae16 100644 --- a/tests/connection.rs +++ b/tests/connection.rs @@ -11,9 +11,8 @@ use rstest::{fixture, rstest}; use serial_test::serial; use tokio::sync::mpsc; use wireframe::{ - ProtocolHooks, connection::test_support::{ActorHarness, ActorStateHarness, poll_queue_next}, - hooks::ConnectionContext, + hooks::{ConnectionContext, ProtocolHooks}, }; use wireframe_testing::{LoggerHandle, TestResult, logger}; diff --git a/tests/connection_actor_errors.rs b/tests/connection_actor_errors.rs index 0bdd1227..881ad105 100644 --- a/tests/connection_actor_errors.rs +++ b/tests/connection_actor_errors.rs @@ -14,9 +14,8 @@ use rstest::{fixture, rstest}; use serial_test::serial; use tokio_util::sync::CancellationToken; use wireframe::{ - ConnectionContext, - ProtocolHooks, connection::{ConnectionActor, ConnectionChannels}, + hooks::{ConnectionContext, ProtocolHooks}, push::PushQueues, response::WireframeError, }; diff --git a/tests/connection_fragmentation.rs b/tests/connection_fragmentation.rs index 262e4c48..f2ee1965 100644 --- a/tests/connection_fragmentation.rs +++ b/tests/connection_fragmentation.rs @@ -8,8 +8,8 @@ use std::{io, num::NonZeroUsize, time::Duration}; use tokio_util::sync::CancellationToken; use wireframe::{ - ConnectionActor, app::{Envelope, Packet}, + connection::ConnectionActor, fragment::{FragmentationConfig, Reassembler, decode_fragment_payload}, push::{PushHandle, PushQueues}, }; diff --git a/tests/correlation_id.rs b/tests/correlation_id.rs index 2a158e34..82c56b7c 100644 --- a/tests/correlation_id.rs +++ b/tests/correlation_id.rs @@ -7,9 +7,9 @@ use rstest::rstest; use tokio::sync::mpsc; use tokio_util::sync::CancellationToken; use wireframe::{ - CorrelatableFrame, app::Envelope, connection::{ConnectionActor, ConnectionChannels}, + correlation::CorrelatableFrame, hooks::{ConnectionContext, ProtocolHooks}, push::PushQueues, response::FrameStream, diff --git a/tests/example_codecs.rs b/tests/example_codecs.rs index b8913492..3df1261b 100644 --- a/tests/example_codecs.rs +++ b/tests/example_codecs.rs @@ -7,14 +7,13 @@ use bytes::{BufMut, Bytes, BytesMut}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio_util::codec::{Decoder, Encoder}; use wireframe::{ - BincodeSerializer, - Serializer, app::{Envelope, Packet, WireframeApp}, codec::{ FrameCodec, examples::{HotlineFrame, HotlineFrameCodec, MysqlFrame, MysqlFrameCodec}, }, correlation::CorrelatableFrame, + serializer::{BincodeSerializer, Serializer}, }; #[test] diff --git a/tests/fixtures/client_lifecycle.rs b/tests/fixtures/client_lifecycle.rs index 8f1529c8..12931612 100644 --- a/tests/fixtures/client_lifecycle.rs +++ b/tests/fixtures/client_lifecycle.rs @@ -24,10 +24,10 @@ use futures::FutureExt; use rstest::fixture; use tokio::{net::TcpListener, task::JoinHandle}; use wireframe::{ - BincodeSerializer, client::{ClientError, WireframeClient}, preamble::{read_preamble, write_preamble}, rewind_stream::RewindStream, + serializer::BincodeSerializer, }; /// Re-export `TestResult` from `wireframe_testing` for use in steps. pub use wireframe_testing::TestResult; diff --git a/tests/fixtures/client_messaging.rs b/tests/fixtures/client_messaging.rs index 99fcadfc..1022df76 100644 --- a/tests/fixtures/client_messaging.rs +++ b/tests/fixtures/client_messaging.rs @@ -11,11 +11,11 @@ use rstest::fixture; use tokio::{net::TcpListener, task::JoinHandle}; use tokio_util::codec::{Framed, LengthDelimitedCodec}; use wireframe::{ - BincodeSerializer, app::{Envelope, Packet}, client::{ClientError, WireframeClient}, correlation::CorrelatableFrame, rewind_stream::RewindStream, + serializer::BincodeSerializer, }; /// `TestResult` for step definitions. pub use wireframe_testing::TestResult; diff --git a/tests/fixtures/client_preamble.rs b/tests/fixtures/client_preamble.rs index 4500a369..146c159e 100644 --- a/tests/fixtures/client_preamble.rs +++ b/tests/fixtures/client_preamble.rs @@ -17,10 +17,10 @@ use futures::FutureExt; use rstest::fixture; use tokio::{net::TcpListener, sync::oneshot, task::JoinHandle}; use wireframe::{ - BincodeSerializer, client::{ClientError, WireframeClient}, preamble::{read_preamble, write_preamble}, rewind_stream::RewindStream, + serializer::BincodeSerializer, }; /// `TestResult` for step definitions. pub use wireframe_testing::TestResult; diff --git a/tests/fixtures/client_runtime.rs b/tests/fixtures/client_runtime.rs index d62f1a35..4173fbdc 100644 --- a/tests/fixtures/client_runtime.rs +++ b/tests/fixtures/client_runtime.rs @@ -15,10 +15,10 @@ use rstest::fixture; use tokio::{net::TcpListener, task::JoinHandle}; use tokio_util::codec::{Framed, LengthDelimitedCodec}; use wireframe::{ - BincodeSerializer, WireframeError, client::{ClientCodecConfig, ClientError, ClientProtocolError, WireframeClient}, rewind_stream::RewindStream, + serializer::BincodeSerializer, }; /// `TestResult` for step definitions. pub use wireframe_testing::TestResult; diff --git a/tests/fixtures/client_streaming.rs b/tests/fixtures/client_streaming.rs index 0c778503..649ff89e 100644 --- a/tests/fixtures/client_streaming.rs +++ b/tests/fixtures/client_streaming.rs @@ -10,12 +10,11 @@ use rstest::fixture; use tokio::{net::TcpListener, task::JoinHandle}; use tokio_util::codec::{Framed, LengthDelimitedCodec}; use wireframe::{ - BincodeSerializer, - Serializer, WireframeError, client::{ClientError, WireframeClient}, correlation::CorrelatableFrame, rewind_stream::RewindStream, + serializer::{BincodeSerializer, Serializer}, }; pub use wireframe_testing::TestResult; diff --git a/tests/fixtures/client_streaming/types.rs b/tests/fixtures/client_streaming/types.rs index 7f4c70f2..f0dc52a0 100644 --- a/tests/fixtures/client_streaming/types.rs +++ b/tests/fixtures/client_streaming/types.rs @@ -3,10 +3,9 @@ use bytes::Bytes; use derive_more::{Display, From}; use wireframe::{ - BincodeSerializer, - Serializer, app::{Packet, PacketParts}, correlation::CorrelatableFrame, + serializer::{BincodeSerializer, Serializer}, }; /// A correlation identifier used to match streaming requests to responses. diff --git a/tests/fixtures/codec_error/decoder_ops.rs b/tests/fixtures/codec_error/decoder_ops.rs index 038a16ba..f2a429ee 100644 --- a/tests/fixtures/codec_error/decoder_ops.rs +++ b/tests/fixtures/codec_error/decoder_ops.rs @@ -6,9 +6,8 @@ use bytes::BytesMut; use tokio_util::codec::Decoder; use wireframe::{ - FrameCodec, byte_order::{read_network_u32, write_network_u32}, - codec::{EofError, LENGTH_HEADER_SIZE, LengthDelimitedFrameCodec}, + codec::{EofError, FrameCodec, LENGTH_HEADER_SIZE, LengthDelimitedFrameCodec}, }; use super::{CodecErrorWorld, TestResult}; diff --git a/tests/fixtures/codec_stateful.rs b/tests/fixtures/codec_stateful.rs index cc655c75..7f312db9 100644 --- a/tests/fixtures/codec_stateful.rs +++ b/tests/fixtures/codec_stateful.rs @@ -18,10 +18,9 @@ use tokio::{ }; use tokio_util::codec::{Decoder, Encoder, Framed, LengthDelimitedCodec}; use wireframe::{ - Serializer, app::{Envelope, WireframeApp}, codec::FrameCodec, - serializer::BincodeSerializer, + serializer::{BincodeSerializer, Serializer}, }; /// Re-export `TestResult` from `wireframe_testing` for use in steps. pub use wireframe_testing::TestResult; diff --git a/tests/fixtures/message_assembly_inbound.rs b/tests/fixtures/message_assembly_inbound.rs index 2b975f7a..7474430b 100644 --- a/tests/fixtures/message_assembly_inbound.rs +++ b/tests/fixtures/message_assembly_inbound.rs @@ -7,10 +7,9 @@ use rstest::fixture; use tokio::{io::DuplexStream, sync::mpsc, task::JoinHandle, time::timeout}; use tokio_util::codec::{Framed, LengthDelimitedCodec}; use wireframe::{ - Serializer, app::{Envelope, Handler, WireframeApp}, fragment::FragmentationConfig, - serializer::BincodeSerializer, + serializer::{BincodeSerializer, Serializer}, test_helpers::{self, TestAssembler}, }; pub use wireframe_testing::TestResult; diff --git a/tests/fixtures/multi_packet.rs b/tests/fixtures/multi_packet.rs index 49164c17..92135452 100644 --- a/tests/fixtures/multi_packet.rs +++ b/tests/fixtures/multi_packet.rs @@ -8,7 +8,7 @@ use std::{error::Error, fmt}; use rstest::fixture; use tokio::sync::mpsc::{self, error::TrySendError}; use tokio_util::sync::CancellationToken; -use wireframe::{Response, connection::ConnectionActor}; +use wireframe::{connection::ConnectionActor, response::Response}; /// Re-export `TestResult` from `wireframe_testing` for use in steps. pub use wireframe_testing::TestResult; diff --git a/tests/fixtures/unified_codec/transport.rs b/tests/fixtures/unified_codec/transport.rs index cc03c201..fe91f954 100644 --- a/tests/fixtures/unified_codec/transport.rs +++ b/tests/fixtures/unified_codec/transport.rs @@ -12,7 +12,6 @@ use futures::{SinkExt, StreamExt}; use tokio::{io::AsyncWriteExt, time::timeout}; use tokio_util::codec::{Framed, LengthDelimitedCodec}; use wireframe::{ - Serializer, app::{Envelope, Packet}, fragment::{ FragmentationConfig, @@ -21,7 +20,7 @@ use wireframe::{ decode_fragment_payload, encode_fragment_payload, }, - serializer::BincodeSerializer, + serializer::{BincodeSerializer, Serializer}, }; use self::unified_codec_transport::{recv_one, send_one}; diff --git a/tests/fragment_transport.rs b/tests/fragment_transport.rs index 9ba363c2..d9775b7d 100644 --- a/tests/fragment_transport.rs +++ b/tests/fragment_transport.rs @@ -11,10 +11,9 @@ use std::time::Duration; use futures::{SinkExt, StreamExt}; use tokio::{io::AsyncWriteExt, sync::mpsc, time::timeout}; use wireframe::{ - Serializer, app::{Envelope, Packet, WireframeApp}, fragment::{Fragmenter, decode_fragment_payload}, - serializer::BincodeSerializer, + serializer::{BincodeSerializer, Serializer}, }; #[path = "fragment_transport/mod.rs"] diff --git a/tests/frame_codec.rs b/tests/frame_codec.rs index a4e914f2..d12e0cce 100644 --- a/tests/frame_codec.rs +++ b/tests/frame_codec.rs @@ -14,11 +14,10 @@ use futures::{SinkExt, StreamExt}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio_util::codec::{Decoder, Encoder, Framed}; use wireframe::{ - Serializer, app::{Envelope, Packet, WireframeApp}, codec::FrameCodec, correlation::CorrelatableFrame, - serializer::BincodeSerializer, + serializer::{BincodeSerializer, Serializer}, }; #[derive(Clone, Debug)] diff --git a/tests/multi_packet.rs b/tests/multi_packet.rs index 80b6da2e..c3402c7c 100644 --- a/tests/multi_packet.rs +++ b/tests/multi_packet.rs @@ -8,9 +8,9 @@ use rstest::{fixture, rstest}; use tokio::{sync::mpsc, task::yield_now, time::timeout}; use tokio_util::sync::CancellationToken; use wireframe::{ - Response, connection::{ConnectionActor, FairnessConfig}, push::{PushHandle, PushQueues}, + response::{FrameStream, Response}, }; use wireframe_testing::{TestError, TestResult}; @@ -35,9 +35,7 @@ fn actor_components() -> TestResult<(PushQueues, PushHandle, Cancellatio } /// Drain all messages from a `FrameStream` for non-channel response variants. -async fn drain_all( - stream: wireframe::FrameStream, -) -> TestResult> { +async fn drain_all(stream: FrameStream) -> TestResult> { stream .try_collect::>() .await diff --git a/tests/response.rs b/tests/response.rs index ff836497..4526b14b 100644 --- a/tests/response.rs +++ b/tests/response.rs @@ -10,11 +10,10 @@ use bytes::BytesMut; use rstest::rstest; use tokio_util::codec::{Decoder, Encoder, LengthDelimitedCodec}; use wireframe::{ - Serializer, app::{Envelope, Packet, WireframeApp}, frame::{Endianness, LengthFormat}, message::Message, - serializer::BincodeSerializer, + serializer::{BincodeSerializer, Serializer}, }; use wireframe_testing::{ TestApp, diff --git a/tests/routes.rs b/tests/routes.rs index 18f4b314..5307a817 100644 --- a/tests/routes.rs +++ b/tests/routes.rs @@ -11,7 +11,11 @@ use std::sync::{ use bytes::BytesMut; use rstest::rstest; use tokio_util::codec::Encoder; -use wireframe::{Serializer, app::Packet, message::Message, serializer::BincodeSerializer}; +use wireframe::{ + app::Packet, + message::Message, + serializer::{BincodeSerializer, Serializer}, +}; use wireframe_testing::{ CommonTestEnvelope, TEST_MAX_FRAME, diff --git a/tests/steps/client_lifecycle_steps.rs b/tests/steps/client_lifecycle_steps.rs index bae43f63..3faa37ef 100644 --- a/tests/steps/client_lifecycle_steps.rs +++ b/tests/steps/client_lifecycle_steps.rs @@ -121,7 +121,7 @@ fn then_client_error_is_wireframe_transport_error( .ok_or("expected a captured client error in world.last_error")?; match last_error { - wireframe::ClientError::Wireframe(wireframe::WireframeError::Io(_)) => Ok(()), + wireframe::client::ClientError::Wireframe(wireframe::WireframeError::Io(_)) => Ok(()), other => Err(format!( "expected ClientError::Wireframe(WireframeError::Io(_)), got {other:?}" ) diff --git a/tests/steps/fragment_steps.rs b/tests/steps/fragment_steps.rs index 5a668b90..d1157bbb 100644 --- a/tests/steps/fragment_steps.rs +++ b/tests/steps/fragment_steps.rs @@ -3,7 +3,7 @@ use std::time::Duration; use rstest_bdd_macros::{given, then, when}; -use wireframe::{FragmentHeader, FragmentIndex, MessageId}; +use wireframe::fragment::{FragmentHeader, FragmentIndex, MessageId}; use crate::fixtures::fragment::{FragmentWorld, TestResult}; diff --git a/tests/wireframe_protocol.rs b/tests/wireframe_protocol.rs index c8ea3b8f..5532269a 100644 --- a/tests/wireframe_protocol.rs +++ b/tests/wireframe_protocol.rs @@ -22,11 +22,10 @@ use tokio_util::{ sync::CancellationToken, }; use wireframe::{ - ConnectionContext, - WireframeProtocol, app::Envelope, codec::FrameCodec, connection::{ConnectionActor, ConnectionChannels}, + hooks::{ConnectionContext, WireframeProtocol}, push::{PushConfigError, PushQueues}, serializer::BincodeSerializer, }; diff --git a/wireframe_testing/src/echo_server.rs b/wireframe_testing/src/echo_server.rs index 97264b50..96ed1c35 100644 --- a/wireframe_testing/src/echo_server.rs +++ b/wireframe_testing/src/echo_server.rs @@ -5,10 +5,9 @@ //! IDs for error testing scenarios. use wireframe::{ - BincodeSerializer, - Serializer, app::{Envelope, Packet}, correlation::CorrelatableFrame, + serializer::{BincodeSerializer, Serializer}, }; /// Server mode for testing various correlation ID scenarios. diff --git a/wireframe_testing/src/integration_helpers.rs b/wireframe_testing/src/integration_helpers.rs index 9eee5a25..fbdd4b51 100644 --- a/wireframe_testing/src/integration_helpers.rs +++ b/wireframe_testing/src/integration_helpers.rs @@ -12,6 +12,7 @@ use thiserror::Error; use wireframe::{ app::{Envelope, Packet, PacketParts}, correlation::CorrelatableFrame, + fragment::{FragmentationError, ReassemblyError}, serializer::BincodeSerializer, }; @@ -159,9 +160,9 @@ pub enum TestError { #[error(transparent)] ConnectionState(#[from] wireframe::connection::ConnectionStateError), #[error(transparent)] - Reassembly(#[from] wireframe::ReassemblyError), + Reassembly(#[from] ReassemblyError), #[error(transparent)] - Fragmentation(#[from] wireframe::FragmentationError), + Fragmentation(#[from] FragmentationError), #[error(transparent)] Codec(#[from] wireframe::codec::CodecError), #[error(transparent)] diff --git a/wireframe_testing/src/multi_packet.rs b/wireframe_testing/src/multi_packet.rs index 8a00f1e0..5f5cf00b 100644 --- a/wireframe_testing/src/multi_packet.rs +++ b/wireframe_testing/src/multi_packet.rs @@ -3,7 +3,7 @@ //! These utilities collect all frames from a [`Response::MultiPacket`] into a //! `Vec`, enabling concise assertions in tests and Cucumber steps. -use wireframe::Response; +use wireframe::response::Response; /// Collect all frames from a [`Response::MultiPacket`]. /// @@ -11,7 +11,7 @@ use wireframe::Response; /// /// ```rust /// use tokio::sync::mpsc; -/// use wireframe::Response; +/// use wireframe::response::Response; /// use wireframe_testing::collect_multi_packet; /// /// # async fn demo() { From 0c1bd4aa2abacdf8667576f6bf0099d20ab76adf Mon Sep 17 00:00:00 2001 From: Leynos Date: Fri, 20 Feb 2026 13:02:38 +0000 Subject: [PATCH 2/4] feat(prelude): export RequestBodyStream and RequestParts in prelude Add RequestBodyStream and RequestParts exports to the prelude module under the cfg(not(loom)) condition to enhance reusability and simplify imports in dependent modules. Co-authored-by: devboxerhub[bot] --- src/prelude.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/prelude.rs b/src/prelude.rs index c0958898..43991423 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -14,6 +14,8 @@ #[cfg(not(loom))] pub use crate::client::{ClientError, WireframeClient}; #[cfg(not(loom))] +pub use crate::request::{RequestBodyStream, RequestParts}; +#[cfg(not(loom))] pub use crate::server::{ServerError, WireframeServer}; pub use crate::{ app::{Envelope, Handler, Middleware, WireframeApp}, From 5ee5bdca3336a52b9156c17cef44a4afefc2e35c Mon Sep 17 00:00:00 2001 From: Leynos Date: Fri, 20 Feb 2026 16:28:23 +0000 Subject: [PATCH 3/4] style(prelude): reorder and group conditional imports for clarity Moved the #[cfg(not(loom))] conditional re-exports to the bottom and grouped them in a single use statement block to improve code readability and maintainability. Co-authored-by: devboxerhub[bot] --- src/prelude.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/prelude.rs b/src/prelude.rs index 43991423..4bdd9895 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -11,12 +11,6 @@ //! fn build() -> Result { WireframeApp::new() } //! ``` -#[cfg(not(loom))] -pub use crate::client::{ClientError, WireframeClient}; -#[cfg(not(loom))] -pub use crate::request::{RequestBodyStream, RequestParts}; -#[cfg(not(loom))] -pub use crate::server::{ServerError, WireframeServer}; pub use crate::{ app::{Envelope, Handler, Middleware, WireframeApp}, error::{Result, WireframeError}, @@ -24,3 +18,9 @@ pub use crate::{ response::Response, serializer::{BincodeSerializer, Serializer}, }; +#[cfg(not(loom))] +pub use crate::{ + client::{ClientError, WireframeClient}, + request::{RequestBodyStream, RequestParts}, + server::{ServerError, WireframeServer}, +}; From 4eaefa538b97445ee4caedceee0c13e216bc9b34 Mon Sep 17 00:00:00 2001 From: Leynos Date: Fri, 20 Feb 2026 22:33:48 +0000 Subject: [PATCH 4/4] docs(documentation): fix spelling of 'specialised' to 'specialized' in docs Corrected the spelling of "specialised" to "specialized" in users-guide.md and v0-1-0-to-v0-2-0-migration-guide.md to maintain consistent US English spelling in the documentation. Co-authored-by: devboxerhub[bot] --- docs/users-guide.md | 2 +- docs/v0-1-0-to-v0-2-0-migration-guide.md | 47 ++++++++++++++---------- 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/docs/users-guide.md b/docs/users-guide.md index 586b2803..3032015f 100644 --- a/docs/users-guide.md +++ b/docs/users-guide.md @@ -11,7 +11,7 @@ Wireframe uses progressive discovery for public APIs: - `wireframe::` root is intentionally small and stable, exposing canonical `Result` and `WireframeError`. -- `wireframe::::...` is the default path for specialised APIs. +- `wireframe::::...` is the default path for specialized APIs. - `wireframe::prelude::*` is an optional convenience import for common workflows. diff --git a/docs/v0-1-0-to-v0-2-0-migration-guide.md b/docs/v0-1-0-to-v0-2-0-migration-guide.md index 6bb2352b..c6d924b2 100644 --- a/docs/v0-1-0-to-v0-2-0-migration-guide.md +++ b/docs/v0-1-0-to-v0-2-0-migration-guide.md @@ -83,7 +83,7 @@ owning modules, and root re-exports were removed. - Root now exposes canonical `wireframe::Result` and `wireframe::WireframeError`. -- Use `wireframe::::...` for specialised APIs. +- Use `wireframe::::...` for specialized APIs. - `wireframe::prelude::*` is available as an optional convenience import for high-frequency types. @@ -101,35 +101,42 @@ owning modules, and root re-exports were removed. `wireframe::WireframeProtocol` -> `wireframe::hooks::{ConnectionContext, ProtocolHooks, WireframeProtocol}` - `wireframe::ClientCodecConfig`, `wireframe::ClientError`, - `wireframe::ClientProtocolError`, `wireframe::ClientWireframeError`, - `wireframe::SocketOptions`, `wireframe::WireframeClient` -> - `wireframe::client::{...}` + `wireframe::ClientProtocolError` -> `wireframe::client::{...}` +- `wireframe::ClientWireframeError`, `wireframe::SocketOptions`, + `wireframe::WireframeClient` -> `wireframe::client::{...}` - `wireframe::CodecError`, `wireframe::CodecErrorContext`, - `wireframe::DefaultRecoveryPolicy`, `wireframe::EofError`, - `wireframe::FrameCodec`, `wireframe::FramingError`, - `wireframe::LengthDelimitedFrameCodec`, `wireframe::MAX_FRAME_LENGTH`, - `wireframe::MIN_FRAME_LENGTH`, `wireframe::ProtocolError`, + `wireframe::DefaultRecoveryPolicy`, `wireframe::EofError` -> + `wireframe::codec::{...}` +- `wireframe::FrameCodec`, `wireframe::FramingError`, + `wireframe::LengthDelimitedFrameCodec`, `wireframe::MAX_FRAME_LENGTH` -> + `wireframe::codec::{...}` +- `wireframe::MIN_FRAME_LENGTH`, `wireframe::ProtocolError`, `wireframe::RecoveryConfig`, `wireframe::RecoveryPolicy`, `wireframe::RecoveryPolicyHook` -> `wireframe::codec::{...}` - `wireframe::DefaultFragmentAdapter`, `wireframe::FRAGMENT_MAGIC`, - `wireframe::FragmentAdapter`, `wireframe::FragmentAdapterError`, - `wireframe::FragmentBatch`, `wireframe::FragmentError`, + `wireframe::FragmentAdapter`, `wireframe::FragmentAdapterError` -> + `wireframe::fragment::{...}` +- `wireframe::FragmentBatch`, `wireframe::FragmentError`, `wireframe::FragmentFrame`, `wireframe::FragmentHeader`, - `wireframe::FragmentIndex`, `wireframe::FragmentSeries`, - `wireframe::FragmentStatus`, `wireframe::FragmentationConfig`, + `wireframe::FragmentIndex`, `wireframe::FragmentSeries` -> + `wireframe::fragment::{...}` +- `wireframe::FragmentStatus`, `wireframe::FragmentationConfig`, `wireframe::FragmentationError`, `wireframe::Fragmenter`, - `wireframe::MessageId`, `wireframe::ReassembledMessage`, - `wireframe::Reassembler`, `wireframe::ReassemblyError`, + `wireframe::MessageId`, `wireframe::ReassembledMessage` -> + `wireframe::fragment::{...}` +- `wireframe::Reassembler`, `wireframe::ReassemblyError`, `wireframe::decode_fragment_payload`, `wireframe::encode_fragment_payload`, `wireframe::fragment_overhead` -> `wireframe::fragment::{...}` - `wireframe::AssembledMessage`, `wireframe::ContinuationFrameHeader`, - `wireframe::FirstFrameHeader`, `wireframe::FirstFrameInput`, - `wireframe::FirstFrameInputError`, `wireframe::FrameHeader`, + `wireframe::FirstFrameHeader`, `wireframe::FirstFrameInput` -> + `wireframe::message_assembler::{...}` +- `wireframe::FirstFrameInputError`, `wireframe::FrameHeader`, `wireframe::FrameSequence`, `wireframe::MessageAssembler`, - `wireframe::MessageAssemblyError`, `wireframe::MessageAssemblyState`, - `wireframe::MessageKey`, `wireframe::MessageSeries`, - `wireframe::MessageSeriesError`, `wireframe::MessageSeriesStatus`, - `wireframe::ParsedFrameHeader` -> `wireframe::message_assembler::{...}` + `wireframe::MessageAssemblyError` -> `wireframe::message_assembler::{...}` +- `wireframe::MessageAssemblyState`, `wireframe::MessageKey`, + `wireframe::MessageSeries`, `wireframe::MessageSeriesError`, + `wireframe::MessageSeriesStatus`, `wireframe::ParsedFrameHeader` -> + `wireframe::message_assembler::{...}` - `wireframe::CODEC_ERRORS`, `wireframe::CONNECTIONS_ACTIVE`, `wireframe::Direction`, `wireframe::ERRORS_TOTAL`, `wireframe::FRAMES_PROCESSED` -> `wireframe::metrics::{...}`