tiedcrossing_type/tree/
path.rs1use super::Name;
5
6use std::fmt::Display;
7use std::ops::Deref;
8use std::str::FromStr;
9
10use serde::{Deserialize, Serialize};
11
12#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
13pub struct Path(Vec<Name>);
14
15impl Deref for Path {
16 type Target = Vec<Name>;
17
18 fn deref(&self) -> &Self::Target {
19 &self.0
20 }
21}
22
23impl Path {
24 pub const ROOT: Self = Self(vec![]);
25
26 pub fn intersperse(&self, sep: &str) -> String {
27 let mut it = self.0.iter();
28 match it.next() {
29 None => Default::default(),
30 Some(first) => {
31 let mut s = String::with_capacity(
32 self.0.iter().map(|p| p.len()).sum::<usize>() + self.0.len() - 1,
33 );
34 s.push_str(first);
35 for p in it {
36 s.push_str(sep);
37 s.push_str(p);
38 }
39 s
40 }
41 }
42 }
43}
44
45impl From<Name> for Path {
46 fn from(name: Name) -> Self {
47 Self(vec![name])
48 }
49}
50
51impl FromIterator<Name> for Path {
52 fn from_iter<T: IntoIterator<Item = Name>>(iter: T) -> Self {
53 Self(Vec::<Name>::from_iter(iter))
54 }
55}
56
57impl FromStr for Path {
58 type Err = anyhow::Error;
59
60 fn from_str(s: &str) -> Result<Self, Self::Err> {
61 s.trim_start_matches('/')
62 .split_terminator('/')
63 .map(FromStr::from_str)
64 .collect::<Result<Vec<_>, Self::Err>>()
65 .map(Self)
66 }
67}
68
69impl Display for Path {
70 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71 write!(f, "{}", self.intersperse("/"))
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78
79 #[test]
80 fn from_str() {
81 assert_eq!("/".parse::<Path>().unwrap(), Path::ROOT);
82 assert_eq!(
83 "/foo".parse::<Path>().unwrap(),
84 Path(vec!["foo".parse().unwrap()])
85 );
86 assert_eq!(
87 "/foo/".parse::<Path>().unwrap(),
88 Path(vec!["foo".parse().unwrap()])
89 );
90 assert_eq!(
91 "/foo/bar".parse::<Path>().unwrap(),
92 Path(vec!["foo".parse().unwrap(), "bar".parse().unwrap()])
93 );
94 }
95}