Skip to main content

dots/
stdx.rs

1//! Extensions to the standard library
2
3use eyre::{Context as _, Result, eyre};
4use simply_colored::*;
5use std::{
6    iter,
7    path::{Path, PathBuf},
8};
9
10/// Extension trait for [`Path`]
11#[easy_ext::ext(PathExt)]
12pub impl<T: AsRef<Path>> T {
13    /// Show the colored path
14    #[allow(clippy::disallowed_methods, reason = "definition of `show_path`")]
15    fn show(&self) -> String {
16        format!("{CYAN}{}{RESET}", self.as_ref().display())
17    }
18
19    /// Like [`Path::strip_prefix`], but includes an informative error message
20    fn strip_prefix(&self, prefix: impl AsRef<Path>) -> Result<&Path> {
21        self.as_ref().strip_prefix(&prefix).with_context(|| {
22            eyre!(
23                "failed to strip prefix {} from {}",
24                prefix.show(),
25                self.show()
26            )
27        })
28    }
29}
30
31/// Traverses all directories upwards from the `base_dir`
32///
33/// For example, if `base_dir` is `/home/user/project/name/`, then the iterator yields:
34/// - `/home/user/project/name/`
35/// - `/home/user/project/`
36/// - `/home/user/`
37/// - `/home/`
38/// - `/`
39pub fn traverse_upwards(base_dir: impl AsRef<Path>) -> impl Iterator<Item = PathBuf> {
40    let mut current_dir = Some(base_dir.as_ref().to_path_buf());
41    iter::once(base_dir.as_ref().to_path_buf()).chain(iter::from_fn(move || {
42        if let Some(d) = &current_dir {
43            current_dir = d.parent().map(Path::to_path_buf);
44            current_dir.clone()
45        } else {
46            None
47        }
48    }))
49}
50
51#[cfg(test)]
52mod tests {
53    use itertools::Itertools as _;
54
55    use super::*;
56
57    #[test]
58    fn traverse_upwards() {
59        let path = PathBuf::from("/home/user/project/name/");
60
61        assert_eq!(
62            super::traverse_upwards(path).collect_vec(),
63            vec![
64                PathBuf::from("/home/user/project/name/"),
65                PathBuf::from("/home/user/project/"),
66                PathBuf::from("/home/user/"),
67                PathBuf::from("/home/"),
68                PathBuf::from("/"),
69            ]
70        );
71    }
72}