fs/
pathbuf.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
use alloc::{borrow::ToOwned, string::String, vec::Vec};
use core::fmt::Display;

#[derive(PartialEq, Eq, Clone)]
pub struct PathBuf(Vec<String>);

impl Display for PathBuf {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        f.write_fmt(format_args!("/{}", self.0.join("/")))
    }
}

impl From<PathBuf> for String {
    fn from(value: PathBuf) -> Self {
        value.path()
    }
}

impl From<String> for PathBuf {
    fn from(value: String) -> Self {
        Self::empty().join(&value)
    }
}

impl From<&str> for PathBuf {
    fn from(value: &str) -> Self {
        Self::empty().join(value)
    }
}

impl PathBuf {
    pub const fn empty() -> Self {
        Self(Vec::new())
    }

    pub fn join(&self, path: &str) -> Self {
        let mut pb = if path.starts_with("/") {
            PathBuf::empty()
        } else {
            self.clone()
        };
        path.split("/").for_each(|x| match x {
            "." | "" => {}
            ".." => {
                pb.0.pop();
            }
            name => pb.0.push(name.to_owned()),
        });

        pb
    }

    pub fn path(&self) -> String {
        String::from("/") + &self.0.join("/")
    }

    #[inline]
    pub fn filename(&self) -> String {
        self.0.last().cloned().unwrap_or(String::from("/"))
    }

    #[inline]
    pub fn dir(&self) -> PathBuf {
        let mut paths = self.clone();
        paths.0.pop();
        paths
    }

    #[inline]
    pub fn levels(&self) -> usize {
        self.0.len()
    }

    pub fn starts_with(&self, target: &PathBuf) -> bool {
        self.0.starts_with(&target.0)
    }

    pub fn trim_start(&self, target: &PathBuf) -> Self {
        let mut pb = self.clone();
        if pb.starts_with(target) {
            pb.0.drain(..target.0.len());
        }
        pb
    }

    #[inline]
    pub fn iter(&self) -> impl Iterator<Item = &String> {
        self.0.iter()
    }
}