1use alloc::borrow::{Cow, ToOwned};
2use alloc::boxed::Box;
3use crate::ffi::{OsStr, OsString};
4use crate::fs::*;
5use alloc::collections::TryReserveError;
6use alloc::rc::Rc;
7use alloc::string::String;
8use alloc::sync::Arc;
9use alloc::vec;
10use alloc::vec::Vec;
11use core::borrow::Borrow;
12use core::fmt::{Debug, Display, Formatter};
13use core::ops::Deref;
14use crate::env::current_dir;
15
16#[must_use]
17pub fn is_separator(c: char) -> bool {
18 c == MAIN_SEPARATOR || c == '/'
19}
20
21pub const MAIN_SEPARATOR: char = '\\';
22pub const MAIN_SEPARATOR_STR: &str = "\\";
23
24pub(crate) const MAX_PATH: usize = windows_sys::Win32::Foundation::MAX_PATH as usize;
26
27pub(crate) const MAX_PATH_EXTENDED: usize = 32767 as usize;
29
30#[derive(Clone, PartialEq, Ord, PartialOrd, Eq)]
31#[repr(transparent)]
32pub struct PathBuf {
33 data: OsString
34}
35
36impl Debug for PathBuf {
37 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
38 Debug::fmt(&self.data, f)
39 }
40}
41
42impl Debug for Path {
43 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
44 Debug::fmt(&self.inner, f)
45 }
46}
47
48impl PathBuf {
49 pub fn new() -> PathBuf {
50 Self { data: OsString::new() }
51 }
52 pub fn with_capacity(capacity: usize) -> PathBuf {
53 Self { data: OsString::with_capacity(capacity) }
54 }
55 pub fn as_path(&self) -> &Path {
56 self
57 }
58 pub fn push<S: AsRef<Path>>(&mut self, part: S) {
59 let part = part.as_ref();
60
61 if part.is_absolute() || part.has_drive_letter() {
62 self.data.clear();
63 self.data.push(part.as_os_str());
64 return
65 }
66
67 if !self.data.as_str().chars().next_back().is_some_and(is_separator) {
68 self.data.push(MAIN_SEPARATOR_STR);
69 }
70 self.data.push(part.as_os_str());
71 }
72 pub fn pop(&mut self) -> bool {
73 match self.parent() {
74 Some(s) => {
75 self.data.truncate(s.as_os_str().len());
76 true
77 }
78 None => false
79 }
80 }
81 pub fn set_file_name<S: AsRef<OsStr>>(&mut self, file_name: S) {
82 self.truncate_extraneous_suffixes();
83
84 if self.file_name().is_some() {
85 self.pop();
86 }
87 self.push(file_name.as_ref());
88 }
89 pub fn set_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool {
90 if !self.file_name().is_some() {
91 return false
92 }
93
94 self.truncate_extraneous_suffixes();
95
96 match self.extension() {
97 Some(e) => self.data.truncate(self.data.len() - e.len()),
98 None => self.data.push(".")
99 }
100 self.data.push(extension);
101
102 true
103 }
104 fn truncate_extraneous_suffixes(&mut self) {
105 self.data.truncate(self.remove_extraneous_suffixes().path_len())
106 }
107 pub fn as_mut_os_string(&mut self) -> &mut OsString {
108 &mut self.data
109 }
110 pub fn into_os_string(self) -> OsString {
111 self.data
112 }
113 pub fn into_boxed_path(self) -> Box<Path> {
114 let s = Box::into_raw(self.data.into_boxed_os_str());
115 unsafe { Box::from_raw(s as *mut Path) }
116 }
117 pub fn capacity(&self) -> usize {
118 self.data.capacity()
119 }
120 pub fn clear(&mut self) {
121 self.data.clear()
122 }
123 pub fn reserve(&mut self, additional: usize) {
124 self.data.reserve(additional)
125 }
126 pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
127 self.data.try_reserve(additional)
128 }
129 pub fn reserve_exact(&mut self, additional: usize) {
130 self.data.reserve_exact(additional)
131 }
132 pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
133 self.data.try_reserve_exact(additional)
134 }
135 pub fn shrink_to_fit(&mut self) {
136 self.data.shrink_to_fit()
137 }
138 pub fn shrink_to(&mut self, amount: usize) {
139 self.data.shrink_to(amount)
140 }
141 pub(crate) fn from_string(mut string: String) -> Self {
142 if string.starts_with(r#"\\?\"#) {
144 string.remove(0);
145 string.remove(0);
146 string.remove(0);
147 string.remove(0);
148 }
149 Self { data: string.into() }
150 }
151}
152
153#[derive(PartialEq, Eq, PartialOrd, Ord)]
154#[repr(transparent)]
155pub struct Path {
156 inner: OsStr
157}
158
159impl Path {
160 pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &Path {
161 let mut s = s.as_ref().as_str();
162 if s.starts_with(r#"\\?\"#) {
163 s = &s[4..];
164 }
165 Self::from_os_str(s.as_ref())
166 }
167
168 pub fn as_os_str(&self) -> &OsStr {
169 &self.inner
170 }
171
172 pub fn as_mut_os_str(&mut self) -> &mut OsStr {
173 &mut self.inner
174 }
175
176 pub fn to_str(&self) -> Option<&str> {
177 self.inner.to_str()
178 }
179
180 pub fn to_string_lossy(&self) -> Cow<'_, str> {
181 self.inner.to_string_lossy()
182 }
183
184 pub fn to_path_buf(&self) -> PathBuf {
185 PathBuf { data: self.inner.to_os_string() }
186 }
187
188 pub fn is_absolute(&self) -> bool {
189 if self.has_drive_letter() && self.as_os_str().as_str().chars().skip(2).next().is_some_and(is_separator) {
190 return true
191 }
192
193 let mut p = self.iter();
194
195 let Some(first) = p.next() else { return false };
197 let first = first.as_str();
198
199 if !first.is_empty() {
201 return false
202 }
203
204 let Some(next) = p.next() else { return false };
206 if !next.is_empty() {
207 return false
208 }
209
210 let Some(next) = p.next() else { return false };
212 if next.is_empty() {
213 return false
214 }
215
216 p.next().is_some()
218 }
219
220 fn has_drive_letter(&self) -> bool {
221 let mut p = self.iter();
222
223 let Some(first) = p.next() else { return false };
224 let first = first.as_str();
225 let mut chars = first.chars();
226
227 let [Some(drive_letter), Some(':')] = [chars.next(), chars.next()] else {
229 return false
230 };
231
232 if !drive_letter.is_ascii_alphabetic() {
233 return false
234 }
235
236 drive_letter.is_ascii_alphabetic()
237 }
238
239 pub fn is_relative(&self) -> bool {
240 !self.is_absolute()
241 }
242
243 pub fn has_root(&self) -> bool {
244 self.is_absolute() || self.as_os_str().as_str().chars().next().is_some_and(is_separator)
245 }
246
247 pub fn parent(&self) -> Option<&Path> {
248 let mut i = self.as_relative_to_root().components();
249 let current = i.next_back()?;
250
251 unsafe {
252 match i.next_back() {
253 Some(n) => Some(self.trim_to_end_of(n.as_ref())),
254 None => Some(self.trim_to_start_of(current.as_ref()))
255 }
256 }
257 }
258
259 pub fn ancestors(&self) -> Ancestors {
260 Ancestors { path: self }
261 }
262
263 pub fn file_name(&self) -> Option<&OsStr> {
264 let final_component = self.as_relative_to_root().components().next_back()?;
265 (final_component.as_str() != "..").then_some(final_component)
266 }
267
268 pub fn strip_prefix<P: AsRef<Path>>(&self, base: P) -> Result<&Path, StripPrefixError> {
269 let mut a = self.components();
270 let mut b = base.as_ref().components();
271
272 loop {
273 let Some(n) = a.next() else { return Err(StripPrefixError {}) };
274 let Some(m) = b.next() else { return Ok(unsafe { self.rtrim_to_start_of(n.as_ref()) }) };
276 if n != m {
277 return Err(StripPrefixError {})
278 }
279 }
280 }
281
282 pub fn starts_with<P: AsRef<Path>>(&self, base: P) -> bool {
283 let mut a = self.components();
284 let mut b = base.as_ref().components();
285
286 loop {
287 let Some(n) = a.next() else { return b.next().is_none() };
288 let Some(m) = b.next() else { return true };
289 if n != m {
290 return false
291 }
292 }
293 }
294
295 pub fn ends_with<P: AsRef<Path>>(&self, child: P) -> bool {
296 let mut a = self.components();
297 let mut b = child.as_ref().components();
298
299 loop {
300 let Some(n) = a.next_back() else { return b.next_back().is_none() };
301 let Some(m) = b.next_back() else { return true };
302 if n != m {
303 return false
304 }
305 }
306 }
307
308 pub fn file_stem(&self) -> Option<&OsStr> {
309 self.split_file_stem_extension().map(|i| i.0)
310 }
311
312 pub fn extension(&self) -> Option<&OsStr> {
313 self.split_file_stem_extension().map(|i| i.1).flatten()
314 }
315
316 fn split_file_stem_extension(&self) -> Option<(&OsStr, Option<&OsStr>)> {
317 let file_name = self.file_name()?.as_str();
318 let Some(dot) = file_name.rfind(".") else { return Some((file_name.as_ref(), None)) };
319 let (stem, extension) = file_name.split_at(dot);
320
321 if stem.is_empty() {
322 Some((file_name.as_ref(), None))
323 }
324 else {
325 let extension = &extension[1..]; Some((stem.as_ref(), Some(extension.as_ref())))
327 }
328 }
329
330 pub fn join<P: AsRef<Path>>(&self, path: P) -> PathBuf {
331 let mut new_path = self.to_owned();
332 new_path.push(path);
333 new_path
334 }
335
336 pub fn with_file_name<S: AsRef<OsStr>>(&self, file_name: S) -> PathBuf {
337 let mut p = self.to_owned();
338 p.set_file_name(file_name);
339 p
340 }
341
342 pub fn with_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {
343 let mut p = self.to_owned();
344 p.set_extension(extension);
345 p
346 }
347
348 pub fn components(&self) -> Components {
349 Components { iter: self.iter() }
350 }
351
352 pub fn iter(&self) -> Iter {
353 let string = self.inner.as_str();
354 Iter {
355 iter: string.split(is_separator),
356 original_string: string,
357 iterated_amount: 0
358 }
359 }
360
361 pub fn display(&self) -> impl Display {
362 self.inner.as_str()
363 }
364
365 pub fn metadata(&self) -> crate::io::Result<Metadata> {
366 metadata(self)
367 }
368
369 pub fn symlink_metadata(&self) -> crate::io::Result<Metadata> {
370 symlink_metadata(self)
371 }
372
373 pub fn canonicalize(&self) -> crate::io::Result<PathBuf> {
374 canonicalize(self)
375 }
376
377 pub fn read_dir(&self) -> crate::io::Result<ReadDir> {
382 read_dir(self)
383 }
384
385 pub fn exists(&self) -> bool {
386 exists_infallible(self)
387 }
388
389 pub fn try_exists(&self) -> crate::io::Result<bool> {
390 exists(self)
391 }
392
393 pub fn is_file(&self) -> bool {
394 self.metadata().is_ok_and(|m| m.is_file())
395 }
396
397 pub fn is_dir(&self) -> bool {
398 self.metadata().is_ok_and(|m| m.is_dir())
399 }
400
401 pub fn is_symlink(&self) -> bool {
402 self.symlink_metadata().is_ok()
403 }
404
405 pub fn into_path_buf(self: Box<Path>) -> PathBuf {
406 let b = Box::into_raw(self);
407 unsafe { PathBuf { data: Box::from_raw(b as *mut OsStr).into_os_string() } }
408 }
409
410 fn from_os_str(os_str: &OsStr) -> &Path {
411 unsafe { &*(os_str as *const OsStr as *const Path) }
413 }
414
415 fn remove_extraneous_suffixes(&self) -> &Path {
416 let without_root = self.as_relative_to_root();
417 let mut i = without_root.components();
418
419 loop {
420 let Some(a) = i.next_back() else {
421 return unsafe { self.trim_to_end_of(without_root.as_os_str().as_str()[0..].as_ref()) };
423 };
424
425 return unsafe { self.trim_to_end_of(a.as_ref()) };
427 }
428 }
429
430 fn as_relative_to_root(&self) -> &Path {
431 let as_str = self.inner.as_str();
432 let mut as_str_chars = as_str.chars();
433
434 let Some(first_char) = as_str_chars.next() else {
435 return self
437 };
438
439 if is_separator(first_char) {
440 if self.is_absolute() {
441 let a = &as_str[2..];
442 let (index, _) = a.char_indices().find(|i| is_separator(i.1)).unwrap();
443 a[index + 1..].as_ref()
444 }
445 else {
446 AsRef::<Path>::as_ref(&as_str[1..]).as_relative_to_root()
447 }
448 }
449
450 else if self.has_drive_letter() {
451 if self.is_absolute() {
452 as_str[3..].as_ref()
454 }
455 else {
456 as_str[2..].as_ref()
458 }
459 }
460
461 else if self.is_relative() {
462 self
463 }
464
465 else {
466 unreachable!()
467 }
468 }
469
470 unsafe fn trim_to_end_of(&self, path: &Path) -> &Path {
472 let end = path.as_os_str().as_encoded_bytes().as_ptr_range().end;
473 let start = self.as_os_str().as_encoded_bytes().as_ptr_range().start;
474 let actual_length = (end as usize) - (start as usize);
475
476 unsafe { core::str::from_utf8_unchecked(core::slice::from_raw_parts(start, actual_length)).as_ref() }
478 }
479
480 unsafe fn trim_to_start_of(&self, path: &Path) -> &Path {
481 let end = path.as_os_str().as_encoded_bytes().as_ptr_range().start;
482 let start = self.as_os_str().as_encoded_bytes().as_ptr_range().start;
483 let actual_length = (end as usize) - (start as usize);
484
485 unsafe { core::str::from_utf8_unchecked(core::slice::from_raw_parts(start, actual_length)).as_ref() }
487 }
488
489 unsafe fn rtrim_to_start_of(&self, path: &Path) -> &Path {
490 let start = path.as_os_str().as_encoded_bytes().as_ptr_range().start;
491 let end = self.as_os_str().as_encoded_bytes().as_ptr_range().end;
492 let actual_length = (end as usize) - (start as usize);
493
494 unsafe { core::str::from_utf8_unchecked(core::slice::from_raw_parts(start, actual_length)).as_ref() }
496 }
497
498 pub(crate) fn encode_for_win32(&self) -> Vec<u16> {
499 match self.as_os_str().as_str() {
501 "." => return current_dir().unwrap().encode_for_win32(),
502 ".." => return current_dir().unwrap().parent().and_then(|p| Some(p.encode_for_win32())).unwrap_or_else(|| vec!['.' as u16, '.' as u16, 0]),
503 _ => ()
504 }
505
506 let s = self.inner.as_str();
507 let mut c = Vec::with_capacity(self.inner.len() * 2 + 1);
508
509 for i in self.components() {
510 if !c.is_empty() {
511 c.extend_from_slice(MAIN_SEPARATOR.encode_utf16(&mut [0,0]));
512 }
513 c.extend(i.as_str().encode_utf16());
514 }
515 c.push(0);
516 c.shrink_to_fit();
517 c
518 }
519
520 pub(crate) fn path_len(&self) -> usize {
521 self.as_os_str().as_str().len()
522 }
523}
524
525impl From<String> for PathBuf {
526 fn from(value: String) -> Self {
527 PathBuf::from_string(value)
528 }
529}
530
531impl Deref for PathBuf {
532 type Target = Path;
533 fn deref(&self) -> &Self::Target {
534 Path::from_os_str(&self.data)
535 }
536}
537
538impl Borrow<Path> for PathBuf {
539 fn borrow(&self) -> &Path {
540 Path::from_os_str(&self.data)
541 }
542}
543
544impl ToOwned for Path {
545 type Owned = PathBuf;
546 fn to_owned(&self) -> Self::Owned {
547 PathBuf { data: self.inner.to_os_string() }
548 }
549}
550
551impl AsRef<Path> for Path {
552 fn as_ref(&self) -> &Path {
553 self
554 }
555}
556
557impl AsRef<Path> for OsStr {
558 fn as_ref(&self) -> &Path {
559 Path::from_os_str(self)
560 }
561}
562
563impl AsRef<Path> for OsString {
564 fn as_ref(&self) -> &Path {
565 Path::from_os_str(self)
566 }
567}
568
569impl AsRef<Path> for PathBuf {
570 fn as_ref(&self) -> &Path {
571 self.as_path()
572 }
573}
574
575impl AsRef<Path> for String {
576 fn as_ref(&self) -> &Path {
577 Path::from_os_str(self.as_ref())
578 }
579}
580
581impl AsRef<Path> for str {
582 fn as_ref(&self) -> &Path {
583 Path::from_os_str(self.as_ref())
584 }
585}
586
587#[derive(Clone, Debug)]
588pub struct StripPrefixError {
589
590}
591
592pub struct Iter<'a> {
593 iterated_amount: usize,
594 original_string: &'a str,
595 iter: core::str::Split<'a, fn(char) -> bool>
596}
597
598impl<'a> Iter<'a> {
599 pub fn as_path(&self) -> &Path {
600 self.original_string[self.iterated_amount..].as_ref()
601 }
602}
603
604impl<'a> Iterator for Iter<'a> {
605 type Item = &'a OsStr;
606 fn next(&mut self) -> Option<Self::Item> {
607 let string = self.iter.next().map(OsStr::from_str)?;
608 self.iterated_amount += string.len() + 1;
609 Some(string)
610 }
611}
612
613impl<'a> DoubleEndedIterator for Iter<'a> {
614 fn next_back(&mut self) -> Option<Self::Item> {
615 self.iter.next_back().map(OsStr::from_str)
616 }
617}
618
619impl<'a> IntoIterator for &'a Path {
620 type Item = &'a OsStr;
621 type IntoIter = Iter<'a>;
622 fn into_iter(self) -> Self::IntoIter {
623 self.iter()
624 }
625}
626
627impl<'a> IntoIterator for &'a PathBuf {
628 type Item = &'a OsStr;
629 type IntoIter = Iter<'a>;
630 fn into_iter(self) -> Self::IntoIter {
631 self.iter()
632 }
633}
634
635pub struct Components<'a> {
636 iter: Iter<'a>
637}
638
639impl<'a> Iterator for Components<'a> {
640 type Item = &'a OsStr;
641 fn next(&mut self) -> Option<Self::Item> {
642 loop {
643 let i = self.iter.next()?;
644 if i.as_str() == "" || i.as_str() == "." {
645 continue
646 }
647 return Some(i)
648 }
649 }
650}
651
652impl<'a> DoubleEndedIterator for Components<'a> {
653 fn next_back(&mut self) -> Option<Self::Item> {
654 loop {
655 let i = self.iter.next_back()?;
656 if i.as_str() == "" || i.as_str() == "." {
657 continue
658 }
659 return Some(i)
660 }
661 }
662}
663
664pub struct Ancestors<'a> {
665 path: &'a Path
666}
667
668impl<'a> Iterator for Ancestors<'a> {
669 type Item = &'a Path;
670 fn next(&mut self) -> Option<Self::Item> {
671 self.path = self.path.parent()?;
672 Some(self.path)
673 }
674}
675
676impl From<&Path> for Arc<Path> {
677 fn from(value: &Path) -> Self {
678 value.to_path_buf().into_boxed_path().into()
679 }
680}
681
682impl From<&Path> for Box<Path> {
683 fn from(value: &Path) -> Self {
684 value.to_path_buf().into_boxed_path()
685 }
686}
687
688impl From<&Path> for Rc<Path> {
689 fn from(value: &Path) -> Self {
690 value.to_path_buf().into_boxed_path().into()
691 }
692}
693
694impl<'a> From<&'a Path> for Cow<'a, Path> {
695 fn from(value: &'a Path) -> Self {
696 Cow::Borrowed(value)
697 }
698}
699
700impl From<&mut Path> for Arc<Path> {
701 fn from(value: &mut Path) -> Self {
702 Arc::from(&*value)
703 }
704}
705
706impl From<&mut Path> for Box<Path> {
707 fn from(value: &mut Path) -> Self {
708 Box::from(&*value)
709 }
710}
711
712impl From<&mut Path> for Rc<Path> {
713 fn from(value: &mut Path) -> Self {
714 Rc::from(&*value)
715 }
716}
717
718impl AsRef<OsStr> for Path {
719 fn as_ref(&self) -> &OsStr {
720 self.as_os_str()
721 }
722}
723
724impl From<Cow<'_, Path>> for Box<Path> {
725 fn from(value: Cow<'_, Path>) -> Self {
726 match value {
727 Cow::Borrowed(p) => p.to_path_buf().into_boxed_path(),
728 Cow::Owned(p) => p.into_boxed_path()
729 }
730 }
731}
732
733impl Clone for Box<Path> {
734 fn clone(&self) -> Self {
735 self.to_path_buf().into_boxed_path()
736 }
737}
738
739impl AsRef<Path> for Components<'_> {
740 fn as_ref(&self) -> &Path {
741 self.iter.as_path()
742 }
743}
744
745impl From<PathBuf> for Box<Path> {
746 fn from(value: PathBuf) -> Self {
747 value.into_boxed_path()
748 }
749}
750
751#[cfg(test)]
752mod test;