diff --git a/docs/roadmap.md b/docs/roadmap.md index f0296d59..811ef135 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -26,10 +26,35 @@ 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 + // No extra imports required + use wireframe::{ + app::{Service, WireframeApp}, + server::WireframeServer, + }; + + async fn handler() {} + + #[tokio::main] + async fn main() -> std::io::Result<()> { + let factory = || { + WireframeApp::new() + .unwrap() + .route(1, Box::new(|| Box::pin(handler()))) + .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..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; /// @@ -69,6 +69,22 @@ impl SharedState { /// assert_eq!(*state, 5); /// ``` #[must_use] + pub fn new(inner: Arc) -> Self { + Self(inner) + } +} + +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 { @@ -91,20 +107,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 +119,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..113daf03 100644 --- a/src/middleware.rs +++ b/src/middleware.rs @@ -20,48 +20,19 @@ 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. + #[inline] + #[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. + #[must_use = "await the returned future"] pub async fn call(&self, req: ServiceRequest) -> Result { self.service.call(req).await } @@ -83,7 +54,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..2123b9e5 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); - /// ``` - workers: num_cpus::get().max(1), + /// 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(), + } + } - /// 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