ignitia/router/mod.rs
1//! # Router Module - High-Performance Request Routing
2//!
3//! This module provides the core routing functionality for the Ignitia web framework.
4//! It implements an efficient radix tree-based router with support for:
5//!
6//! - Path parameters (`{id}`, `{name}`)
7//! - Wildcard routes (`*filepath`)
8//! - Nested routers with prefix mounting
9//! - Global and route-specific middleware
10//! - HTTP method-based routing (GET, POST, PUT, DELETE, etc.)
11//! - State management across routes
12//! - WebSocket endpoint registration (with feature flag)
13//! - Compile-time route optimization with atomic swapping
14//!
15//! ## Architecture
16//!
17//! The router uses a two-phase design:
18//! 1. **Build Phase**: Routes are registered and middleware is configured
19//! 2. **Compile Phase**: Routes are optimized and middleware is pre-wrapped
20//!
21//! This approach allows for zero-cost route matching at runtime with all
22//! middleware composition done once during compilation.
23//!
24//! ## Performance Features
25//!
26//! - Lock-free compiled route access using `ArcSwap`
27//! - Radix tree for O(log n) route lookups
28//! - Pre-compiled middleware chains
29//! - Zero-allocation route matching
30//! - Efficient parameter extraction
31//!
32//! ## Usage Example
33//!
34//! ```
35//! use ignitia::Router;
36//!
37//! let router = Router::new()
38//! .get("/users", list_users)
39//! .post("/users", create_user)
40//! .get("/users/{id}", get_user)
41//! .middleware(LoggerMiddleware::new());
42//! ```
43
44pub mod method;
45pub mod radix;
46pub mod route;
47
48use crate::handler::universal_handler;
49use crate::middleware::{BoxFuture, Middleware, Next};
50use crate::response::IntoResponse;
51use crate::{Error, Extensions, Handler, HandlerFn, Request, Response, Result};
52use arc_swap::ArcSwap;
53use dashmap::DashMap;
54use http::Method;
55use parking_lot::RwLock;
56use std::sync::Arc;
57
58pub use radix::{RadixNode, RadixRouter};
59pub use route::Route;
60
61/// Helper macro to define HTTP method routing functions
62///
63/// This macro generates convenience methods for each HTTP method,
64/// reducing boilerplate when defining routes.
65macro_rules! define_http_method {
66 ($name:ident, $method:expr, $doc:expr) => {
67 #[doc = $doc]
68 pub fn $name<H, T>(self, path: &str, handler: H) -> Self
69 where
70 H: crate::handler::UniversalHandler<T>,
71 {
72 self.route_with(path, $method, handler)
73 }
74 };
75}
76
77/// A handler with attached middleware layers
78///
79/// This struct represents a handler function along with its middleware chain.
80/// It allows building up middleware layers before converting to a final handler.
81///
82/// # Example
83///
84/// ```
85/// let layered = LayeredHandler::new(my_handler)
86/// .layer(AuthMiddleware::new())
87/// .layer(RateLimitMiddleware::new());
88/// ```
89#[derive(Clone)]
90pub struct LayeredHandler {
91 /// The core handler function
92 handler: HandlerFn,
93 /// Middleware layers to apply to this handler
94 middleware: Vec<Arc<dyn Middleware>>,
95}
96
97impl LayeredHandler {
98 /// Create a new layered handler from any handler type
99 ///
100 /// # Example
101 ///
102 /// ```
103 /// async fn handler() -> &'static str { "Hello" }
104 /// let layered = LayeredHandler::new(handler);
105 /// ```
106 pub fn new<H, T>(handler: H) -> Self
107 where
108 H: crate::handler::UniversalHandler<T>,
109 {
110 Self {
111 handler: universal_handler(handler),
112 middleware: Vec::new(),
113 }
114 }
115
116 /// Add a middleware layer to this handler
117 ///
118 /// Middleware is applied in the order it's added.
119 ///
120 /// # Example
121 ///
122 /// ```
123 /// layered
124 /// .layer(LoggerMiddleware::new())
125 /// .layer(AuthMiddleware::new());
126 /// ```
127 pub fn layer<M: Middleware + 'static>(mut self, mw: M) -> Self {
128 self.middleware.push(Arc::new(mw));
129 self
130 }
131
132 /// Convert this layered handler into a final HandlerFn
133 ///
134 /// This wraps the handler with all its middleware layers.
135 pub fn into_handler(self) -> HandlerFn {
136 wrap_handler_with_middleware(self.handler, self.middleware)
137 }
138}
139
140/// Compiled router state for lock-free access
141///
142/// This struct represents the optimized, ready-to-use router state.
143/// All middleware is pre-wrapped and routes are optimized for fast lookups.
144#[derive(Clone)]
145struct CompiledRouter {
146 /// The radix tree with optimized routes
147 radix_router: RadixRouter,
148 /// Global middleware (empty after compilation)
149 _middleware: Vec<Arc<dyn Middleware>>,
150 /// Handler for 404 Not Found responses
151 not_found_handler: Option<HandlerFn>,
152}
153
154/// High-performance HTTP router with radix tree routing
155///
156/// The `Router` is the core routing component of Ignitia. It uses a radix tree
157/// for efficient path matching and supports advanced features like nested routers,
158/// middleware composition, and state management.
159///
160/// ## Features
161///
162/// - **Radix Tree Routing**: O(log n) route lookups
163/// - **Path Parameters**: Extract dynamic segments from URLs
164/// - **Wildcard Routes**: Match arbitrary path suffixes
165/// - **Nested Routers**: Compose routers with path prefixes
166/// - **Middleware**: Apply middleware globally or per-route
167/// - **State Management**: Share state across handlers
168/// - **Atomic Compilation**: Lock-free route access after compilation
169///
170/// ## Example
171///
172/// ```
173/// let router = Router::new()
174/// .get("/", index_handler)
175/// .get("/users/{id}", get_user)
176/// .post("/users", create_user)
177/// .middleware(LoggerMiddleware::new())
178/// .state(db_pool);
179/// ```
180pub struct Router {
181 /// Mutable router configuration (read/write locked)
182 pub inner: Arc<RwLock<RouterInner>>,
183 /// Compiled, optimized router state (lock-free read access)
184 compiled: ArcSwap<CompiledRouter>,
185}
186
187/// Internal mutable router state
188///
189/// This struct holds the router configuration during the build phase.
190/// It's protected by a RwLock for safe concurrent access.
191pub struct RouterInner {
192 /// The radix tree router
193 radix_router: RadixRouter,
194 /// Global middleware stack
195 middleware: Vec<Arc<dyn Middleware>>,
196 /// Custom 404 handler
197 not_found_handler: Option<HandlerFn>,
198 /// Nested routers for composition
199 nested_routers: Vec<(String, Router)>,
200 /// Dirty flag to trigger recompilation
201 dirty: bool,
202 /// Shared state extensions
203 pub extensions: Extensions,
204
205 #[cfg(feature = "websocket")]
206 #[cfg_attr(docsrs, doc(cfg(feature = "websocket")))]
207 /// WebSocket endpoint handlers
208 websocket_routes: DashMap<String, Arc<dyn crate::websocket::WebSocketHandler>>,
209}
210impl Router {
211 /// Create a new empty router
212 ///
213 /// # Example
214 ///
215 /// ```
216 /// let router = Router::new();
217 /// ```
218 pub fn new() -> Self {
219 let inner = RouterInner {
220 radix_router: RadixRouter::new(),
221 middleware: Vec::new(),
222 not_found_handler: None,
223 nested_routers: Vec::new(),
224 extensions: Extensions::new(),
225 dirty: true,
226 #[cfg(feature = "websocket")]
227 websocket_routes: DashMap::new(),
228 };
229
230 Self {
231 inner: Arc::new(RwLock::new(inner)),
232 compiled: ArcSwap::new(Arc::new(CompiledRouter {
233 radix_router: RadixRouter::new(),
234 _middleware: Vec::new(),
235 not_found_handler: None,
236 })),
237 }
238 }
239
240 /// Extract all routes from a radix router
241 ///
242 /// Used internally for router merging and inspection.
243 fn extract_radix_routes(radix_router: &RadixRouter) -> DashMap<Method, Vec<Route>> {
244 let routes = DashMap::new();
245 Self::extract_node_routes(&radix_router.root, "", &routes);
246 routes
247 }
248
249 /// Recursively extract routes from radix tree nodes
250 ///
251 /// Traverses the radix tree and collects all registered routes.
252 fn extract_node_routes(
253 node: &RadixNode,
254 path_prefix: &str,
255 routes: &DashMap<Method, Vec<Route>>,
256 ) {
257 let current_path = if path_prefix.is_empty() {
258 if let Some(param_name) = &node.param_name {
259 if node.is_wildcard {
260 format!("/{{*{}}}", param_name)
261 } else {
262 format!("/{{{}}}", param_name)
263 }
264 } else {
265 node.path.clone()
266 }
267 } else {
268 if let Some(param_name) = &node.param_name {
269 let param_syntax = if node.is_wildcard {
270 format!("/{{*{}}}", param_name)
271 } else {
272 format!("/{{{}}}", param_name)
273 };
274 format!("{}{}", path_prefix.trim_end_matches('/'), param_syntax)
275 } else if node.path.is_empty() {
276 path_prefix.to_string()
277 } else if node.path.starts_with('/') {
278 format!("{}{}", path_prefix.trim_end_matches('/'), node.path)
279 } else {
280 format!("{}/{}", path_prefix.trim_end_matches('/'), node.path)
281 }
282 };
283
284 for entry in &node.handlers {
285 let method = entry.key();
286 let handler = entry.value();
287 let route_path = if current_path.is_empty() {
288 "/".to_string()
289 } else if !current_path.starts_with('/') {
290 format!("/{}", current_path)
291 } else {
292 current_path.clone()
293 };
294
295 let route = Route::new(&route_path, method.clone(), handler.clone());
296 routes
297 .entry(method.clone())
298 .or_insert_with(Vec::new)
299 .push(route);
300 }
301
302 for child in &node.children {
303 Self::extract_node_routes(child, ¤t_path, routes);
304 }
305 }
306
307 /// Register a route with a handler
308 ///
309 /// This is the low-level route registration method. Most users should use
310 /// the convenience methods like `get()`, `post()`, etc.
311 ///
312 /// # Arguments
313 ///
314 /// * `path` - The URL path pattern (e.g., "/users/{id}")
315 /// * `method` - The HTTP method
316 /// * `handler` - The handler function
317 ///
318 /// # Example
319 ///
320 /// ```
321 /// router.route("/api/users", Method::GET, list_users);
322 /// ```
323 pub fn route(self, path: &str, method: Method, handler: HandlerFn) -> Self {
324 let full_path = normalize_path(path);
325 let mut inner = self.inner.write();
326 inner.dirty = true;
327 inner.radix_router.insert(&full_path, method, handler);
328 drop(inner);
329 self
330 }
331
332 /// Register a route with a universal handler
333 ///
334 /// Accepts any handler that implements `UniversalHandler<T>`.
335 ///
336 /// # Example
337 ///
338 /// ```
339 /// router.route_with("/users", Method::GET, list_users_handler);
340 /// ```
341 pub fn route_with<H, T>(self, path: &str, method: Method, handler: H) -> Self
342 where
343 H: crate::handler::UniversalHandler<T>,
344 {
345 self.route(path, method, universal_handler(handler))
346 }
347
348 /// Register a route with a layered handler
349 ///
350 /// Allows attaching route-specific middleware.
351 ///
352 /// # Example
353 ///
354 /// ```
355 /// let layered = LayeredHandler::new(handler)
356 /// .layer(AuthMiddleware::new());
357 /// router.route_with_layered("/admin", Method::GET, layered);
358 /// ```
359 pub fn route_with_layered(self, path: &str, method: Method, lh: LayeredHandler) -> Self {
360 self.route(path, method, lh.into_handler())
361 }
362
363 define_http_method!(get, Method::GET, "Adds a GET route");
364 define_http_method!(post, Method::POST, "Adds a POST route");
365 define_http_method!(put, Method::PUT, "Adds a PUT route");
366 define_http_method!(delete, Method::DELETE, "Adds a DELETE route");
367 define_http_method!(patch, Method::PATCH, "Adds a PATCH route");
368 define_http_method!(head, Method::HEAD, "Adds a HEAD route");
369 define_http_method!(options, Method::OPTIONS, "Adds an OPTIONS route");
370 define_http_method!(connect, Method::CONNECT, "Adds an CONNECT route");
371 define_http_method!(trace, Method::TRACE, "Adds an TRACE route");
372
373 /// Register a handler for all HTTP methods
374 ///
375 /// Convenient for routes that handle multiple methods the same way.
376 ///
377 /// # Example
378 ///
379 /// ```
380 /// router.any("/health", health_check);
381 /// ```
382 pub fn any<H, T>(self, path: &str, handler: H) -> Self
383 where
384 H: crate::handler::UniversalHandler<T>,
385 {
386 let methods = [
387 Method::GET,
388 Method::POST,
389 Method::PUT,
390 Method::DELETE,
391 Method::PATCH,
392 Method::HEAD,
393 Method::OPTIONS,
394 Method::CONNECT,
395 Method::TRACE,
396 ];
397 let mut router = self;
398 for method in methods {
399 router = router.route_with(path, method, handler.clone());
400 }
401 router
402 }
403
404 /// Add global middleware to the router
405 ///
406 /// Global middleware applies to all routes registered on this router.
407 /// Middleware is applied in the order it's added.
408 ///
409 /// # Example
410 ///
411 /// ```
412 /// router
413 /// .middleware(LoggerMiddleware::new())
414 /// .middleware(CorsMiddleware::new());
415 /// ```
416 pub fn middleware<M: Middleware + 'static>(self, middleware: M) -> Self {
417 let mut inner = self.inner.write();
418 inner.dirty = true;
419 inner.middleware.push(Arc::new(middleware));
420 drop(inner);
421 self
422 }
423
424 /// Set a custom 404 Not Found handler
425 ///
426 /// By default, returns a simple "Not Found" response.
427 ///
428 /// # Example
429 ///
430 /// ```
431 /// router.not_found(custom_404_handler);
432 /// ```
433 pub fn not_found<H, T>(self, handler: H) -> Self
434 where
435 H: crate::handler::UniversalHandler<T>,
436 {
437 let mut inner = self.inner.write();
438 inner.dirty = true;
439 inner.not_found_handler = Some(universal_handler(handler));
440 drop(inner);
441 self
442 }
443
444 /// Nest a router under a path prefix
445 ///
446 /// All routes from the nested router are mounted under the specified prefix.
447 /// The nested router's middleware is preserved.
448 ///
449 /// # Example
450 ///
451 /// ```
452 /// let api_router = Router::new()
453 /// .get("/users", list_users)
454 /// .post("/users", create_user);
455 ///
456 /// router.nest("/api", api_router);
457 /// // Now accessible at /api/users
458 /// ```
459 pub fn nest(self, path: &str, router: Router) -> Self {
460 let prefix = normalize_path(path);
461 let mut inner = self.inner.write();
462 inner.dirty = true;
463
464 let nested_inner = router.inner.read();
465
466 // Take nested radix tree, wrap its handlers with nested middleware, and insert under prefix
467 let mut wrapped_root = nested_inner.radix_router.root.clone();
468 wrap_tree_handlers(&mut wrapped_root, nested_inner.middleware.clone());
469 inner
470 .radix_router
471 .insert_nested(&prefix, &RadixRouter { root: wrapped_root });
472
473 #[cfg(feature = "websocket")]
474 {
475 for entry in nested_inner.websocket_routes.iter() {
476 let path = entry.key();
477 let handler = entry.value();
478 let full_path = if path == "/" {
479 prefix.clone()
480 } else {
481 format!("{}{}", prefix.trim_end_matches('/'), path)
482 };
483 inner.websocket_routes.insert(full_path, handler.clone());
484 }
485 }
486
487 if inner.not_found_handler.is_none() {
488 inner.not_found_handler = nested_inner.not_found_handler.clone();
489 }
490
491 Self::merge_extensions(&mut inner.extensions, &nested_inner.extensions);
492 drop(nested_inner);
493 drop(inner);
494 self
495 }
496
497 /// Merge another router into this one
498 ///
499 /// Combines routes, middleware, and state from both routers.
500 /// Useful for modular application composition.
501 ///
502 /// # Example
503 ///
504 /// ```
505 /// router
506 /// .merge(user_routes)
507 /// .merge(product_routes);
508 /// ```
509 pub fn merge(self, other: Router) -> Self {
510 let mut inner = self.inner.write();
511 let other_inner = other.inner.read();
512
513 inner.dirty = true;
514
515 // Merge other radix routes into this router
516 let extracted_routes = Self::extract_radix_routes(&other_inner.radix_router);
517 for entry in extracted_routes.iter() {
518 let method = entry.key().clone();
519 let routes = entry.value();
520 for route in routes.iter() {
521 inner
522 .radix_router
523 .insert(&route.path, method.clone(), route.handler.clone());
524 }
525 }
526
527 inner
528 .middleware
529 .extend(other_inner.middleware.iter().cloned());
530 inner
531 .nested_routers
532 .extend(other_inner.nested_routers.iter().cloned());
533
534 if inner.not_found_handler.is_none() && other_inner.not_found_handler.is_some() {
535 inner.not_found_handler = other_inner.not_found_handler.clone();
536 }
537
538 #[cfg(feature = "websocket")]
539 {
540 for entry in other_inner.websocket_routes.iter() {
541 let path = entry.key();
542 let handler = entry.value();
543 if !inner.websocket_routes.contains_key(path) {
544 inner.websocket_routes.insert(path.clone(), handler.clone());
545 }
546 }
547 }
548
549 Self::merge_extensions(&mut inner.extensions, &other_inner.extensions);
550
551 drop(inner);
552 drop(other_inner);
553 self
554 }
555
556 /// Merge extensions from source into target
557 ///
558 /// Only inserts extensions that don't already exist in target.
559 fn merge_extensions(target_extensions: &mut Extensions, source_extensions: &Extensions) {
560 for entry in source_extensions.map.iter() {
561 let type_id = entry.key();
562 let extension = entry.value();
563 target_extensions.insert_if_not_exists_typeid(*type_id, extension.clone());
564 }
565 }
566
567 /// Register a WebSocket endpoint
568 ///
569 /// WebSocket handlers implement the `WebSocketHandler` trait.
570 ///
571 /// # Example
572 ///
573 /// ```
574 /// router.websocket("/ws", MyWebSocketHandler::new());
575 /// ```
576 #[cfg(feature = "websocket")]
577 pub fn websocket<H, T>(self, path: &str, handler: H) -> Self
578 where
579 H: crate::websocket::UniversalWebSocketHandler<T>,
580 T: Send + Sync + 'static,
581 {
582 let normalized_path = normalize_path(path);
583 let ws_handler = crate::websocket::universal_ws_handler(handler);
584
585 {
586 let mut inner = self.inner.write();
587 inner.dirty = true;
588 inner
589 .websocket_routes
590 .insert(normalized_path.clone(), Arc::clone(&ws_handler));
591 }
592
593 let http_handler = Arc::new(move |req: Request| {
594 Box::pin(async move {
595 if crate::websocket::is_websocket_request(&req) {
596 Ok(crate::websocket::upgrade_connection(&req)?)
597 } else {
598 Ok(Response::bad_request("WebSocket upgrade required"))
599 }
600 }) as crate::handler::BoxFuture<'static, crate::Result<Response>>
601 });
602
603 self.route(&normalized_path, Method::GET, http_handler)
604 }
605
606 /// Register a WebSocket endpoint with a closure
607 ///
608 /// Convenience method for simple WebSocket handlers.
609 ///
610 /// # Example
611 ///
612 /// ```
613 /// router.websocket_fn("/chat", |conn| async move {
614 /// // Handle WebSocket connection
615 /// Ok(())
616 /// });
617 /// ```
618 #[cfg(feature = "websocket")]
619 pub fn websocket_fn<F, Fut, R>(self, path: &str, f: F) -> Self
620 where
621 F: Fn(crate::websocket::WebSocketConnection) -> Fut + Clone + Send + Sync + 'static,
622 Fut: std::future::Future<Output = R> + Send + 'static,
623 R: crate::response::IntoResponse,
624 {
625 use crate::websocket::websocket_handler;
626 self.websocket(path, websocket_handler(f))
627 }
628
629 /// Get all registered WebSocket handlers
630 ///
631 /// Used internally by the server to handle WebSocket upgrades.
632 #[cfg(feature = "websocket")]
633 pub fn get_websocket_handlers(
634 &self,
635 ) -> DashMap<String, Arc<dyn crate::websocket::WebSocketHandler>> {
636 self.inner.read().websocket_routes.clone()
637 }
638
639 /// Add shared state to the router
640 ///
641 /// State can be extracted in handlers using the `State` extractor.
642 ///
643 /// # Example
644 ///
645 /// ```
646 /// let db_pool = create_db_pool();
647 /// router.state(db_pool);
648 /// ```
649 pub fn state<T>(self, state: T) -> Self
650 where
651 T: Clone + Send + Sync + 'static,
652 {
653 let mut inner = self.inner.write();
654 inner.dirty = true;
655 inner.extensions.insert(state);
656 drop(inner);
657 self
658 }
659
660 /// Add Arc-wrapped state to the router
661 ///
662 /// For state that's already in an Arc, avoiding double-wrapping.
663 ///
664 /// # Example
665 ///
666 /// ```
667 /// let db = Arc::new(Database::new());
668 /// router.state_arc(db);
669 /// ```
670 pub fn state_arc<T>(self, state: Arc<T>) -> Self
671 where
672 T: Send + Sync + 'static,
673 {
674 let mut inner = self.inner.write();
675 inner.dirty = true;
676 inner.extensions.insert(state);
677 drop(inner);
678 self
679 }
680
681 /// Add state created by a factory function
682 ///
683 /// The factory is called once when the state is registered.
684 ///
685 /// # Example
686 ///
687 /// ```
688 /// router.state_factory(|| Database::connect());
689 /// ```
690 pub fn state_factory<T, F>(self, factory: F) -> Self
691 where
692 T: Clone + Send + Sync + 'static,
693 F: FnOnce() -> T,
694 {
695 let state = factory();
696 let mut inner = self.inner.write();
697 inner.dirty = true;
698 inner.extensions.insert(state);
699 drop(inner);
700 self
701 }
702
703 /// Check if state of type T exists
704 ///
705 /// # Example
706 ///
707 /// ```
708 /// if router.has_state::<Database>() {
709 /// // Database is available
710 /// }
711 /// ```
712 pub fn has_state<T: Send + Sync + Clone + 'static>(&self) -> bool {
713 self.inner.read().extensions.get::<T>().is_some()
714 }
715
716 /// Get a clone of the state if it exists
717 ///
718 /// Returns None if the state hasn't been registered.
719 ///
720 /// # Example
721 ///
722 /// ```
723 /// if let Some(db) = router.get_state::<Database>() {
724 /// // Use database
725 /// }
726 /// ```
727 pub fn get_state<T: Clone + Send + Sync + 'static>(&self) -> Option<T> {
728 self.inner
729 .read()
730 .extensions
731 .get::<T>()
732 .map(|arc_t| arc_t.as_ref().clone())
733 }
734
735 /// Ensure the router is compiled
736 ///
737 /// Returns the compiled router, recompiling if necessary.
738 /// Uses atomic swap for lock-free access after compilation.
739 fn ensure_compiled(&self) -> Arc<CompiledRouter> {
740 {
741 let inner = self.inner.read();
742 if !inner.dirty {
743 return self.compiled.load_full();
744 }
745 }
746
747 let compiled = {
748 let inner = self.inner.read();
749 self.compile_inner(&*inner)
750 };
751
752 let compiled_arc = Arc::new(compiled);
753 self.compiled.store(Arc::clone(&compiled_arc));
754
755 {
756 let mut inner = self.inner.write();
757 inner.dirty = false;
758 }
759
760 compiled_arc
761 }
762
763 /// Compile the router into optimized state
764 ///
765 /// Pre-wraps all handlers with middleware for zero-cost runtime execution.
766 fn compile_inner(&self, inner: &RouterInner) -> CompiledRouter {
767 let mut middleware = inner.middleware.clone();
768 let mut not_found_handler = inner.not_found_handler.clone();
769
770 // Start with a copy of the radix tree
771 let mut radix_router = inner.radix_router.clone();
772
773 // Wrap nested routers captured earlier are already merged into inner.radix_router
774 // Pre-wrap global middleware into all handlers once at compile time, then clear it
775 if !middleware.is_empty() {
776 // Wrap not_found handler
777 if let Some(h) = &mut not_found_handler {
778 let wrapped = wrap_handler_with_middleware(h.clone(), middleware.clone());
779 not_found_handler = Some(wrapped);
780 }
781
782 // Wrap the whole tree
783 let mut root = radix_router.root.clone();
784 wrap_tree_handlers(&mut root, middleware.clone());
785 radix_router = RadixRouter { root };
786
787 // Clear middleware for runtime fast path
788 middleware.clear();
789 }
790
791 CompiledRouter {
792 radix_router,
793 _middleware: middleware,
794 not_found_handler,
795 }
796 }
797
798 /// Handle an incoming HTTP request
799 ///
800 /// This is the main entry point for request processing.
801 /// Routes are looked up in the compiled radix tree and handlers are executed.
802 ///
803 /// # Performance
804 ///
805 /// - Lock-free route lookup using ArcSwap
806 /// - O(log n) path matching with radix tree
807 /// - Zero allocation for route matching
808 /// - Pre-compiled middleware chains
809 #[inline]
810 pub async fn handle(&self, req: Request) -> Result<Response> {
811 let compiled = self.ensure_compiled();
812 let mut req = req;
813 {
814 let inner = self.inner.read();
815 Self::merge_extensions(&mut req.extensions, &inner.extensions);
816 }
817 self.handle_radix_route(&compiled, req).await
818 }
819
820 /// Handle a request using radix tree routing
821 ///
822 /// Performs path matching and parameter extraction.
823 async fn handle_radix_route(
824 &self,
825 compiled: &CompiledRouter,
826 req: Request,
827 ) -> Result<Response> {
828 if let Some((handler, params)) = compiled.radix_router.lookup(&req.method, req.uri.path()) {
829 let mut req = req;
830 req.params = params;
831 return handler.handle(req).await;
832 }
833
834 if let Some(handler) = &compiled.not_found_handler {
835 handler.handle(req.clone()).await
836 } else {
837 Err(Error::NotFound(req.uri.path().to_string()))
838 }
839 }
840
841 /// Check if a route exists for the given method and path
842 ///
843 /// Useful for OPTIONS requests or route introspection.
844 ///
845 /// # Example
846 ///
847 /// ```
848 /// if router.matches(&Method::GET, "/users") {
849 /// // Route exists
850 /// }
851 /// ```
852 pub fn matches(&self, method: &Method, path: &str) -> bool {
853 let compiled = self.ensure_compiled();
854 compiled.radix_router.lookup(method, path).is_some()
855 }
856
857 /// Get routing statistics
858 ///
859 /// Returns information about the radix tree structure.
860 ///
861 /// # Example
862 ///
863 /// ```
864 /// if let Some(stats) = router.stats() {
865 /// println!("Total routes: {}", stats.handler_count);
866 /// }
867 pub fn stats(&self) -> Option<crate::router::radix::RadixStats> {
868 let compiled = self.ensure_compiled();
869 Some(compiled.radix_router.stats())
870 }
871
872 /// Print the routing tree for debugging
873 ///
874 /// Outputs a human-readable representation of all registered routes.
875 ///
876 /// # Example
877 ///
878 /// ```
879 /// router.print_tree();
880 /// ```
881 pub fn print_tree(&self) {
882 let compiled = self.ensure_compiled();
883 compiled.radix_router.print_tree();
884 }
885}
886
887/// Wrap a handler with middleware chain
888///
889/// Pre-composes the middleware chain once, creating a single optimized handler.
890/// This is done at compile time, not on every request.
891///
892/// # Performance
893///
894/// The middleware chain is built once and reused for all requests,
895/// eliminating per-request allocation and function composition overhead.
896fn wrap_handler_with_middleware(
897 handler: HandlerFn,
898 middleware: Vec<Arc<dyn Middleware>>,
899) -> HandlerFn {
900 if middleware.is_empty() {
901 return handler;
902 }
903
904 // Terminal handler
905 let terminal = Arc::new(move |req: Request| -> BoxFuture<'static, Response> {
906 let handler = handler.clone();
907 Box::pin(async move {
908 match handler.handle(req).await {
909 Ok(resp) => resp,
910 Err(err) => err.into_response(),
911 }
912 })
913 }) as Arc<dyn Fn(Request) -> BoxFuture<'static, Response> + Send + Sync>;
914
915 // Build chain by folding middleware in reverse
916 let chain = middleware.iter().rev().fold(terminal, |next, mw| {
917 let mw = mw.clone();
918 Arc::new(move |req: Request| -> BoxFuture<'static, Response> {
919 let mw = mw.clone();
920 let next = next.clone();
921
922 Box::pin(async move {
923 let nxt = Next::new(move |r: Request| -> BoxFuture<'static, Response> { next(r) });
924 // Middleware returns Response directly, no need for match
925 mw.handle(req, nxt).await
926 })
927 }) as Arc<dyn Fn(Request) -> BoxFuture<'static, Response> + Send + Sync>
928 });
929
930 // Return final handler
931 Arc::new(
932 move |req: Request| -> BoxFuture<'static, crate::Result<Response>> {
933 let chain = chain.clone();
934 Box::pin(async move { Ok(chain(req).await) })
935 },
936 )
937}
938
939/// Recursively wrap all handlers in a radix tree with middleware
940///
941/// Applies middleware to every handler in the tree, used for global
942/// middleware and nested router middleware.
943fn wrap_tree_handlers(node: &mut RadixNode, middleware: Vec<Arc<dyn Middleware>>) {
944 let new_handlers = DashMap::new();
945 for entry in &node.handlers {
946 let method = entry.key().clone();
947 let handler = entry.value().clone();
948 let wrapped = wrap_handler_with_middleware(handler.clone(), middleware.clone());
949 new_handlers.insert(method.clone(), wrapped);
950 }
951 node.handlers = new_handlers;
952
953 for child in &mut node.children {
954 wrap_tree_handlers(child, middleware.clone());
955 }
956}
957
958/// Normalize a path for routing
959///
960/// Ensures paths start with `/` and don't end with `/` (except root).
961#[inline]
962fn normalize_path(path: &str) -> String {
963 let mut normalized = path.to_string();
964 if !normalized.starts_with('/') {
965 normalized.insert(0, '/');
966 }
967 if normalized != "/" && normalized.ends_with('/') {
968 normalized.pop();
969 }
970 normalized
971}
972
973impl Clone for Router {
974 /// Clone the router
975 ///
976 /// Creates a new router with the same configuration.
977 /// The compiled state is shared using Arc.
978 fn clone(&self) -> Self {
979 let inner = self.inner.read();
980 Self {
981 inner: Arc::new(RwLock::new(RouterInner {
982 radix_router: inner.radix_router.clone(),
983 middleware: inner.middleware.clone(),
984 not_found_handler: inner.not_found_handler.clone(),
985 nested_routers: inner.nested_routers.clone(),
986 dirty: inner.dirty,
987 extensions: inner.extensions.clone(),
988 #[cfg(feature = "websocket")]
989 websocket_routes: inner.websocket_routes.clone(),
990 })),
991 compiled: ArcSwap::new(Arc::new(CompiledRouter {
992 radix_router: RadixRouter::new(),
993 _middleware: Vec::new(),
994 not_found_handler: None,
995 })),
996 }
997 }
998}
999
1000impl Default for Router {
1001 /// Create a default router
1002 ///
1003 /// Equivalent to `Router::new()`.
1004 fn default() -> Self {
1005 Self::new()
1006 }
1007}