1use itertools::EitherOrBoth::{Both, Left};
4use itertools::Itertools;
5
6pub fn map_path(path: &str, path_template: &str) -> Option<Vec<(String, Option<String>)>> {
9 if path.is_empty() || path_template.is_empty() {
10 return None;
11 }
12
13 let path_in = path.split('/').filter(|part| !part.is_empty()).collect_vec();
14 let path_template = path_template.split('/').filter(|part| !part.is_empty()).collect_vec();
15 if path_in.len() >= path_template.len() {
16 let mut path_map = vec![];
17 for item in path_in.iter().zip_longest(path_template) {
18 if let Both(a, b) = item {
19 if b.starts_with('{') && b.ends_with('}') {
20 path_map.push((a.to_string(), Some(b[1..(b.len() - 1)].to_string())));
21 } else if *a == b {
22 path_map.push((a.to_string(), None));
23 } else {
24 return None
25 }
26 } else if let Left(a) = item {
27 path_map.push((a.to_string(), None));
28 } else {
29 return None
30 }
31 }
32 Some(path_map)
33 } else {
34 None
35 }
36}
37
38#[cfg(test)]
39mod tests {
40 use expectest::prelude::*;
41
42 use crate::paths::map_path;
43
44 #[test]
45 fn map_path_simple_values() {
46 expect!(map_path("", "")).to(be_none());
47 expect!(map_path("/", "/")).to(be_equal_to(Some(vec![])));
48 expect!(map_path("/a", "/a")).to(be_equal_to(Some(vec![("a".to_string(), None)])));
49 expect!(map_path("/a", "/a")).to(be_equal_to(Some(vec![("a".to_string(), None)])));
50 expect!(map_path("/a/", "/a")).to(be_equal_to(Some(vec![("a".to_string(), None)])));
51 expect!(map_path("/a/b", "/a/b")).to(be_equal_to(Some(vec![("a".to_string(), None),
52 ("b".to_string(), None)])));
53 expect!(map_path("/a/b/c", "/a/b/c")).to(be_equal_to(Some(vec![("a".to_string(), None),
54 ("b".to_string(), None), ("c".to_string(), None)])));
55
56 expect!(map_path("", "/")).to(be_none());
57 expect!(map_path("/", "")).to(be_none());
58 expect!(map_path("/", "/a")).to(be_none());
59 expect!(map_path("/a", "/")).to(be_some().value(vec![("a".to_string(), None)]));
60 expect!(map_path("/a/b", "/a")).to(be_some().value(vec![("a".to_string(), None), ("b".to_string(), None)]));
61 expect!(map_path("/a/b", "/a/b/c")).to(be_none());
62 }
63
64 #[test]
65 fn map_path_with_variables() {
66 expect!(map_path("/a", "/{id}")).to(be_equal_to(Some(vec![("a".to_string(), Some("id".to_string()))])));
67 expect!(map_path("/a/", "/{id}")).to(be_equal_to(Some(vec![("a".to_string(), Some("id".to_string()))])));
68 expect!(map_path("/a", "/{id}/")).to(be_equal_to(Some(vec![("a".to_string(), Some("id".to_string()))])));
69 expect!(map_path("/a/b", "/a/{id}")).to(be_equal_to(Some(vec![("a".to_string(), None),
70 ("b".to_string(), Some("id".to_string()))])));
71 expect!(map_path("/a/b", "/{id}/b")).to(be_equal_to(Some(vec![("a".to_string(), Some("id".to_string())),
72 ("b".to_string(), None)])));
73 expect!(map_path("/a/b", "/{id}/{id}")).to(be_equal_to(Some(vec![("a".to_string(), Some("id".to_string())),
74 ("b".to_string(), Some("id".to_string()))])));
75 expect!(map_path("/a/b/c", "/a/{b}/c")).to(be_equal_to(Some(vec![("a".to_string(), None),
76 ("b".to_string(), Some("b".to_string())), ("c".to_string(), None)])));
77
78 expect!(map_path("/", "/{id}")).to(be_none());
79 expect!(map_path("/a/b", "/{id}")).to(be_some().value(vec![
80 ("a".to_string(), Some("id".to_string())),
81 ("b".to_string(), None)
82 ]));
83 expect!(map_path("/a", "/{id}/b")).to(be_none());
84 expect!(map_path("/a", "/{id}/{id}")).to(be_none());
85 expect!(map_path("/a/b/c", "/{id}/{id}")).to(be_some().value(vec![
86 ("a".to_string(), Some("id".to_string())),
87 ("b".to_string(), Some("id".to_string())),
88 ("c".to_string(), None)
89 ]));
90 }
91}