axfs_ng_vfs/
path.rs

1use alloc::{borrow::ToOwned, string::String, sync::Arc};
2use core::{borrow::Borrow, fmt, ops::Deref};
3
4use crate::{VfsError, VfsResult};
5
6pub const DOT: &str = ".";
7pub const DOTDOT: &str = "..";
8
9pub const MAX_NAME_LEN: usize = 255;
10
11pub(crate) fn verify_entry_name(name: &str) -> VfsResult<()> {
12    if name == DOT || name == DOTDOT {
13        return Err(VfsError::InvalidInput);
14    }
15    if name.len() > MAX_NAME_LEN {
16        return Err(VfsError::NameTooLong);
17    }
18    Ok(())
19}
20
21/// A single component of a [`Path`].
22///
23/// This corresponds to [`std::path::Component`].
24#[derive(Debug, PartialEq, Eq, Hash)]
25pub enum Component<'a> {
26    RootDir,
27    CurDir,
28    ParentDir,
29    Normal(&'a str),
30}
31
32impl<'a> Component<'a> {
33    pub fn as_str(&self) -> &'a str {
34        match self {
35            Component::RootDir => "/",
36            Component::CurDir => ".",
37            Component::ParentDir => "..",
38            Component::Normal(s) => s,
39        }
40    }
41}
42
43/// An iterator over the [`Component`]s of a [`Path`].
44///
45/// This corresponds to [`std::path::Components`].
46#[doc(hidden)]
47pub struct Components<'a> {
48    path: &'a str,
49    at_start: bool,
50}
51
52impl<'a> Components<'a> {
53    pub fn as_path(&self) -> &'a Path {
54        Path::new(self.path)
55    }
56
57    fn parse_forward(&mut self, comp: &'a str) -> Option<Component<'a>> {
58        let comp = match comp {
59            "" => {
60                if self.at_start {
61                    Some(Component::RootDir)
62                } else {
63                    None
64                }
65            }
66            "." => {
67                if self.at_start {
68                    Some(Component::CurDir)
69                } else {
70                    None
71                }
72            }
73            ".." => Some(Component::ParentDir),
74            _ => Some(Component::Normal(comp)),
75        };
76        self.at_start = false;
77        comp
78    }
79
80    fn parse_backward(&mut self, comp: &'a str, no_rest: bool) -> Option<Component<'a>> {
81        match comp {
82            "" => {
83                if self.at_start && no_rest {
84                    Some(Component::RootDir)
85                } else {
86                    None
87                }
88            }
89            "." => {
90                if self.at_start && no_rest {
91                    Some(Component::CurDir)
92                } else {
93                    None
94                }
95            }
96            ".." => Some(Component::ParentDir),
97            _ => Some(Component::Normal(comp)),
98        }
99    }
100}
101
102impl<'a> Iterator for Components<'a> {
103    type Item = Component<'a>;
104
105    fn next(&mut self) -> Option<Self::Item> {
106        loop {
107            if self.path.is_empty() {
108                return None;
109            }
110            let (comp, rest) = match self.path.find('/') {
111                Some(index) => (&self.path[..index], &self.path[index + 1..]),
112                None => (self.path, ""),
113            };
114            self.path = rest;
115            if let Some(comp) = self.parse_forward(comp) {
116                return Some(comp);
117            }
118        }
119    }
120}
121
122impl<'a> DoubleEndedIterator for Components<'a> {
123    fn next_back(&mut self) -> Option<Self::Item> {
124        loop {
125            if self.path.is_empty() {
126                return None;
127            }
128            let (comp, rest) = match self.path.rfind('/') {
129                Some(index) => (
130                    &self.path[index + 1..],
131                    &self.path[..(index + 1).min(self.path.len() - 1)],
132                ),
133                None => (self.path, ""),
134            };
135            self.path = rest;
136            if let Some(comp) = self.parse_backward(comp, rest.is_empty()) {
137                return Some(comp);
138            }
139        }
140    }
141}
142
143/// A slice of path (akin to [`str`]).
144///
145/// Different from [`std::path::Path`], this type is always
146/// UTF-8 encoded.
147#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
148pub struct Path {
149    inner: str,
150}
151
152impl Path {
153    pub fn new<S: AsRef<str> + ?Sized>(s: &S) -> &Path {
154        unsafe { &*(s.as_ref() as *const str as *const Path) }
155    }
156
157    pub fn as_str(&self) -> &str {
158        &self.inner
159    }
160
161    pub fn as_bytes(&self) -> &[u8] {
162        self.inner.as_bytes()
163    }
164
165    /// Produces an iterator over the [`Components`] of the path.
166    pub fn components(&self) -> Components<'_> {
167        Components {
168            path: &self.inner,
169            at_start: true,
170        }
171    }
172
173    /// Returns the final component of the `Path`, if there is one.
174    pub fn file_name(&self) -> Option<&str> {
175        self.components().next_back().and_then(|p| match p {
176            Component::Normal(p) => Some(p),
177            _ => None,
178        })
179    }
180
181    /// Creates an owned [`PathBuf`] with path adjoined to `self`.
182    pub fn join(&self, other: impl AsRef<Path>) -> PathBuf {
183        let mut path = self.to_owned();
184        path.push(other);
185        path
186    }
187
188    /// Returns the `Path` without its final component, if there is one.
189    pub fn parent(&self) -> Option<&Path> {
190        let mut comps = self.components();
191        let comp = comps.next_back();
192        comp.and_then(move |p| match p {
193            Component::Normal(_) | Component::CurDir | Component::ParentDir => {
194                Some(comps.as_path())
195            }
196            _ => None,
197        })
198    }
199
200    /// Returns `true` if the `Path` is absolute, i.e., if it is independent of
201    /// the current directory.
202    pub fn is_absolute(&self) -> bool {
203        self.inner.starts_with('/')
204    }
205
206    /// Normalizes a path without performing I/O.
207    pub fn normalize(&self) -> Option<PathBuf> {
208        let mut ret = PathBuf::new();
209        for component in self.components() {
210            match component {
211                Component::RootDir => {
212                    ret.push("/");
213                }
214                Component::CurDir => {}
215                Component::ParentDir => {
216                    if !ret.pop() {
217                        return None;
218                    }
219                }
220                Component::Normal(c) => {
221                    ret.push(c);
222                }
223            }
224        }
225        Some(ret)
226    }
227}
228
229impl fmt::Display for Path {
230    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
231        self.inner.fmt(f)
232    }
233}
234
235impl<'a> From<&'a str> for &'a Path {
236    fn from(value: &'a str) -> Self {
237        Path::new(value)
238    }
239}
240
241impl ToOwned for Path {
242    type Owned = PathBuf;
243
244    fn to_owned(&self) -> Self::Owned {
245        PathBuf {
246            inner: self.inner.to_owned(),
247        }
248    }
249}
250
251impl From<&Path> for Arc<Path> {
252    #[inline]
253    fn from(v: &Path) -> Arc<Path> {
254        let arc = Arc::<str>::from(&v.inner);
255        unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Path) }
256    }
257}
258
259impl AsRef<str> for Path {
260    #[inline]
261    fn as_ref(&self) -> &str {
262        &self.inner[..]
263    }
264}
265
266impl AsRef<Path> for Path {
267    #[inline]
268    fn as_ref(&self) -> &Path {
269        self
270    }
271}
272
273macro_rules! impl_as_ref {
274    ($($t:ty),+) => {
275        $(impl AsRef<Path> for $t {
276            fn as_ref(&self) -> &Path {
277                Path::new(self)
278            }
279        })+
280    };
281}
282
283impl_as_ref!(str, String);
284
285/// An owned, mutable [`Path`] (akin to [`String`]).
286///
287/// Different from [`std::path::PathBuf`], this type is always
288/// UTF-8 encoded.
289#[derive(Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
290pub struct PathBuf {
291    inner: String,
292}
293
294impl PathBuf {
295    pub const fn new() -> Self {
296        Self {
297            inner: String::new(),
298        }
299    }
300
301    pub fn pop(&mut self) -> bool {
302        match self.parent().map(|p| p.as_str().len()) {
303            Some(len) => {
304                self.inner.truncate(len);
305                true
306            }
307            None => false,
308        }
309    }
310
311    pub fn push(&mut self, path: impl AsRef<Path>) {
312        self._push(path.as_ref());
313    }
314
315    fn _push(&mut self, path: &Path) {
316        if path.as_str().is_empty() {
317            return;
318        }
319        if path.is_absolute() {
320            self.inner.clear();
321        } else if !self.inner.ends_with('/') {
322            self.inner.push('/');
323        }
324        self.inner += path.as_str();
325    }
326}
327
328impl<T: AsRef<Path>> FromIterator<T> for PathBuf {
329    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
330        let mut path = PathBuf::new();
331        for item in iter {
332            path.push(item);
333        }
334        path
335    }
336}
337
338impl Borrow<Path> for PathBuf {
339    fn borrow(&self) -> &Path {
340        self
341    }
342}
343
344impl Deref for PathBuf {
345    type Target = Path;
346
347    #[inline]
348    fn deref(&self) -> &Path {
349        Path::new(&self.inner)
350    }
351}
352
353impl AsRef<str> for PathBuf {
354    #[inline]
355    fn as_ref(&self) -> &str {
356        &self.inner[..]
357    }
358}
359
360impl AsRef<Path> for PathBuf {
361    #[inline]
362    fn as_ref(&self) -> &Path {
363        self
364    }
365}
366
367impl From<String> for PathBuf {
368    fn from(value: String) -> Self {
369        Self { inner: value }
370    }
371}
372
373impl From<&str> for PathBuf {
374    fn from(value: &str) -> Self {
375        Self {
376            inner: value.to_owned(),
377        }
378    }
379}
380
381impl fmt::Display for PathBuf {
382    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
383        self.inner.fmt(f)
384    }
385}
386
387#[cfg(test)]
388mod test {
389    use alloc::vec::Vec;
390
391    use super::*;
392
393    #[test]
394    fn test_back_components() {
395        for path in ["../fds/", "./fs", "fs", "../", "..", ".", "./."] {
396            let path = Path::new(path);
397            let forward: Vec<_> = path.components().collect();
398            let mut backward: Vec<_> = path.components().rev().collect();
399            backward.reverse();
400            assert_eq!(forward, backward);
401        }
402    }
403
404    #[test]
405    fn test_file_name() {
406        assert_eq!(Some("c"), Path::new("../a/b/c").file_name());
407        assert_eq!(Some("b"), Path::new("a/b/.").file_name());
408        assert_eq!(None, Path::new("a/..").file_name());
409    }
410}