1mod compile;
2mod path;
3
4pub use path::{join_paths, normalize_path, to_brace_path};
5pub(crate) use compile::{compile_router, CompiledRouter};
6pub(crate) use path::to_matchit_path;
7
8use path::normalize_prefix;
9
10use crate::handler::{ErrorHandlerFn, FallibleHandler, IntoHandler};
11use crate::middleware::{IntoMwEntry, MwEntry};
12use crate::raw::{IntoRawHandler, RawHandler};
13use crate::response::Response;
14use crate::route_value::{MetaMap, RouteValue};
15use crate::state::TypeMap;
16use http::Method;
17use std::collections::HashMap;
18use std::sync::Arc;
19
20struct RouteDef {
21 method: Method,
22 path: String,
24 middleware: Vec<MwEntry>,
25 handler: FallibleHandler,
26 meta: MetaMap,
27}
28
29struct RawDef {
30 path: String,
31 handler: RawHandler,
32}
33
34#[derive(Clone)]
36pub enum RouteEntry {
37 Http {
38 method: Method,
39 path: String,
40 meta: MetaMap,
42 },
43 Raw {
44 path: String,
45 },
46}
47
48#[derive(Clone)]
50pub struct RouteTable(pub Vec<RouteEntry>);
51
52pub(crate) type CatcherMap = HashMap<u16, FallibleHandler>;
54
55pub struct Router {
57 routes: Vec<RouteDef>,
58 raw_routes: Vec<RawDef>,
59 middleware: Vec<MwEntry>,
60 pub(crate) state: TypeMap,
61 pub(crate) defaults: MetaMap,
63 last_was_route: bool,
65 catchers: CatcherMap,
67 scoped_catchers: Vec<(String, CatcherMap)>,
69 error_handler: Option<ErrorHandlerFn>,
70}
71
72impl Router {
73 pub fn new() -> Self {
74 Self {
75 routes: Vec::new(),
76 raw_routes: Vec::new(),
77 middleware: Vec::new(),
78 state: TypeMap::new(),
79 defaults: MetaMap::new(),
80 last_was_route: false,
81 catchers: HashMap::new(),
82 scoped_catchers: Vec::new(),
83 error_handler: None,
84 }
85 }
86
87 pub(crate) fn clone_for_compile(&self) -> Router {
89 Router {
90 routes: self
91 .routes
92 .iter()
93 .map(|r| RouteDef {
94 method: r.method.clone(),
95 path: r.path.clone(),
96 middleware: r.middleware.clone(),
97 handler: Arc::clone(&r.handler),
98 meta: r.meta.clone(),
99 })
100 .collect(),
101 raw_routes: self
102 .raw_routes
103 .iter()
104 .map(|r| RawDef {
105 path: r.path.clone(),
106 handler: Arc::clone(&r.handler),
107 })
108 .collect(),
109 middleware: self.middleware.clone(),
110 state: self.state.clone_map(),
111 defaults: self.defaults.clone(),
112 last_was_route: self.last_was_route,
113 catchers: self
114 .catchers
115 .iter()
116 .map(|(s, h)| (*s, Arc::clone(h)))
117 .collect(),
118 scoped_catchers: self
119 .scoped_catchers
120 .iter()
121 .map(|(p, m)| {
122 (
123 p.clone(),
124 m.iter().map(|(s, h)| (*s, Arc::clone(h))).collect(),
125 )
126 })
127 .collect(),
128 error_handler: self.error_handler.as_ref().map(Arc::clone),
129 }
130 }
131
132 pub fn use_middleware<M>(&mut self, mw: M) -> &mut Self
133 where
134 M: IntoMwEntry,
135 {
136 self.last_was_route = false;
137 self.middleware.push(mw.into_mw_entry());
138 self
139 }
140
141 pub fn with<T: RouteValue>(&mut self, value: T) -> &mut Self {
146 if self.last_was_route {
147 if let Some(r) = self.routes.last_mut() {
148 r.meta.insert(value);
149 }
150 } else {
151 self.defaults.insert(value);
152 }
153 self
154 }
155
156 pub fn with_update<T, F>(&mut self, f: F) -> &mut Self
158 where
159 T: RouteValue + Clone + Default,
160 F: FnOnce(&mut T),
161 {
162 if let Some(r) = self.routes.last_mut() {
163 let mut v = r.meta.get::<T>().map(|a| (*a).clone()).unwrap_or_default();
164 f(&mut v);
165 r.meta.insert(v);
166 self.last_was_route = true;
167 }
168 self
169 }
170
171 pub fn route_middleware<M>(&mut self, mw: M) -> &mut Self
173 where
174 M: IntoMwEntry,
175 {
176 if let Some(r) = self.routes.last_mut() {
177 let entry = mw.into_mw_entry();
178 if !r.middleware.iter().any(|e| e.name == entry.name) {
179 r.middleware.push(entry);
180 }
181 }
182 self
183 }
184
185 pub fn route_meta<T: RouteValue>(&mut self, value: T) -> &mut Self {
187 if let Some(r) = self.routes.last_mut() {
188 r.meta.insert(value);
189 self.last_was_route = true;
190 } else {
191 self.defaults.insert(value);
192 }
193 self
194 }
195
196 pub fn state<T>(&mut self, value: T) -> &mut Self
197 where
198 T: Send + Sync + 'static,
199 {
200 self.state.insert(value);
201 self
202 }
203
204 pub fn try_state<T>(&self) -> Option<std::sync::Arc<T>>
206 where
207 T: Send + Sync + 'static,
208 {
209 self.state.get::<T>()
210 }
211
212 pub fn get<H, T>(&mut self, path: &str, handler: H) -> &mut Self
213 where
214 H: IntoHandler<T>,
215 {
216 self.add(Method::GET, path, handler)
217 }
218
219 pub fn post<H, T>(&mut self, path: &str, handler: H) -> &mut Self
220 where
221 H: IntoHandler<T>,
222 {
223 self.add(Method::POST, path, handler)
224 }
225
226 pub fn put<H, T>(&mut self, path: &str, handler: H) -> &mut Self
227 where
228 H: IntoHandler<T>,
229 {
230 self.add(Method::PUT, path, handler)
231 }
232
233 pub fn patch<H, T>(&mut self, path: &str, handler: H) -> &mut Self
234 where
235 H: IntoHandler<T>,
236 {
237 self.add(Method::PATCH, path, handler)
238 }
239
240 pub fn delete<H, T>(&mut self, path: &str, handler: H) -> &mut Self
241 where
242 H: IntoHandler<T>,
243 {
244 self.add(Method::DELETE, path, handler)
245 }
246
247 pub fn redirect(&mut self, from: &str, to: impl Into<String>, status: u16) -> &mut Self {
254 let location = to.into();
255 self.get(from, move || {
256 let location = location.clone();
257 async move { crate::Redirect::with(status, location) }
258 })
259 }
260
261 pub fn raw<H>(&mut self, path: &str, handler: H) -> &mut Self
263 where
264 H: IntoRawHandler,
265 {
266 self.raw_routes.push(RawDef {
267 path: normalize_path(path),
268 handler: handler.into_raw_handler(),
269 });
270 self
271 }
272
273 pub fn mount(&mut self, prefix: &str, other: Router) -> &mut Self {
279 let prefix = normalize_prefix(prefix);
280 let child_mw = other.middleware;
281
282 for mut route in other.routes {
283 route.path = join_paths(&prefix, &route.path);
284 let mut mw = child_mw.clone();
285 mw.extend(route.middleware);
286 route.middleware = mw;
287 let mut meta = other.defaults.clone();
288 meta.extend(route.meta);
289 route.meta = meta;
290 self.routes.push(route);
291 }
292 self.last_was_route = false;
293
294 for mut raw in other.raw_routes {
295 raw.path = join_paths(&prefix, &raw.path);
296 self.raw_routes.push(raw);
297 }
298
299 self.state.extend(other.state);
300
301 if !other.catchers.is_empty() {
302 self.scoped_catchers.push((prefix.clone(), other.catchers));
303 }
304 for (child_prefix, map) in other.scoped_catchers {
305 self.scoped_catchers
306 .push((join_paths(&prefix, &child_prefix), map));
307 }
308 if self.error_handler.is_none() {
309 self.error_handler = other.error_handler;
310 }
311
312 self
313 }
314
315 pub fn group<F>(&mut self, prefix: &str, f: F) -> &mut Self
317 where
318 F: FnOnce(&mut Router),
319 {
320 let mut child = Router::new();
321 f(&mut child);
322 self.mount(prefix, child)
323 }
324
325 pub fn catch<H, T>(&mut self, status: u16, handler: H) -> &mut Self
330 where
331 H: IntoHandler<T>,
332 {
333 self.last_was_route = false;
334 self.catchers.insert(status, handler.into_handler());
335 self
336 }
337
338 pub fn not_found<H, T>(&mut self, handler: H) -> &mut Self
340 where
341 H: IntoHandler<T>,
342 {
343 self.catch(404, handler)
344 }
345
346 pub fn error_handler<F, Fut>(&mut self, f: F) -> &mut Self
348 where
349 F: Fn(crate::error::Error) -> Fut + Send + Sync + 'static,
350 Fut: std::future::Future<Output = Response> + Send + 'static,
351 {
352 self.error_handler = Some(Arc::new(move |err| Box::pin(f(err))));
353 self
354 }
355
356 pub fn route_entries(&self) -> Vec<RouteEntry> {
358 let mut out = Vec::new();
359 for r in &self.routes {
360 let mut meta = self.defaults.clone();
361 meta.extend(r.meta.clone());
362 out.push(RouteEntry::Http {
363 method: r.method.clone(),
364 path: r.path.clone(),
365 meta,
366 });
367 }
368 for r in &self.raw_routes {
369 out.push(RouteEntry::Raw {
370 path: r.path.clone(),
371 });
372 }
373 out
374 }
375
376 pub(crate) fn check_route_values(
378 &self,
379 state: &crate::state::StateMap,
380 installed_plugins: &std::collections::HashSet<&'static str>,
381 ) -> Result<(), String> {
382 use crate::route_value::BuildCtx;
383 let ctx = BuildCtx {
384 state,
385 installed_plugins,
386 route_path: "<defaults>",
387 route_method: None,
388 };
389 self.defaults.check_all(&ctx)?;
390 for r in &self.routes {
391 let mut meta = self.defaults.clone();
392 meta.extend(r.meta.clone());
393 let ctx = BuildCtx {
394 state,
395 installed_plugins,
396 route_path: &r.path,
397 route_method: Some(&r.method),
398 };
399 meta.check_all(&ctx)?;
400 }
401 Ok(())
402 }
403
404 pub fn explain(&self) -> String {
406 use std::fmt::Write;
407 let mut out = String::new();
408 let _ = writeln!(out, "root_middleware: [{}]", format_mw_names(&self.middleware));
409 let _ = writeln!(out, "error_handler: {}", self.error_handler.is_some());
410 let mut catch_lines = Vec::new();
411 if !self.catchers.is_empty() {
412 let mut codes: Vec<_> = self.catchers.keys().copied().collect();
413 codes.sort_unstable();
414 catch_lines.push(format!("/ → {:?}", codes));
415 }
416 for (prefix, map) in &self.scoped_catchers {
417 let mut codes: Vec<_> = map.keys().copied().collect();
418 codes.sort_unstable();
419 let p = if prefix.is_empty() { "/" } else { prefix.as_str() };
420 catch_lines.push(format!("{p} → {:?}", codes));
421 }
422 let _ = writeln!(out, "catchers: [{}]", catch_lines.join("; "));
423 if !self.defaults.is_empty() {
424 let _ = writeln!(out, "defaults: [{}]", self.defaults.labels().join(" "));
425 }
426 for r in &self.routes {
427 let labels = r.meta.labels();
428 if labels.is_empty() {
429 let _ = writeln!(
430 out,
431 "{} {} mw=[{}]",
432 r.method,
433 r.path,
434 format_mw_names(&r.middleware)
435 );
436 } else {
437 let _ = writeln!(
438 out,
439 "{} {} mw=[{}] {}",
440 r.method,
441 r.path,
442 format_mw_names(&r.middleware),
443 labels.join(" ")
444 );
445 }
446 }
447 for r in &self.raw_routes {
448 let _ = writeln!(out, "RAW {} mw=[]", r.path);
449 }
450 out
451 }
452
453 fn add<H, T>(&mut self, method: Method, path: &str, handler: H) -> &mut Self
454 where
455 H: IntoHandler<T>,
456 {
457 self.routes.push(RouteDef {
458 method,
459 path: normalize_path(path),
460 middleware: Vec::new(),
462 handler: handler.into_handler(),
463 meta: MetaMap::new(),
464 });
465 self.last_was_route = true;
466 self
467 }
468}
469
470impl Default for Router {
471 fn default() -> Self {
472 Self::new()
473 }
474}
475
476fn format_mw_names(entries: &[MwEntry]) -> String {
477 entries
478 .iter()
479 .map(|e| e.name.as_str())
480 .collect::<Vec<_>>()
481 .join(", ")
482}