intrepid_core/routing/
routes.rs1use std::{collections::HashMap, sync::Arc};
2use uuid::Uuid;
3
4use super::path_error::PathError;
5
6#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
8#[repr(transparent)]
9pub struct RouteId(Uuid);
10
11impl From<Uuid> for RouteId {
12 fn from(uuid: Uuid) -> Self {
13 Self(uuid)
14 }
15}
16
17#[derive(Clone, Default, Debug)]
20pub struct Routes {
21 router: path_tree::PathTree<RouteId>,
22 paths_by_id: HashMap<RouteId, Arc<str>>,
23 ids_by_path: HashMap<Arc<str>, RouteId>,
24}
25
26impl Routes {
27 pub fn at<'route, 'path>(
29 &'route self,
30 path: &'path str,
31 ) -> Option<(&'route RouteId, path_tree::Path<'route, 'path>)> {
32 self.router.find(path)
33 }
34
35 pub fn insert(&mut self, route: impl Into<String>, value: RouteId) {
37 let route = route.into();
38
39 let _index = self.router.insert(route.as_str(), value);
40 let shared_path: Arc<str> = route.into();
41
42 self.paths_by_id.insert(value, shared_path.clone());
43 self.ids_by_path.insert(shared_path, value);
44 }
45
46 pub fn get_id(&self, path: &str) -> Option<RouteId> {
48 self.ids_by_path.get(path).copied()
49 }
50
51 pub fn get_path(&self, id: RouteId) -> Option<&str> {
53 self.paths_by_id.get(&id).map(|path| path.as_ref())
54 }
55
56 pub fn capture<T>(&self, path: impl AsRef<str>) -> Result<T, PathError>
58 where
59 T: serde::de::DeserializeOwned,
60 {
61 let Some((_route_id, captures)) = self.router.find(path.as_ref()) else {
62 return Err(PathError::FailedToCapture(path.as_ref().to_string()));
63 };
64
65 let mut raws = Vec::new();
66
67 for value in &captures.raws {
68 raws.push(value);
69 }
70
71 let slice = serde_json::to_vec(&raws)?;
72
73 Ok(serde_json::from_slice(&slice)?)
74 }
75
76 pub fn paths(&self) -> Vec<String> {
78 let mut routes: Vec<String> = self
79 .ids_by_path
80 .keys()
81 .map(|path| path.to_string())
82 .collect();
83
84 routes.sort();
85 routes
86 }
87}
88
89#[test]
90fn grabbing_path_captures() -> Result<(), tower::BoxError> {
91 let mut routes = Routes::default();
92 let route_id = RouteId::from(uuid::Uuid::new_v4());
93
94 routes.insert("/view/:id/children/:child_id/add/:new_child_name", route_id);
95
96 let uuid_one = uuid::Uuid::new_v4();
97 let uuid_two = uuid::Uuid::new_v4();
98 let uuid_three = uuid::Uuid::new_v4();
99 let path = format!("/view/{uuid_one}/children/{uuid_two}/add/{uuid_three}");
100
101 let uuids: (uuid::Uuid, uuid::Uuid, uuid::Uuid) = routes.capture(path)?;
102
103 assert_eq!(uuids, (uuid_one, uuid_two, uuid_three));
104
105 Ok(())
106}