lurk_ipld/
path.rs

1//! Path
2use crate::cid::Cid;
3
4/// Represents a path in an ipld dag.
5#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
6pub struct Path(Vec<String>);
7
8impl Path {
9    /// Iterate over path segments.
10    pub fn iter(&self) -> impl Iterator<Item = &str> {
11        self.0.iter().map(|s| &**s)
12    }
13
14    /// Join segment.
15    pub fn join<T: AsRef<str>>(&mut self, segment: T) {
16        for seg in segment.as_ref().split('/').filter(|s| !s.is_empty()) {
17            self.0.push(seg.to_owned())
18        }
19    }
20}
21
22impl From<Vec<String>> for Path {
23    fn from(segments: Vec<String>) -> Self {
24        Path(segments)
25    }
26}
27
28impl From<Vec<&str>> for Path {
29    fn from(segments: Vec<&str>) -> Self {
30        Path(segments.into_iter().map(String::from).collect())
31    }
32}
33
34impl From<&str> for Path {
35    fn from(s: &str) -> Self {
36        let mut path = Path::default();
37        path.join(s);
38        path
39    }
40}
41
42impl From<String> for Path {
43    fn from(s: String) -> Self {
44        Path::from(s.as_str())
45    }
46}
47
48impl ToString for Path {
49    fn to_string(&self) -> String {
50        let mut path = "".to_string();
51        for seg in &self.0 {
52            path.push_str(seg.as_str());
53            path.push('/');
54        }
55        path.pop();
56        path
57    }
58}
59
60/// Path in a dag.
61#[derive(Clone, Debug, PartialEq, Eq, Hash)]
62pub struct DagPath<'a>(&'a Cid, Path);
63
64impl<'a> DagPath<'a> {
65    /// Create a new dag path.
66    pub fn new<T: Into<Path>>(cid: &'a Cid, path: T) -> Self {
67        Self(cid, path.into())
68    }
69
70    /// Returns the root of the path.
71    pub fn root(&self) -> &Cid {
72        self.0
73    }
74
75    /// Returns the ipld path.
76    pub fn path(&self) -> &Path {
77        &self.1
78    }
79}
80
81impl<'a> From<&'a Cid> for DagPath<'a> {
82    fn from(cid: &'a Cid) -> Self {
83        Self(cid, Default::default())
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90
91    #[test]
92    fn test_parsing_one_segment() {
93        assert_eq!(Path::from("0"), Path::from(vec!["0"]));
94    }
95
96    #[test]
97    fn test_parsing_three_segments() {
98        assert_eq!(Path::from("0/foo/2"), Path::from(vec!["0", "foo", "2"]));
99    }
100
101    #[test]
102    fn test_eliding_empty_segments() {
103        assert_eq!(Path::from("0//2"), Path::from(vec!["0", "2"]));
104    }
105
106    #[test]
107    fn test_eliding_leading_slashes() {
108        assert_eq!(Path::from("/0/2"), Path::from(vec!["0", "2"]));
109    }
110
111    #[test]
112    fn test_eliding_trailing_slashes() {
113        assert_eq!(Path::from("0/2/"), Path::from(vec!["0", "2"]));
114    }
115
116    #[test]
117    fn test_to_string() {
118        assert_eq!(Path::from(vec!["0", "foo", "2"]).to_string(), "0/foo/2");
119    }
120}