webrune 0.1.2

A composable web server.
Documentation
use crate::{
    Flow::{self, Continue, Exit},
    IntoResponse, Request, Response,
};
use http::Method;
use std::{collections::HashMap, pin::Pin, sync::Arc};

/// A type-erased, method-specific endpoint handler.
///
/// `MethodHandler` is the internal representation used by the router after
/// request extraction and routing have completed.
///
/// It accepts a fully-formed [`Request`] and shared state `S`, and produces
/// a [`Flow`] that always resolves to a concrete [`Response`].
///
/// This indirection allows heterogeneous endpoint handlers to be stored
/// in a single routing table.
pub type MethodHandler<S> = dyn Fn(Request, S) -> Pin<Box<dyn Future<Output = Flow<Response, Response>> + Send + 'static>>
    + Send
    + Sync
    + 'static;

/// A collection of HTTP method handlers for a single route.
///
/// An [`Endpoint`] corresponds to a matched path. Each HTTP method
/// registered for that path maps to a [`MethodHandler`].
pub struct Endpoint<S> {
    /// Mapping from HTTP methods to their corresponding handlers.
    pub methods: HashMap<Method, Arc<MethodHandler<S>>>,
}

/// A handler for a single routed endpoint.
///
/// `EndpointHandler` is a lower-level abstraction than [`Handler`], used
/// specifically by the router. It represents logic that:
/// - operates on extracted request data (`I`),
/// - has access to shared state `S`,
/// - and produces an output or error convertible into a response.
///
/// Unlike [`Handler`], endpoint handlers return `Result`-like semantics,
/// which are later normalized into [`Flow<Response, Response>`].
///
/// # Type Parameters
///
/// - `I`: Extracted request input
/// - `S`: Shared state type
pub trait EndpointHandler<I, S> {
    /// The successful output type.
    type Output: IntoResponse;

    /// The error type.
    type Error: IntoResponse;

    /// The future returned by [`handle`](Self::handle).
    type Future: Future<Output = Flow<Self::Output, Self::Error>>;

    /// Executes the endpoint handler.
    fn handle(&self, input: I, state: S) -> Self::Future;
}

/// Blanket implementation of [`EndpointHandler`] for async functions and closures.
///
/// Any function or closure with the signature:
///
/// ```text
/// fn(I, S) -> impl Future<Output = Result<O, E>>
/// ```
///
/// automatically implements [`EndpointHandler<I, S>`], as long as both
/// `O` and `E` can be converted into a response.
///
/// This allows endpoint handlers to be written using familiar `Result`
/// semantics, while still integrating with the crate’s [`Flow`]-based
/// control model.
impl<F, Fut, I, S, O, E> EndpointHandler<I, S> for F
where
    F: Fn(I, S) -> Fut,
    Fut: Future<Output = Result<O, E>>,
    O: IntoResponse,
    E: IntoResponse,
{
    type Output = O;
    type Error = E;
    type Future = impl Future<Output = Flow<Self::Output, Self::Error>>;

    fn handle(&self, input: I, state: S) -> Self::Future {
        let future = self(input, state);

        async move {
            match future.await {
                Ok(value) => Continue(value),
                Err(value) => Exit(value),
            }
        }
    }
}