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#[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#[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#[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 pub fn components(&self) -> Components<'_> {
167 Components {
168 path: &self.inner,
169 at_start: true,
170 }
171 }
172
173 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 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 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 pub fn is_absolute(&self) -> bool {
203 self.inner.starts_with('/')
204 }
205
206 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#[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}