1use itertools::Itertools;
2use snafu::Snafu;
3use std::{
4 collections::{btree_map::Entry, BTreeMap},
5 ops::Index,
6};
7
8pub use crate::join;
9
10#[derive(Clone, Debug, PartialEq, Eq)]
11pub(crate) struct Module<Api> {
12 pub(crate) prefix: Vec<String>,
13 pub(crate) versions: BTreeMap<u64, Api>,
14}
15
16impl<Api> Module<Api> {
17 fn new(prefix: Vec<String>) -> Self {
18 Self {
19 prefix,
20 versions: Default::default(),
21 }
22 }
23
24 pub(crate) fn path(&self) -> String {
25 self.prefix.join("/")
26 }
27}
28
29#[derive(Clone, Debug, Snafu, PartialEq, Eq)]
30pub enum DispatchError {
31 #[snafu(display("duplicate module {prefix} v{version}"))]
32 ModuleAlreadyExists { prefix: String, version: u64 },
33 #[snafu(display("module {prefix} cannot be a prefix of module {conflict}"))]
34 ConflictingModules { prefix: String, conflict: String },
35}
36
37#[derive(Debug)]
39pub(crate) enum Trie<Api> {
40 Branch {
41 prefix: Vec<String>,
43 children: BTreeMap<String, Box<Self>>,
45 },
46 Leaf {
47 module: Module<Api>,
49 },
50}
51
52impl<Api> Default for Trie<Api> {
53 fn default() -> Self {
54 Self::Branch {
55 prefix: vec![],
56 children: Default::default(),
57 }
58 }
59}
60
61impl<Api> Trie<Api> {
62 pub(crate) fn is_singleton(&self) -> bool {
68 matches!(self, Self::Leaf { .. })
69 }
70
71 pub(crate) fn insert<I>(
73 &mut self,
74 prefix: I,
75 version: u64,
76 api: Api,
77 ) -> Result<(), DispatchError>
78 where
79 I: IntoIterator,
80 I::Item: Into<String>,
81 {
82 let mut prefix = prefix.into_iter().map(|segment| segment.into());
83
84 let mut curr = self;
86 while let Some(segment) = prefix.next() {
87 match curr {
89 Self::Branch { prefix, children } => {
90 curr = children.entry(segment.clone()).or_insert_with(|| {
93 let mut prefix = prefix.clone();
94 prefix.push(segment);
95 Box::new(Trie::Branch {
96 prefix,
97 children: Default::default(),
98 })
99 });
100 }
101 Self::Leaf { module } => {
102 return Err(DispatchError::ConflictingModules {
105 prefix: module.path(),
106 conflict: join!(&module.path(), &segment, &prefix.join("/")),
107 });
108 }
109 }
110 }
111
112 if let Self::Branch { prefix, children } = curr {
115 if children.is_empty() {
116 *curr = Self::Leaf {
117 module: Module::new(prefix.clone()),
118 };
119 } else {
120 let prefix = prefix.join("/");
126 let conflict = loop {
127 match curr {
128 Self::Branch { children, .. } => {
129 curr = children
130 .values_mut()
131 .next()
132 .expect("malformed dispatch trie: empty branch");
133 }
134 Self::Leaf { module } => {
135 break module.path();
136 }
137 }
138 };
139 return Err(DispatchError::ConflictingModules { prefix, conflict });
140 }
141 }
142 let Self::Leaf { module } = curr else {
143 unreachable!();
144 };
145
146 let Entry::Vacant(e) = module.versions.entry(version) else {
149 return Err(DispatchError::ModuleAlreadyExists {
150 prefix: module.path(),
151 version,
152 });
153 };
154 e.insert(api);
155 Ok(())
156 }
157
158 pub(crate) fn get<I>(&self, prefix: I) -> Option<&Module<Api>>
163 where
164 I: IntoIterator,
165 I::Item: AsRef<str>,
166 {
167 let mut iter = prefix.into_iter();
168 let module = self.traverse(&mut iter)?;
169 if iter.next().is_some() {
171 None
172 } else {
173 Some(module)
174 }
175 }
176
177 pub(crate) fn search<I>(&self, path: I) -> Option<&Module<Api>>
182 where
183 I: IntoIterator,
184 I::Item: AsRef<str>,
185 {
186 self.traverse(&mut path.into_iter())
187 }
188
189 pub(crate) fn iter(&self) -> Iter<'_, Api> {
191 Iter { stack: vec![self] }
192 }
193
194 fn traverse<I>(&self, iter: &mut I) -> Option<&Module<Api>>
199 where
200 I: Iterator,
201 I::Item: AsRef<str>,
202 {
203 let mut curr = self;
204 loop {
205 match curr {
206 Self::Branch { children, .. } => {
207 let segment = iter.next()?;
209 curr = children.get(segment.as_ref())?;
210 }
211 Self::Leaf { module } => return Some(module),
212 }
213 }
214 }
215}
216
217pub(crate) struct Iter<'a, Api> {
218 stack: Vec<&'a Trie<Api>>,
219}
220
221impl<'a, Api> Iterator for Iter<'a, Api> {
222 type Item = &'a Module<Api>;
223
224 fn next(&mut self) -> Option<Self::Item> {
225 loop {
226 match self.stack.pop()? {
227 Trie::Branch { children, .. } => {
228 self.stack
231 .extend(children.values().rev().map(|boxed| &**boxed));
232 }
233 Trie::Leaf { module } => return Some(module),
234 }
235 }
236 }
237}
238
239impl<'a, Api> IntoIterator for &'a Trie<Api> {
240 type IntoIter = Iter<'a, Api>;
241 type Item = &'a Module<Api>;
242
243 fn into_iter(self) -> Self::IntoIter {
244 self.iter()
245 }
246}
247
248impl<I, Api> Index<I> for Trie<Api>
249where
250 I: IntoIterator,
251 I::Item: AsRef<str>,
252{
253 type Output = Module<Api>;
254
255 fn index(&self, index: I) -> &Self::Output {
256 self.get(index).unwrap()
257 }
258}
259
260pub(crate) fn split(s: &str) -> impl '_ + Iterator<Item = &str> {
265 s.split('/').filter(|seg| !seg.is_empty())
266}
267
268pub(crate) fn join(s1: &str, s2: &str) -> String {
270 let s1 = s1.strip_prefix('/').unwrap_or(s1);
271 let s1 = s1.strip_suffix('/').unwrap_or(s1);
272 let s2 = s2.strip_prefix('/').unwrap_or(s2);
273 let s2 = s2.strip_suffix('/').unwrap_or(s2);
274 if s1.is_empty() {
275 s2.to_string()
276 } else if s2.is_empty() {
277 s1.to_string()
278 } else {
279 format!("{s1}/{s2}")
280 }
281}
282
283#[macro_export]
284macro_rules! join {
285 () => { String::new() };
286 ($s:expr) => { $s };
287 ($head:expr$(, $($tail:expr),*)?) => {
288 $crate::dispatch::join($head, &$crate::join!($($($tail),*)?))
289 }
290}
291
292#[cfg(test)]
293mod test {
294 use super::*;
295
296 #[test]
297 fn test_empty_trie() {
298 let t = Trie::<()>::default();
299 assert_eq!(t.iter().next(), None);
300 assert_eq!(t.get(["mod"]), None);
301 }
302
303 #[test]
304 fn test_branch_trie() {
305 let mut t = Trie::default();
306
307 let mod_a = Module {
308 prefix: vec!["mod".into(), "a".into()],
309 versions: [(0, 0)].into(),
310 };
311 let mod_b = Module {
312 prefix: vec!["mod".into(), "b".into()],
313 versions: [(1, 1)].into(),
314 };
315
316 t.insert(["mod", "a"], 0, 0).unwrap();
317 t.insert(["mod", "b"], 1, 1).unwrap();
318
319 assert_eq!(t.iter().collect::<Vec<_>>(), [&mod_a, &mod_b]);
320
321 assert_eq!(t.search(["mod", "a", "route"]), Some(&mod_a));
322 assert_eq!(t.get(["mod", "a"]), Some(&mod_a));
323 assert_eq!(t.get(["mod", "a", "route"]), None);
324
325 assert_eq!(t.search(["mod", "b", "route"]), Some(&mod_b));
326 assert_eq!(t.get(["mod", "b"]), Some(&mod_b));
327 assert_eq!(t.get(["mod", "b", "route"]), None);
328
329 t.insert(["mod"], 0, 0).unwrap_err();
331 t.insert(Vec::<String>::new(), 0, 0).unwrap_err();
332 t.insert(["mod", "a", "b"], 0, 0).unwrap_err();
333 }
334
335 #[test]
336 fn test_null_prefix() {
337 let mut t = Trie::default();
338
339 let module = Module {
340 prefix: vec![],
341 versions: [(0, 0)].into(),
342 };
343 t.insert(Vec::<String>::new(), 0, 0).unwrap();
344
345 assert_eq!(t.iter().collect::<Vec<_>>(), [&module]);
346 assert_eq!(t.search(["anything"]), Some(&module));
347 assert_eq!(t.get(Vec::<String>::new()), Some(&module));
348 assert_eq!(t.get(["anything"]), None);
349
350 t.insert(["anything"], 1, 1).unwrap_err();
352 }
353}