Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/extractor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,19 @@ impl<T: Send + Sync> std::ops::Deref for SharedState<T> {
/// let state = Arc::new(42);
/// let shared = SharedState::new(state.clone());
/// assert_eq!(*shared, 42);
/// Returns a reference to the inner value wrapped by `SharedState`.
///
/// Allows transparent access to the underlying shared state as if it were a direct reference.
///
/// # Examples
///
/// ```
/// use std::sync::Arc;
/// use wireframe::extractor::SharedState;
///
/// let state = Arc::new(42);
/// let shared = SharedState::new(state.clone());
/// assert_eq!(*shared, 42);
/// ```
fn deref(&self) -> &Self::Target {
&self.0
Expand Down
29 changes: 28 additions & 1 deletion src/middleware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ pub struct Next<'a, S: Service + ?Sized> {
}

impl<'a, S: Service + ?Sized> Next<'a, S> {
/// Creates a new `Next` instance that wraps a reference to the given service.
///
/// # Examples
///
/// ```
/// let service = MyService::default();
/// let next = Next::new(&service);
/// ```
pub fn new(service: &'a S) -> Self {
Self { service }
}
Expand All @@ -19,7 +27,26 @@ impl<'a, S: Service + ?Sized> Next<'a, S> {
///
/// # Errors
///
/// Propagates any error returned by the wrapped service.
/// Asynchronously calls the wrapped service with the given request, returning its response or error.
///
/// # Examples
///
/// ```
/// # use your_crate::{Next, ServiceRequest, ServiceResponse, Service};
/// # struct DummyService;
/// # #[async_trait::async_trait]
/// # impl Service for DummyService {
/// # type Error = std::convert::Infallible;
/// # async fn call(&self, _req: ServiceRequest) -> Result<ServiceResponse, Self::Error> {
/// # Ok(ServiceResponse)
/// # }
/// # }
/// # let service = DummyService;
/// let next = Next::new(&service);
/// # tokio_test::block_on(async {
/// let response = next.call(ServiceRequest).await.unwrap();
/// # });
/// ```
pub async fn call(&self, req: ServiceRequest) -> Result<ServiceResponse, S::Error> {
self.service.call(req).await
}
Expand Down
46 changes: 44 additions & 2 deletions src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ where
{
/// Create a new server using the given application factory.
#[must_use]
/// Creates a new server with the specified factory function.
///
/// The server is initialised with no bound listener and a default worker count equal to the number of CPU cores (at least one).
///
/// # Examples
///
/// ```
/// let server = WireframeServer::new(my_factory);
/// ```
pub fn new(factory: F) -> Self {
Self {
factory,
Expand All @@ -38,6 +47,19 @@ where

/// Set the number of worker tasks to spawn for the server.
#[must_use]
/// Sets the number of worker tasks to spawn, ensuring at least one.
///
/// Returns a new server instance with the updated worker count.
///
/// # Parameters
///
/// - `count`: The desired number of worker tasks. If less than 1, defaults to 1.
///
/// # Examples
///
/// ```
/// let server = WireframeServer::new(factory).workers(4);
/// ```
pub fn workers(mut self, count: usize) -> Self {
self.workers = count.max(1);
self
Expand All @@ -47,7 +69,9 @@ where
///
/// # Errors
///
/// Returns any I/O error produced while creating the TCP listener.
/// Binds the server to the specified socket address using a non-blocking TCP listener.
///
/// Returns an error if binding or configuring the listener fails.
pub fn bind(mut self, addr: SocketAddr) -> io::Result<Self> {
let std_listener = StdTcpListener::bind(addr)?;
std_listener.set_nonblocking(true)?;
Expand All @@ -64,7 +88,25 @@ where
///
/// # Panics
///
/// Panics if called before [`bind`] has configured the listener.
/// Runs the server, accepting connections and handling shutdown signals.
///
/// Panics if called before `bind` has configured the listener. Spawns worker tasks to accept incoming TCP connections and gracefully shuts down on Ctrl+C.
///
/// # Returns
///
/// An I/O result indicating success or failure.
///
/// # Examples
///
/// ```no_run
/// # use std::net::SocketAddr;
/// # use your_crate::{WireframeServer, WireframeApp};
/// # async fn run_server() -> std::io::Result<()> {
/// let server = WireframeServer::new(|| WireframeApp::new())
/// .bind("127.0.0.1:8080".parse::<SocketAddr>().unwrap())?;
/// server.run().await
/// # }
/// ```
pub async fn run(self) -> io::Result<()> {
let listener = self.listener.expect("`bind` must be called before `run`");
let (shutdown_tx, _) = broadcast::channel(16);
Expand Down