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, &current_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}