Skip to main content

reinhardt_urls/routers/
server_router.rs

1//! Unified Router with hierarchical routing support
2//!
3//! This module provides a unified router that supports:
4//! - **High-performance O(m) route matching** using matchit Radix Tree (m = path length)
5//! - Nested routers with automatic prefix inheritance
6//! - Namespace-based URL reversal
7//! - Middleware and DI context propagation
8//! - Integration with ViewSets, functions, and class-based views
9//!
10//! # Performance Characteristics
11//!
12//! The router uses [matchit](https://docs.rs/matchit) for O(m) route matching where m is the path length:
13//! - Route lookup: O(m) - Independent of the number of registered routes
14//! - Route compilation: O(n) - Done once at startup where n is the number of routes
15//! - Memory: Efficient through Radix Tree's prefix sharing
16//!
17//! With 1000+ routes, matchit provides 3-5x better performance compared to naive O(n×m) linear search.
18//!
19//! # Implementation Details
20//!
21//! Each HTTP method has its own matchit router for optimal performance:
22//! - `GET`, `POST`, `PUT`, `DELETE`, `PATCH`, `HEAD`, `OPTIONS`
23//! - Routes are compiled lazily on first access (thread-safe with RwLock)
24//! - Parameters are extracted directly from matchit's Params
25//!
26//! # Module Layout
27//!
28//! The implementation is split across focused submodules to keep each file
29//! small and reviewable:
30//!
31//! - `types`    — `MiddlewareInfo`, `RouteInfo`, `FunctionRoute`, `ViewRoute`,
32//!   `RouteHandler`, `RouteMatch`, and the `join_path` helper
33//! - `builder` — constructors and builder-style configuration
34//!   (`new`, `with_prefix`, `with_namespace`, `with_di_context`,
35//!   `with_middleware`, `exclude`, `mount`, `group`)
36//! - `registration` — route registration entry points
37//!   (`function`, `handler`, `route`, `viewset`, `endpoint`, `view`,
38//!   `with_route_middleware`)
39//! - `compile` — matchit compilation and `validate_*` helpers
40//! - `introspection` — read-only accessors, `get_all_routes`,
41//!   `register_all_routes`, `reverse`
42//! - `dispatch` — `resolve`, `match_own_routes_*`, `path_exists_for_any_method`
43//! - `router_impls` — `Debug`, `Default`, `Handler`, `RegisterViewSet`
44//! - `handlers` — `FunctionHandler` and `ViewSetHandler` adapters
45//! - `matching` — `path_matches` and `extract_params` utilities
46//! - `global`   — global router registry used by `showurls`
47
48use crate::routers::UrlReverser;
49use matchit::Router as MatchitRouter;
50use reinhardt_di::InjectionContext;
51use reinhardt_middleware::Middleware;
52#[cfg(feature = "viewsets")]
53use std::collections::HashMap;
54use std::sync::{Arc, RwLock};
55
56pub mod global;
57mod handlers;
58mod matching;
59
60mod builder;
61mod compile;
62mod dispatch;
63mod introspection;
64mod registration;
65mod router_impls;
66mod types;
67
68#[cfg(test)]
69mod tests;
70
71use self::types::{FunctionRoute, RouteHandler, ViewRoute};
72
73pub use self::global::{
74	clear_router, get_router, get_router_di_context, is_router_registered,
75	register_di_registrations, register_router, register_router_arc, take_di_registrations,
76};
77pub use self::handlers::FunctionHandler;
78pub use self::matching::{extract_params, path_matches};
79pub use self::types::{MiddlewareInfo, RouteInfo};
80
81/// Unified router with hierarchical routing support
82///
83/// Supports multiple API styles:
84/// - FastAPI-style: Function-based routes
85/// - DRF-style: ViewSets with automatic CRUD
86/// - Django-style: Class-based views
87///
88/// # Examples
89///
90/// ```
91/// use reinhardt_urls::routers::ServerRouter;
92/// use hyper::Method;
93/// # use reinhardt_http::{Request, Response, Result};
94///
95/// # async fn example() -> Result<()> {
96/// // Create a users sub-router
97/// let users_router = ServerRouter::new()
98///     .with_namespace("users")
99///     .function("/export/", Method::GET, |_req| async { Ok(Response::ok()) });
100///
101/// // Verify users router has namespace
102/// assert_eq!(users_router.namespace(), Some("users"));
103///
104/// // Create root router
105/// let router = ServerRouter::new()
106///     .with_prefix("/api/v1/")
107///     .with_namespace("v1")
108///     .function("/health/", Method::GET, |_req| async { Ok(Response::ok()) })
109///     .mount("/users/", users_router);
110///
111/// // Verify root router configuration
112/// assert_eq!(router.prefix(), "/api/v1/");
113/// assert_eq!(router.namespace(), Some("v1"));
114///
115/// // Generated URLs:
116/// // /api/v1/health/
117/// // /api/v1/users/export/
118/// # Ok(())
119/// # }
120/// # tokio::runtime::Runtime::new().unwrap().block_on(example()).unwrap();
121/// ```
122pub struct ServerRouter {
123	/// Router's prefix path
124	pub(crate) prefix: String,
125
126	/// Namespace for URL reversal
127	pub(crate) namespace: Option<String>,
128
129	/// Routes defined in this router
130	pub(crate) routes: Vec<crate::routers::Route>,
131
132	/// ViewSet registrations
133	#[cfg(feature = "viewsets")]
134	pub(crate) viewsets: HashMap<String, Arc<dyn reinhardt_views::viewsets::ViewSet>>,
135
136	/// Function-based routes
137	pub(crate) functions: Vec<FunctionRoute>,
138
139	/// Class-based view routes
140	pub(crate) views: Vec<ViewRoute>,
141
142	/// Child routers
143	pub(crate) children: Vec<ServerRouter>,
144
145	/// DI context
146	pub(crate) di_context: Option<Arc<InjectionContext>>,
147
148	/// Middleware-contributed DI singleton registrations that have been
149	/// harvested by [`Self::with_middleware`] but not yet applied. Filled
150	/// when [`Self::with_middleware`] runs before [`Self::with_di_context`];
151	/// drained either by a later [`Self::with_di_context`] call (into that
152	/// context's `SingletonScope`) or, if no context is ever attached, by
153	/// [`Self::register_all_routes`] (into the global deferred-registration
154	/// list). This avoids both the silent drop and the global-list leak
155	/// described in #4426.
156	pub(crate) pending_middleware_di: reinhardt_di::DiRegistrationList,
157
158	/// Middleware stack
159	pub(crate) middleware: Vec<Arc<dyn Middleware>>,
160
161	/// Middleware type information for runtime introspection
162	pub(crate) middleware_names: Vec<MiddlewareInfo>,
163
164	/// Per-middleware exclusion patterns, indexed parallel to `middleware` vec.
165	/// Each entry contains the exclusion path patterns for the corresponding middleware.
166	pub(crate) middleware_exclusions: Vec<Vec<String>>,
167
168	/// URL reverser
169	pub(crate) reverser: UrlReverser,
170
171	/// Matchit router for GET requests (uses RwLock for thread-safe lazy compilation)
172	pub(crate) get_router: RwLock<MatchitRouter<RouteHandler>>,
173
174	/// Matchit router for POST requests
175	pub(crate) post_router: RwLock<MatchitRouter<RouteHandler>>,
176
177	/// Matchit router for PUT requests
178	pub(crate) put_router: RwLock<MatchitRouter<RouteHandler>>,
179
180	/// Matchit router for DELETE requests
181	pub(crate) delete_router: RwLock<MatchitRouter<RouteHandler>>,
182
183	/// Matchit router for PATCH requests
184	pub(crate) patch_router: RwLock<MatchitRouter<RouteHandler>>,
185
186	/// Matchit router for HEAD requests
187	pub(crate) head_router: RwLock<MatchitRouter<RouteHandler>>,
188
189	/// Matchit router for OPTIONS requests
190	pub(crate) options_router: RwLock<MatchitRouter<RouteHandler>>,
191
192	/// Flag indicating if routes have been compiled (uses RwLock for thread-safety)
193	pub(crate) routes_compiled: RwLock<bool>,
194}