fs_router/core/
table.rs

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}