cap_primitives/fs/manually/
canonical_path.rs

1use std::ffi::OsStr;
2use std::path::{Component, PathBuf};
3
4/// Utility for collecting the canonical path components.
5pub(super) struct CanonicalPath<'path_buf> {
6    /// If the user requested a canonical path, a reference to the `PathBuf` to
7    /// write it to.
8    path: Option<&'path_buf mut PathBuf>,
9
10    /// Our own private copy of the canonical path, for assertion checking.
11    #[cfg(racy_asserts)]
12    pub(super) debug: PathBuf,
13}
14
15impl<'path_buf> CanonicalPath<'path_buf> {
16    pub(super) fn new(path: Option<&'path_buf mut PathBuf>) -> Self {
17        Self {
18            #[cfg(racy_asserts)]
19            debug: PathBuf::new(),
20
21            path,
22        }
23    }
24
25    pub(super) fn push(&mut self, one: &OsStr) {
26        #[cfg(racy_asserts)]
27        self.debug.push(one);
28
29        if let Some(path) = &mut self.path {
30            path.push(one)
31        }
32    }
33
34    pub(super) fn pop(&mut self) -> bool {
35        #[cfg(racy_asserts)]
36        self.debug.pop();
37
38        if let Some(path) = &mut self.path {
39            path.pop()
40        } else {
41            true
42        }
43    }
44
45    /// The complete canonical path has been scanned. Set `path` to `None`
46    /// so that it isn't cleared when `self` is dropped.
47    pub(super) fn complete(&mut self) {
48        // Replace "" with ".", since "" as a relative path is interpreted as
49        // an error.
50        if let Some(path) = &mut self.path {
51            if path.as_os_str().is_empty() {
52                path.push(Component::CurDir);
53            }
54            self.path = None;
55        }
56    }
57}
58
59impl<'path_buf> Drop for CanonicalPath<'path_buf> {
60    fn drop(&mut self) {
61        // If `self.path` is still `Some` here, it means that we haven't called
62        // `complete()` yet, meaning the `CanonicalPath` is being dropped
63        // before the complete path has been processed. In that case, clear
64        // `path` to indicate that we weren't able to obtain a complete path.
65        if let Some(path) = &mut self.path {
66            path.clear();
67            self.path = None;
68        }
69    }
70}