From 175c11b972f3c695b509983454ad129914f704cf Mon Sep 17 00:00:00 2001 From: Leynos Date: Thu, 12 Jun 2025 11:36:15 +0100 Subject: [PATCH 01/10] Add core trait definitions --- Cargo.lock | 19 +++++++++++++++ Cargo.toml | 2 ++ docs/roadmap.md | 2 +- src/extractor.rs | 51 ++++++++++++++++++++++++++++++++++++++++ src/frame.rs | 22 ++++++++++++++++++ src/lib.rs | 3 +++ src/middleware.rs | 59 +++++++++++++++++++++++++++++++++++++++++++++++ src/server.rs | 8 +++---- 8 files changed, 161 insertions(+), 5 deletions(-) create mode 100644 src/extractor.rs create mode 100644 src/frame.rs create mode 100644 src/middleware.rs diff --git a/Cargo.lock b/Cargo.lock index a78fc8f6..f2310555 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,17 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[package]] +name = "async-trait" +version = "0.1.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "autocfg" version = "1.4.0" @@ -58,6 +69,12 @@ dependencies = [ "virtue", ] +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + [[package]] name = "cfg-if" version = "1.0.1" @@ -448,7 +465,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" name = "wireframe" version = "0.1.0" dependencies = [ + "async-trait", "bincode", + "bytes", "futures", "num_cpus", "serde", diff --git a/Cargo.toml b/Cargo.toml index 0f795c61..50b2132b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,8 @@ bincode = "2" tokio = { version = "1", default-features = false, features = ["net", "signal", "rt-multi-thread", "macros", "sync", "time"] } futures = "0.3" num_cpus = "^1" +async-trait = "0.1" +bytes = "1" [lints.clippy] pedantic = "warn" diff --git a/docs/roadmap.md b/docs/roadmap.md index 3c943a5e..e7f4d68d 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -22,7 +22,7 @@ after formatting. Line numbers below refer to that file. `WireframeApp` instance from a factory closure. A Ctrl+C signal triggers graceful shutdown, notifying all workers to stop accepting new connections. - - [ ] Standardise supporting trait definitions. + - [x] Standardise supporting trait definitions. Provide naming conventions and generic bounds for the `FrameProcessor` trait, state extractors and middleware via `async_trait` and associated types. diff --git a/src/extractor.rs b/src/extractor.rs new file mode 100644 index 00000000..18961d89 --- /dev/null +++ b/src/extractor.rs @@ -0,0 +1,51 @@ +use async_trait::async_trait; +use std::sync::Arc; + +/// Request context passed to extractors. +/// +/// This type contains metadata about the current connection and provides +/// access to application state registered with [`WireframeApp`]. +#[derive(Default)] +pub struct MessageRequest { + // TODO: populate with connection info and state storage +} + +/// Raw payload buffer handed to extractors. +#[derive(Default)] +pub struct Payload<'a> { + /// Incoming bytes not yet processed. + pub data: &'a [u8], +} + +/// Asynchronous extractor trait. +#[async_trait] +pub trait FromMessageRequest: Sized { + /// Error type returned when extraction fails. + type Error: std::error::Error + Send + Sync + 'static; + + /// Perform extraction from the request and payload. + async fn from_message_request( + req: &MessageRequest, + payload: &mut Payload<'_>, + ) -> Result; +} + +/// Shared application state accessible to handlers. +#[derive(Clone)] +pub struct SharedState(Arc); + +impl SharedState { + /// Construct a new [`SharedState`]. + #[must_use] + pub fn new(inner: Arc) -> Self { + Self(inner) + } +} + +impl std::ops::Deref for SharedState { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} diff --git a/src/frame.rs b/src/frame.rs new file mode 100644 index 00000000..1028fedc --- /dev/null +++ b/src/frame.rs @@ -0,0 +1,22 @@ +use async_trait::async_trait; + +/// Trait defining how raw bytes are decoded into frames and how frames are +/// encoded back into bytes for transmission. +/// +/// The `Frame` associated type represents a logical unit extracted from or +/// written to the wire. Errors are represented by the `Error` associated type, +/// which must implement [`std::error::Error`]. +#[async_trait] +pub trait FrameProcessor: Send + Sync { + /// Logical frame type extracted from the stream. + type Frame; + + /// Error type returned by `decode` and `encode`. + type Error: std::error::Error + Send + Sync + 'static; + + /// Attempt to decode the next frame from `src`. + async fn decode(&mut self, src: &[u8]) -> Result, Self::Error>; + + /// Encode `frame` and append the bytes to `dst`. + async fn encode(&mut self, frame: &Self::Frame, dst: &mut Vec) -> Result<(), Self::Error>; +} diff --git a/src/lib.rs b/src/lib.rs index 9c88284c..d93632f1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,6 @@ pub mod app; +pub mod extractor; +pub mod frame; pub mod message; +pub mod middleware; pub mod server; diff --git a/src/middleware.rs b/src/middleware.rs new file mode 100644 index 00000000..c4ae3b46 --- /dev/null +++ b/src/middleware.rs @@ -0,0 +1,59 @@ +use async_trait::async_trait; + +/// Incoming request wrapper passed through middleware. +#[derive(Debug)] +pub struct ServiceRequest; + +/// Response produced by a handler or middleware. +#[derive(Debug, Default)] +pub struct ServiceResponse; + +/// Continuation used by middleware to call the next service in the chain. +pub struct Next<'a, S> +where + S: Service + ?Sized, +{ + service: &'a S, +} + +impl<'a, S> Next<'a, S> +where + S: Service + ?Sized, +{ + /// Construct a new [`Next`] wrapper. + pub const fn new(service: &'a S) -> Self { + Self { service } + } + + /// Call the next service with the given request. + /// + /// # Errors + /// + /// Propagates any error returned by the wrapped service. + pub async fn call(&self, req: ServiceRequest) -> Result { + self.service.call(req).await + } +} + +/// Trait representing an asynchronous service. +#[async_trait] +pub trait Service: Send + Sync { + /// Error type returned by the service. + type Error: std::error::Error + Send + Sync + 'static; + + /// Handle the incoming request and produce a response. + async fn call(&self, req: ServiceRequest) -> Result; +} + +/// Factory for wrapping services with middleware. +#[async_trait] +pub trait Transform: Send + Sync +where + S: Service, +{ + /// Wrapped service produced by the middleware. + type Service: Service; + + /// Create a new middleware service wrapping `service`. + async fn transform(&self, service: S) -> Self::Service; +} diff --git a/src/server.rs b/src/server.rs index 6ac1fa3c..a58e97f4 100644 --- a/src/server.rs +++ b/src/server.rs @@ -34,7 +34,7 @@ where /// /// # Examples /// - /// ``` + /// ```ignore /// let server = WireframeServer::new(|| WireframeApp::default()); /// ``` pub fn new(factory: F) -> Self { @@ -59,7 +59,7 @@ where /// /// # Examples /// - /// ``` + /// ```ignore /// let server = WireframeServer::new(factory).workers(4); /// ``` pub fn workers(mut self, count: usize) -> Self { @@ -85,7 +85,7 @@ where /// /// # Examples /// - /// ``` + /// ```ignore /// use std::net::SocketAddr; /// let server = WireframeServer::new(factory); /// let addr: SocketAddr = "127.0.0.1:8080".parse().unwrap(); @@ -125,7 +125,7 @@ where /// /// # Examples /// - /// ``` + /// ```ignore /// # use std::net::SocketAddr; /// # use mycrate::{WireframeServer, WireframeApp}; /// # async fn run_server() -> std::io::Result<()> { From 6008d7897bf7977afcdb523f00179f2fe149c9fb Mon Sep 17 00:00:00 2001 From: Leynos Date: Thu, 12 Jun 2025 11:58:48 +0100 Subject: [PATCH 02/10] Refine payload and state traits --- src/extractor.rs | 23 ++++++++++++++++++++--- src/middleware.rs | 4 ++-- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/extractor.rs b/src/extractor.rs index 18961d89..e43a3e5b 100644 --- a/src/extractor.rs +++ b/src/extractor.rs @@ -17,6 +17,23 @@ pub struct Payload<'a> { pub data: &'a [u8], } +impl Payload<'_> { + /// Advances the payload by `count` bytes. + /// + /// Consumes up to `count` bytes from the front of the slice, ensuring we + /// never slice beyond the available buffer. + pub fn advance(&mut self, count: usize) { + let n = count.min(self.data.len()); + self.data = &self.data[n..]; + } + + /// Returns the number of bytes remaining. + #[must_use] + pub fn remaining(&self) -> usize { + self.data.len() + } +} + /// Asynchronous extractor trait. #[async_trait] pub trait FromMessageRequest: Sized { @@ -32,9 +49,9 @@ pub trait FromMessageRequest: Sized { /// Shared application state accessible to handlers. #[derive(Clone)] -pub struct SharedState(Arc); +pub struct SharedState(Arc); -impl SharedState { +impl SharedState { /// Construct a new [`SharedState`]. #[must_use] pub fn new(inner: Arc) -> Self { @@ -42,7 +59,7 @@ impl SharedState { } } -impl std::ops::Deref for SharedState { +impl std::ops::Deref for SharedState { type Target = T; fn deref(&self) -> &Self::Target { diff --git a/src/middleware.rs b/src/middleware.rs index c4ae3b46..1b3c2bdc 100644 --- a/src/middleware.rs +++ b/src/middleware.rs @@ -52,8 +52,8 @@ where S: Service, { /// Wrapped service produced by the middleware. - type Service: Service; + type Output: Service; /// Create a new middleware service wrapping `service`. - async fn transform(&self, service: S) -> Self::Service; + async fn transform(&self, service: S) -> Self::Output; } From c3fbe2700c5ea62c6f90fc149f3824d0802b20dc Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Thu, 12 Jun 2025 12:20:53 +0100 Subject: [PATCH 03/10] =?UTF-8?q?=F0=9F=93=9D=20Add=20docstrings=20to=20`c?= =?UTF-8?q?odex/standardise-trait-definitions-for-frameprocessor`=20(#9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Docstrings generation was requested by @leynos. * https://github.com/leynos/wireframe/pull/8#issuecomment-2966084703 The following files were modified: * `src/extractor.rs` * `src/middleware.rs` * `src/server.rs` Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- src/extractor.rs | 22 ++++++++++++++++++++++ src/middleware.rs | 32 ++++++++++++++++++++++++++++++-- src/server.rs | 14 ++++++++++++++ 3 files changed, 66 insertions(+), 2 deletions(-) diff --git a/src/extractor.rs b/src/extractor.rs index e43a3e5b..9bbf136e 100644 --- a/src/extractor.rs +++ b/src/extractor.rs @@ -54,6 +54,16 @@ pub struct SharedState(Arc); impl SharedState { /// Construct a new [`SharedState`]. #[must_use] + /// Creates a new `SharedState` instance wrapping the provided `Arc`. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// let state = Arc::new(42); + /// let shared = SharedState::new(state.clone()); + /// assert_eq!(*shared, 42); + /// ``` pub fn new(inner: Arc) -> Self { Self(inner) } @@ -62,6 +72,18 @@ impl SharedState { impl std::ops::Deref for SharedState { type Target = T; + /// Returns a reference to the inner shared state value. + /// + /// This allows transparent access to the underlying state managed by `SharedState`. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// let state = Arc::new(42); + /// let shared = SharedState::new(state.clone()); + /// assert_eq!(*shared, 42); + /// ``` fn deref(&self) -> &Self::Target { &self.0 } diff --git a/src/middleware.rs b/src/middleware.rs index 1b3c2bdc..6e11a50c 100644 --- a/src/middleware.rs +++ b/src/middleware.rs @@ -20,7 +20,14 @@ impl<'a, S> Next<'a, S> where S: Service + ?Sized, { - /// Construct a new [`Next`] wrapper. + /// Creates a new `Next` instance wrapping a reference to the given service. + /// + /// # Examples + /// + /// ``` + /// let service = MyService::default(); + /// let next = Next::new(&service); + /// ``` pub const fn new(service: &'a S) -> Self { Self { service } } @@ -29,7 +36,28 @@ where /// /// # Errors /// - /// Propagates any error returned by the wrapped service. + /// Asynchronously invokes the next service in the middleware chain with the given request. + /// + /// Returns the response from the wrapped service, or propagates any error produced. + /// + /// # Examples + /// + /// ``` + /// # use your_crate::{ServiceRequest, ServiceResponse, Next, Service}; + /// # struct DummyService; + /// # #[async_trait::async_trait] + /// # impl Service for DummyService { + /// # type Error = std::convert::Infallible; + /// # async fn call(&self, _req: ServiceRequest) -> Result { + /// # Ok(ServiceResponse::default()) + /// # } + /// # } + /// # let service = DummyService; + /// let next = Next::new(&service); + /// let req = ServiceRequest {}; + /// let res = tokio_test::block_on(next.call(req)); + /// assert!(res.is_ok()); + /// ``` pub async fn call(&self, req: ServiceRequest) -> Result { self.service.call(req).await } diff --git a/src/server.rs b/src/server.rs index a58e97f4..0e2200c7 100644 --- a/src/server.rs +++ b/src/server.rs @@ -36,6 +36,14 @@ where /// /// ```ignore /// let server = WireframeServer::new(|| WireframeApp::default()); + /// Creates a new `WireframeServer` with the given factory closure. + /// + /// The server is initialised with the default number of worker tasks equal to the number of CPU cores. The TCP listener is not yet bound; use `bind` to associate a socket address. + /// + /// # Examples + /// + /// ```ignore + /// let server = WireframeServer::new(|| WireframeApp::default()); /// ``` pub fn new(factory: F) -> Self { Self { @@ -61,6 +69,12 @@ where /// /// ```ignore /// let server = WireframeServer::new(factory).workers(4); + /// Sets the number of worker tasks for the server, ensuring at least one worker. + /// + /// # Examples + /// + /// ```ignore + /// let server = WireframeServer::new(factory).workers(4); /// ``` pub fn workers(mut self, count: usize) -> Self { self.workers = count.max(1); From 8ee8a59f2796178feaf2d85830f4a439d63c30ad Mon Sep 17 00:00:00 2001 From: Leynos Date: Thu, 12 Jun 2025 12:37:54 +0100 Subject: [PATCH 04/10] Add payload tests --- src/extractor.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/extractor.rs b/src/extractor.rs index 9bbf136e..28e7bb94 100644 --- a/src/extractor.rs +++ b/src/extractor.rs @@ -54,6 +54,28 @@ pub struct SharedState(Arc); impl SharedState { /// Construct a new [`SharedState`]. #[must_use] + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn advance_consumes_bytes() { + let mut payload = Payload { data: b"hello" }; + payload.advance(2); + assert_eq!(payload.data, b"llo"); + payload.advance(10); + assert!(payload.data.is_empty()); + } + + #[test] + fn remaining_reports_length() { + let mut payload = Payload { data: b"abc" }; + assert_eq!(payload.remaining(), 3); + payload.advance(1); + assert_eq!(payload.remaining(), 2); + } +} /// Creates a new `SharedState` instance wrapping the provided `Arc`. /// /// # Examples From a17e4dc8ba4449a25b1f6862cd8beb1dd0d47c10 Mon Sep 17 00:00:00 2001 From: Leynos Date: Thu, 12 Jun 2025 19:32:32 +0100 Subject: [PATCH 05/10] Document SharedState::new and fix attributes --- src/extractor.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/extractor.rs b/src/extractor.rs index 28e7bb94..7ced57d9 100644 --- a/src/extractor.rs +++ b/src/extractor.rs @@ -53,6 +53,17 @@ pub struct SharedState(Arc); impl SharedState { /// Construct a new [`SharedState`]. + /// + /// # Examples + /// + /// ```ignore + /// use std::sync::Arc; + /// use wireframe::extractor::SharedState; + /// + /// let data = Arc::new(5u32); + /// let state = SharedState::new(Arc::clone(&data)); + /// assert_eq!(*state, 5); + /// ``` #[must_use] #[cfg(test)] From ea3a7a804eaf4dd9d818e9bfc9c604a21448a0f5 Mon Sep 17 00:00:00 2001 From: Leynos Date: Thu, 12 Jun 2025 21:20:18 +0100 Subject: [PATCH 06/10] Refine request context and cleanup docs --- src/extractor.rs | 4 +++- src/server.rs | 42 ++++++++++++------------------------------ 2 files changed, 15 insertions(+), 31 deletions(-) diff --git a/src/extractor.rs b/src/extractor.rs index 7ced57d9..57638fcf 100644 --- a/src/extractor.rs +++ b/src/extractor.rs @@ -1,4 +1,5 @@ use async_trait::async_trait; +use std::net::SocketAddr; use std::sync::Arc; /// Request context passed to extractors. @@ -7,7 +8,8 @@ use std::sync::Arc; /// access to application state registered with [`WireframeApp`]. #[derive(Default)] pub struct MessageRequest { - // TODO: populate with connection info and state storage + /// Address of the peer that sent the current message. + pub peer_addr: Option, } /// Raw payload buffer handed to extractors. diff --git a/src/server.rs b/src/server.rs index 0e2200c7..fea74f52 100644 --- a/src/server.rs +++ b/src/server.rs @@ -32,37 +32,19 @@ where /// /// The server is initialised with a default worker count equal to the number of CPU cores. /// - /// # Examples - /// - /// ```ignore - /// let server = WireframeServer::new(|| WireframeApp::default()); - /// Creates a new `WireframeServer` with the given factory closure. - /// - /// The server is initialised with the default number of worker tasks equal to the number of CPU cores. The TCP listener is not yet bound; use `bind` to associate a socket address. - /// - /// # Examples - /// - /// ```ignore - /// let server = WireframeServer::new(|| WireframeApp::default()); - /// ``` - pub fn new(factory: F) -> Self { - Self { - factory, - listener: None, - workers: num_cpus::get(), - } - } - /// Set the number of worker tasks to spawn. - #[must_use] - /// Sets the number of worker tasks to spawn for the server. - /// - /// Ensures that at least one worker is configured, even if a lower value is provided. - /// - /// # Parameters - /// - `count`: Desired number of worker tasks. - /// - /// # Returns + /// ```no_run + /// use wireframe::{app::WireframeApp, server::WireframeServer}; + /// + /// #[tokio::main] + /// async fn main() -> std::io::Result<()> { + /// let factory = || WireframeApp::new().unwrap(); + /// WireframeServer::new(factory) + /// .workers(4) + /// .bind("127.0.0.1:0".parse().unwrap())? + /// .run() + /// .await + /// } /// A new `WireframeServer` instance with the updated worker count. /// /// # Examples From ac1722894b24dc27362b8bae0441c2e9b07bea32 Mon Sep 17 00:00:00 2001 From: Leynos Date: Thu, 12 Jun 2025 21:38:11 +0100 Subject: [PATCH 07/10] Refine trait docs and server --- docs/roadmap.md | 2 +- src/frame.rs | 5 +++-- src/middleware.rs | 10 +++++++--- src/server.rs | 7 +++++++ 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/docs/roadmap.md b/docs/roadmap.md index e7f4d68d..f0296d59 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -22,7 +22,7 @@ after formatting. Line numbers below refer to that file. `WireframeApp` instance from a factory closure. A Ctrl+C signal triggers graceful shutdown, notifying all workers to stop accepting new connections. - - [x] Standardise supporting trait definitions. + - [x] Standardize supporting trait definitions. Provide naming conventions and generic bounds for the `FrameProcessor` trait, state extractors and middleware via `async_trait` and associated types. diff --git a/src/frame.rs b/src/frame.rs index 1028fedc..c15c3a66 100644 --- a/src/frame.rs +++ b/src/frame.rs @@ -1,4 +1,5 @@ use async_trait::async_trait; +use bytes::BytesMut; /// Trait defining how raw bytes are decoded into frames and how frames are /// encoded back into bytes for transmission. @@ -15,8 +16,8 @@ pub trait FrameProcessor: Send + Sync { type Error: std::error::Error + Send + Sync + 'static; /// Attempt to decode the next frame from `src`. - async fn decode(&mut self, src: &[u8]) -> Result, Self::Error>; + async fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error>; /// Encode `frame` and append the bytes to `dst`. - async fn encode(&mut self, frame: &Self::Frame, dst: &mut Vec) -> Result<(), Self::Error>; + async fn encode(&mut self, frame: &Self::Frame, dst: &mut BytesMut) -> Result<(), Self::Error>; } diff --git a/src/middleware.rs b/src/middleware.rs index 6e11a50c..77f9aaeb 100644 --- a/src/middleware.rs +++ b/src/middleware.rs @@ -22,9 +22,13 @@ where { /// Creates a new `Next` instance wrapping a reference to the given service. /// - /// # Examples - /// - /// ``` +/// +/// ```ignore +/// use wireframe::middleware::{ServiceRequest, ServiceResponse, Next, Service}; +/// ``` + /// Service produced by the middleware. + type Wrapped: Service; + async fn transform(&self, service: S) -> Self::Wrapped; /// let service = MyService::default(); /// let next = Next::new(&service); /// ``` diff --git a/src/server.rs b/src/server.rs index fea74f52..59f2e20f 100644 --- a/src/server.rs +++ b/src/server.rs @@ -32,6 +32,13 @@ where /// /// The server is initialised with a default worker count equal to the number of CPU cores. /// + /// ```no_run + /// use wireframe::{app::WireframeApp, server::WireframeServer}; + /// + /// let factory = || WireframeApp::new().unwrap(); + /// let server = WireframeServer::new(factory); + /// ``` + workers: num_cpus::get().max(1), /// ```no_run /// use wireframe::{app::WireframeApp, server::WireframeServer}; From 6acff82284c42ba4e56a33600c45f767b9af5293 Mon Sep 17 00:00:00 2001 From: Leynos Date: Thu, 12 Jun 2025 21:54:54 +0100 Subject: [PATCH 08/10] Refine extractor trait and clean docs --- docs/rust-binary-router-library-design.md | 7 ++++--- src/extractor.rs | 10 ++++++---- src/server.rs | 3 +-- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/docs/rust-binary-router-library-design.md b/docs/rust-binary-router-library-design.md index 3793a674..259408a2 100644 --- a/docs/rust-binary-router-library-design.md +++ b/docs/rust-binary-router-library-design.md @@ -769,13 +769,14 @@ within handlers. ````rustrust use wireframe::dev::{MessageRequest, Payload}; // Hypothetical types - use std::future::Future; pub trait FromMessageRequest: Sized { type Error: Into; // Error type if extraction fails - type Future: Future>; - fn from_message_request(req: &MessageRequest, payload: &mut Payload) -> Self::Future; + fn from_message_request( + req: &MessageRequest, + payload: &mut Payload, + ) -> Result; } ```rust diff --git a/src/extractor.rs b/src/extractor.rs index 57638fcf..6f31a4bd 100644 --- a/src/extractor.rs +++ b/src/extractor.rs @@ -1,4 +1,3 @@ -use async_trait::async_trait; use std::net::SocketAddr; use std::sync::Arc; @@ -36,14 +35,17 @@ impl Payload<'_> { } } -/// Asynchronous extractor trait. -#[async_trait] +/// Trait for extracting data from a [`MessageRequest`]. pub trait FromMessageRequest: Sized { /// Error type returned when extraction fails. type Error: std::error::Error + Send + Sync + 'static; /// Perform extraction from the request and payload. - async fn from_message_request( + /// + /// # Errors + /// + /// Returns an error if extraction fails. + fn from_message_request( req: &MessageRequest, payload: &mut Payload<'_>, ) -> Result; diff --git a/src/server.rs b/src/server.rs index 59f2e20f..66219a5a 100644 --- a/src/server.rs +++ b/src/server.rs @@ -40,8 +40,7 @@ where /// ``` workers: num_cpus::get().max(1), - /// ```no_run - /// use wireframe::{app::WireframeApp, server::WireframeServer}; + /// Set the number of worker tasks to spawn for the server. /// /// #[tokio::main] /// async fn main() -> std::io::Result<()> { From 601045bceeb92f60299f2de21b5d64f40ba8e597 Mon Sep 17 00:00:00 2001 From: Leynos Date: Fri, 13 Jun 2025 07:34:22 +0100 Subject: [PATCH 09/10] Rename middleware output type --- src/middleware.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/middleware.rs b/src/middleware.rs index 77f9aaeb..7a2107e7 100644 --- a/src/middleware.rs +++ b/src/middleware.rs @@ -31,8 +31,8 @@ where async fn transform(&self, service: S) -> Self::Wrapped; /// let service = MyService::default(); /// let next = Next::new(&service); - /// ``` - pub const fn new(service: &'a S) -> Self { + type Output: Service; + async fn transform(&self, service: S) -> Self::Output; Self { service } } From b711bcfd93bd5d25e4a555db4f8e02f38cb137f5 Mon Sep 17 00:00:00 2001 From: Leynos Date: Fri, 13 Jun 2025 07:53:46 +0100 Subject: [PATCH 10/10] Rename Transform output type --- src/middleware.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/middleware.rs b/src/middleware.rs index 7a2107e7..ba5ab521 100644 --- a/src/middleware.rs +++ b/src/middleware.rs @@ -31,8 +31,8 @@ where async fn transform(&self, service: S) -> Self::Wrapped; /// let service = MyService::default(); /// let next = Next::new(&service); - type Output: Service; - async fn transform(&self, service: S) -> Self::Output; + type Wrapped: Service; + async fn transform(&self, service: S) -> Self::Wrapped; Self { service } }