Wado

core:router

HTTP path router (core:router).

Generic over the handler type H. Match algorithm is a segment-level tagged DFA: routes split at / boundaries and each segment becomes a single transition. Hot-path is a deterministic loop with no backtracking; at each state, transitions are tried in this order: literal, then :param, then *wildcard. Once a terminal (or wildcard) is reached, method dispatch tries the specific-method list first, then falls back to the optional any slot.

Static routes (no :param, no *wildcard) are routed through a hashed side-table with pre-built RouteMatch shells. Hits on a static route return a reference into the table, which (assuming Option<&T> niche optimization) costs zero heap allocations per match.

Captured parameters are accessible either by name via params["id"] (IndexValue<String>) or as a typed struct via params.deserialize::<T>() (T: Deserialize). The latter parses directly from byte ranges of the path string without intermediate substring allocations for scalar fields.

See docs/wep-2026-05-06-core-router.md.

Synopsis

let mut routes = Router::<i32>::new();
routes.get("/health", 1);
routes.get("/users/:id", 2);
assert routes.match_path(Method::Get, &"/health") matches { Some(hit) && hit.handler == 1 };
assert routes.match_path(Method::Get, &"/users/42") matches { Some(hit) && hit.handler == 2
    && hit.params.get("id") matches { Some(v) && v == "42" } };

Structs

pub struct PathParams

Captured path parameters for a matched route.

PathParams is a thin handle of references into router-owned data: path is the request path that produced the match, names is the parameter-name list shared with the matched terminal state, and ranges is a flat [start0, end0, start1, end1, ...] of byte ranges into path. Empty for static-route matches; in that case all three fields point at shared empty singletons.

Fields are private.

pub fn len(&self) -> i32

Number of captured parameters (0 for static routes).

pub fn is_empty(&self) -> bool

True when no parameters were captured.

pub fn get<S: AsStrSlice>(&self, name: S) -> Option<String>

Look up a captured parameter by name. Returns None if absent. The returned String is freshly allocated from the matched byte range of the path.

pub fn deserialize<T: Deserialize>(&self) -> Result<T, DeserializeError>

Deserialize captured parameters into a typed struct T. Scalar fields parse directly from path bytes; only String fields incur a substring allocation.

impl IndexValue<String> for PathParams

fn index_value(&self, name: String) -> String

pub struct RouteMatch<H>

Result of a successful route match.

handler: H

params: PathParams

pub struct Router<H>

Generic HTTP path router.

Fields are private.

pub fn new() -> Router<H>

pub fn route<S: AsStrSlice>(&mut self, method: Method, pattern: S, handler: H)

Registers a handler for (method, pattern). Last-write-wins. Panics on a malformed pattern.

pub fn get<S: AsStrSlice>(&mut self, pattern: S, handler: H)

pub fn post<S: AsStrSlice>(&mut self, pattern: S, handler: H)

pub fn put<S: AsStrSlice>(&mut self, pattern: S, handler: H)

pub fn patch<S: AsStrSlice>(&mut self, pattern: S, handler: H)

pub fn delete<S: AsStrSlice>(&mut self, pattern: S, handler: H)

pub fn options<S: AsStrSlice>(&mut self, pattern: S, handler: H)

pub fn any<S: AsStrSlice>(&mut self, pattern: S, handler: H)

Registers a handler that matches any HTTP method (including Method::Other(_)) at pattern. Specific-method handlers at the same pattern take precedence; any is the fallback.

pub fn match_path(&self, method: Method, path: &String) -> Option<&RouteMatch<H>>

Matches (method, path). The path argument must be a URL path (no query string, no fragment).

pub fn allowed_methods<S: AsStrSlice>(&self, path: S) -> List<Method>

Returns the specific methods registered for path. any does not contribute. Empty array on a 404 or when only any is registered.

pub fn match_request(&self, request: &Request) -> Option<&RouteMatch<H>>

Matches against a wasi:http Request. Strips ?query / #frag from the path before matching.

pub struct PathParamsStructAccess

Fields are private.

impl DeserializeStruct for PathParamsStructAccess

fn next_field<S: FieldSchema>(&mut self) -> Result<Option<i32>, DeserializeError>
fn value<T: Deserialize>(&mut self) -> Result<T, DeserializeError>
fn skip(&mut self) -> Result<(), DeserializeError>
fn end(&mut self) -> Result<(), DeserializeError>