1use crate::cid::Cid;
3
4#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
6pub struct Path(Vec<String>);
7
8impl Path {
9 pub fn iter(&self) -> impl Iterator<Item = &str> {
11 self.0.iter().map(|s| &**s)
12 }
13
14 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#[derive(Clone, Debug, PartialEq, Eq, Hash)]
62pub struct DagPath<'a>(&'a Cid, Path);
63
64impl<'a> DagPath<'a> {
65 pub fn new<T: Into<Path>>(cid: &'a Cid, path: T) -> Self {
67 Self(cid, path.into())
68 }
69
70 pub fn root(&self) -> &Cid {
72 self.0
73 }
74
75 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}