file_system/fundamentals/path/
components.rs

1use core::str::Split;
2
3use super::{Path, SEPARATOR};
4
5#[derive(Debug, Clone, PartialEq, Eq)]
6pub enum Component<'a> {
7    Root,
8    Current,
9    Parent,
10    Normal(&'a str),
11}
12
13impl<'a> From<&'a str> for Component<'a> {
14    fn from(item: &'a str) -> Self {
15        match item {
16            "" => Component::Root,
17            "/" => Component::Root,
18            "." => Component::Current,
19            ".." => Component::Parent,
20            _ => Component::Normal(item),
21        }
22    }
23}
24
25#[derive(Debug, Clone)]
26pub struct Components<'a>(Split<'a, char>);
27
28impl<'a> Components<'a> {
29    pub fn new(path: &'_ Path) -> Components<'_> {
30        Components(path.as_str().split(SEPARATOR))
31    }
32
33    pub fn strip_prefix(self, components: &Components<'a>) -> Option<Components<'a>> {
34        let mut self_iter = self.clone();
35        let components_iter = components.clone();
36
37        for component in components_iter {
38            match self_iter.next() {
39                Some(self_component) if self_component == component => {}
40                _ => return None,
41            }
42        }
43
44        Some(Components(self_iter.0))
45    }
46
47    pub fn get_common_components(self, other: Components<'a>) -> usize {
48        self.zip(other).take_while(|(a, b)| a == b).count()
49    }
50}
51
52impl<'a> Iterator for Components<'a> {
53    type Item = Component<'a>;
54
55    fn next(&mut self) -> Option<Self::Item> {
56        self.0.next().map(Component::from)
57    }
58}
59
60impl DoubleEndedIterator for Components<'_> {
61    fn next_back(&mut self) -> Option<Self::Item> {
62        self.0.next_back().map(Component::from)
63    }
64}
65
66#[cfg(test)]
67mod tests {
68
69    use alloc::{vec, vec::Vec};
70
71    use super::*;
72
73    #[test]
74    fn test_components() {
75        assert_eq!(
76            Components::new(Path::from_str("/a/b/c")).collect::<Vec<_>>(),
77            vec![
78                Component::Root,
79                Component::Normal("a"),
80                Component::Normal("b"),
81                Component::Normal("c")
82            ]
83        );
84
85        assert_eq!(
86            Components::new(Path::from_str("/a/./b/c")).collect::<Vec<_>>(),
87            vec![
88                Component::Root,
89                Component::Normal("a"),
90                Component::Current,
91                Component::Normal("b"),
92                Component::Normal("c")
93            ]
94        );
95
96        assert_eq!(
97            Components::new(Path::from_str("a/b/c")).collect::<Vec<_>>(),
98            vec![
99                Component::Normal("a"),
100                Component::Normal("b"),
101                Component::Normal("c")
102            ]
103        );
104
105        assert_eq!(
106            Components::new(Path::from_str("a/./../b/c")).collect::<Vec<_>>(),
107            vec![
108                Component::Normal("a"),
109                Component::Current,
110                Component::Parent,
111                Component::Normal("b"),
112                Component::Normal("c")
113            ]
114        );
115    }
116}