From ab731b9147c285a35b50a75dc99cfa4715c148ef Mon Sep 17 00:00:00 2001 From: Leynos Date: Fri, 13 Jun 2025 09:42:45 +0100 Subject: [PATCH 1/5] Fix compile errors and clippy issues --- docs/roadmap.md | 28 +++++++++++++++++++++++++++- src/extractor.rs | 19 +++++-------------- src/middleware.rs | 43 ++++++------------------------------------- src/server.rs | 44 ++++++++++---------------------------------- 4 files changed, 48 insertions(+), 86 deletions(-) diff --git a/docs/roadmap.md b/docs/roadmap.md index f0296d59..6f81d9e9 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -26,10 +26,36 @@ after formatting. Line numbers below refer to that file. Provide naming conventions and generic bounds for the `FrameProcessor` trait, state extractors and middleware via `async_trait` and associated types. - - [ ] Provide a minimal, runnable example. + - [x] Provide a minimal, runnable example. Include imports and an async `main` so the snippet compiles out of the box. + ```rust + use std::{future::Future, pin::Pin}; + use wireframe::{ + app::{Service, WireframeApp}, + server::WireframeServer, + }; + + async fn handler() {} + + #[tokio::main] + async fn main() -> std::io::Result<()> { + let factory = || { + let svc: Service = Box::new(|| Box::pin(handler())); + WireframeApp::new() + .unwrap() + .route(1, svc) + .unwrap() + }; + + WireframeServer::new(factory) + .bind("127.0.0.1:7878".parse().unwrap())? + .run() + .await + } + ``` + ## 2. Middleware and Extractors - [ ] Develop a minimal middleware system and extractor traits for payloads, diff --git a/src/extractor.rs b/src/extractor.rs index 6f31a4bd..3259e6bd 100644 --- a/src/extractor.rs +++ b/src/extractor.rs @@ -69,6 +69,10 @@ impl SharedState { /// assert_eq!(*state, 5); /// ``` #[must_use] + pub fn new(inner: Arc) -> Self { + Self(inner) + } +} #[cfg(test)] mod tests { @@ -91,20 +95,6 @@ mod tests { assert_eq!(payload.remaining(), 2); } } - /// 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) - } -} impl std::ops::Deref for SharedState { type Target = T; @@ -117,6 +107,7 @@ impl std::ops::Deref for SharedState { /// /// ``` /// use std::sync::Arc; + /// use wireframe::extractor::SharedState; /// let state = Arc::new(42); /// let shared = SharedState::new(state.clone()); /// assert_eq!(*shared, 42); diff --git a/src/middleware.rs b/src/middleware.rs index ba5ab521..a61e49d3 100644 --- a/src/middleware.rs +++ b/src/middleware.rs @@ -20,48 +20,17 @@ impl<'a, S> Next<'a, S> where S: Service + ?Sized, { - /// Creates a new `Next` instance wrapping a reference to the given service. - /// -/// -/// ```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); - type Wrapped: Service; - async fn transform(&self, service: S) -> Self::Wrapped; + /// Create a new [`Next`] wrapping the given service. + #[must_use] + pub fn new(service: &'a S) -> Self { Self { service } } - /// Call the next service with the given request. + /// Call the next service with the provided request. /// /// # Errors /// - /// 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()); - /// ``` + /// Propagates any error produced by the wrapped service. pub async fn call(&self, req: ServiceRequest) -> Result { self.service.call(req).await } @@ -83,7 +52,7 @@ pub trait Transform: Send + Sync where S: Service, { - /// Wrapped service produced by the middleware. + /// Middleware-wrapped service produced by `transform`. type Output: Service; /// Create a new middleware service wrapping `service`. diff --git a/src/server.rs b/src/server.rs index 66219a5a..5e6e3287 100644 --- a/src/server.rs +++ b/src/server.rs @@ -28,42 +28,18 @@ impl WireframeServer where F: Fn() -> WireframeApp + Send + Sync + Clone + 'static, { - /// Constructs a new `WireframeServer` using the provided application factory closure. - /// - /// 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); - /// ``` + /// Construct a new server using the supplied application factory. + #[must_use] + pub fn new(factory: F) -> Self { + Self { + factory, + listener: None, workers: num_cpus::get().max(1), + } + } - /// Set the number of worker tasks to spawn for the server. - /// - /// #[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 - /// - /// ```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); - /// ``` + /// Set the number of worker tasks to spawn. + #[must_use] pub fn workers(mut self, count: usize) -> Self { self.workers = count.max(1); self From be703149fee36938cc33a8ed883a2c6c90cdae0f Mon Sep 17 00:00:00 2001 From: Leynos Date: Fri, 13 Jun 2025 09:55:04 +0100 Subject: [PATCH 2/5] Add must_use annotation and fix example --- docs/roadmap.md | 46 +++++++++++++++++++++++----------------------- src/middleware.rs | 1 + 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/docs/roadmap.md b/docs/roadmap.md index 6f81d9e9..f8780fce 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -30,31 +30,31 @@ after formatting. Line numbers below refer to that file. Include imports and an async `main` so the snippet compiles out of the box. - ```rust - use std::{future::Future, pin::Pin}; - use wireframe::{ - app::{Service, WireframeApp}, - server::WireframeServer, + ```rust + use std::{future::Future, pin::Pin}; + use wireframe::{ + app::{Service, WireframeApp}, + server::WireframeServer, + }; + + async fn handler() {} + + #[tokio::main] + async fn main() -> std::io::Result<()> { + let factory = || { + let svc: Service = Box::new(|| Box::pin(handler())); + WireframeApp::new() + .unwrap() + .route(1, svc) + .unwrap() }; - async fn handler() {} - - #[tokio::main] - async fn main() -> std::io::Result<()> { - let factory = || { - let svc: Service = Box::new(|| Box::pin(handler())); - WireframeApp::new() - .unwrap() - .route(1, svc) - .unwrap() - }; - - WireframeServer::new(factory) - .bind("127.0.0.1:7878".parse().unwrap())? - .run() - .await - } - ``` + WireframeServer::new(factory) + .bind("127.0.0.1:7878".parse().unwrap())? + .run() + .await + } + ``` ## 2. Middleware and Extractors diff --git a/src/middleware.rs b/src/middleware.rs index a61e49d3..228a0b3c 100644 --- a/src/middleware.rs +++ b/src/middleware.rs @@ -31,6 +31,7 @@ where /// # Errors /// /// Propagates any error produced by the wrapped service. + #[must_use = "call the returned future"] pub async fn call(&self, req: ServiceRequest) -> Result { self.service.call(req).await } From f2c10324a64647bfff5a1b988001c439d91297f2 Mon Sep 17 00:00:00 2001 From: Leynos Date: Fri, 13 Jun 2025 11:50:39 +0100 Subject: [PATCH 3/5] Implement feedback and ensure example compiles --- docs/roadmap.md | 2 +- src/extractor.rs | 14 +++++++++++++- src/middleware.rs | 3 ++- src/server.rs | 4 ++-- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/docs/roadmap.md b/docs/roadmap.md index f8780fce..ffadd0e3 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -31,7 +31,7 @@ after formatting. Line numbers below refer to that file. the box. ```rust - use std::{future::Future, pin::Pin}; + // No extra imports required use wireframe::{ app::{Service, WireframeApp}, server::WireframeServer, diff --git a/src/extractor.rs b/src/extractor.rs index 3259e6bd..dcf0552b 100644 --- a/src/extractor.rs +++ b/src/extractor.rs @@ -60,7 +60,7 @@ impl SharedState { /// /// # Examples /// - /// ```ignore + /// ```no_run /// use std::sync::Arc; /// use wireframe::extractor::SharedState; /// @@ -74,6 +74,18 @@ impl SharedState { } } +impl From> for SharedState { + fn from(inner: Arc) -> Self { + Self(inner) + } +} + +impl From for SharedState { + fn from(inner: T) -> Self { + Self(Arc::new(inner)) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/middleware.rs b/src/middleware.rs index 228a0b3c..113daf03 100644 --- a/src/middleware.rs +++ b/src/middleware.rs @@ -21,6 +21,7 @@ where S: Service + ?Sized, { /// Create a new [`Next`] wrapping the given service. + #[inline] #[must_use] pub fn new(service: &'a S) -> Self { Self { service } @@ -31,7 +32,7 @@ where /// # Errors /// /// Propagates any error produced by the wrapped service. - #[must_use = "call the returned future"] + #[must_use = "await the returned future"] pub async fn call(&self, req: ServiceRequest) -> Result { self.service.call(req).await } diff --git a/src/server.rs b/src/server.rs index 5e6e3287..55dfbb0b 100644 --- a/src/server.rs +++ b/src/server.rs @@ -34,13 +34,13 @@ where Self { factory, listener: None, - workers: num_cpus::get().max(1), + workers: num_cpus::get(), } } /// Set the number of worker tasks to spawn. #[must_use] - pub fn workers(mut self, count: usize) -> Self { + pub fn workers(&mut self, count: usize) -> &mut Self { self.workers = count.max(1); self } From 466f29c3f93c4a33b8a626373d1654161009aee1 Mon Sep 17 00:00:00 2001 From: Leynos Date: Fri, 13 Jun 2025 12:46:10 +0100 Subject: [PATCH 4/5] Restore builder chaining --- src/server.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server.rs b/src/server.rs index 55dfbb0b..2123b9e5 100644 --- a/src/server.rs +++ b/src/server.rs @@ -40,7 +40,7 @@ where /// Set the number of worker tasks to spawn. #[must_use] - pub fn workers(&mut self, count: usize) -> &mut Self { + pub fn workers(mut self, count: usize) -> Self { self.workers = count.max(1); self } From 771b951273f96ccf2985c7de2f768d9561c346e3 Mon Sep 17 00:00:00 2001 From: Leynos Date: Fri, 13 Jun 2025 15:00:19 +0100 Subject: [PATCH 5/5] Clarify runnable example --- docs/roadmap.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/roadmap.md b/docs/roadmap.md index ffadd0e3..811ef135 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -42,10 +42,9 @@ after formatting. Line numbers below refer to that file. #[tokio::main] async fn main() -> std::io::Result<()> { let factory = || { - let svc: Service = Box::new(|| Box::pin(handler())); WireframeApp::new() .unwrap() - .route(1, svc) + .route(1, Box::new(|| Box::pin(handler()))) .unwrap() };