1use std::collections::HashSet;
2
3use super::errors::RouteError;
4use super::spec::{RouteKind, RouteSpec};
5
6#[derive(Debug, Clone)]
7pub struct RouteTable<T> {
8 pub routes: Vec<(RouteSpec, T)>,
9 pub fallback: Option<T>,
10}
11
12impl<T> RouteTable<T> {
13 pub fn new() -> Self {
14 Self {
15 routes: Vec::new(),
16 fallback: None,
17 }
18 }
19
20 pub fn with_capacity(capacity: usize) -> Self {
21 Self {
22 routes: Vec::with_capacity(capacity),
23 fallback: None,
24 }
25 }
26
27 pub fn insert(&mut self, spec: RouteSpec, handler: T) -> Result<(), RouteError> {
28 if spec.kind == RouteKind::Fallback {
29 if self.fallback.is_some() {
30 return Err(RouteError::MultipleFallbacks);
31 }
32 self.fallback = Some(handler);
33 return Ok(());
34 }
35
36 if self.routes.iter().any(|(existing, _)| existing.path == spec.path) {
37 return Err(RouteError::DuplicateRoute(spec.path));
38 }
39
40 self.routes.push((spec, handler));
41 Ok(())
42 }
43
44 pub fn from_routes<I>(routes: I) -> Result<Self, RouteError>
45 where
46 I: IntoIterator<Item = (RouteSpec, T)>,
47 {
48 let mut table = Self::new();
49 let mut seen_paths: HashSet<String> = HashSet::new();
50
51 for (spec, handler) in routes {
52 if spec.kind == RouteKind::Fallback {
53 if table.fallback.is_some() {
54 return Err(RouteError::MultipleFallbacks);
55 }
56 table.fallback = Some(handler);
57 continue;
58 }
59
60 if !seen_paths.insert(spec.path.clone()) {
61 return Err(RouteError::DuplicateRoute(spec.path));
62 }
63
64 table.routes.push((spec, handler));
65 }
66
67 Ok(table)
68 }
69}