uni_path/lib.rs
1//! Platform-independent path manipulation.
2//!
3//! This module provides two types, [`PathBuf`] and [`Path`] (akin to [`String`]
4//! and [`str`]), for working with paths abstractly. These types are thin wrappers
5//! around [`String`] and [`str`] respectively, meaning that they work directly
6//! on strings.
7//!
8//! Paths can be parsed into [`Component`]s by iterating over the structure
9//! returned by the [`components`] method on [`Path`]. [`Component`]s roughly
10//! correspond to the substrings between path separators (`/`). You can
11//! reconstruct an equivalent path from components with the [`push`] method on
12//! [`PathBuf`]; note that the paths may differ syntactically by the
13//! normalization described in the documentation for the [`components`] method.
14//!
15//! ## Simple usage
16//!
17//! Path manipulation includes both parsing components from slices and building
18//! new owned paths.
19//!
20//! To parse a path, you can create a [`Path`] slice from a [`str`]
21//! slice and start asking questions:
22//!
23//! ```
24//! use uni_path::Path;
25//!
26//! let path = Path::new("/tmp/foo/bar.txt");
27//!
28//! let parent = path.parent();
29//! assert_eq!(parent, Some(Path::new("/tmp/foo")));
30//!
31//! let file_stem = path.file_stem();
32//! assert_eq!(file_stem, Some("bar"));
33//!
34//! let extension = path.extension();
35//! assert_eq!(extension, Some("txt"));
36//! ```
37//!
38//! To build or modify paths, use [`PathBuf`]:
39//!
40//! ```
41//! use uni_path::PathBuf;
42//!
43//! // This way works...
44//! let mut path = PathBuf::from("/");
45//!
46//! path.push("lib");
47//! path.push("libc");
48//!
49//! path.set_extension("so");
50//!
51//! // ... but push is best used if you don't know everything up
52//! // front. If you do, this way is better:
53//! let path: PathBuf = ["/", "lib", "libc.so"].iter().collect();
54//! ```
55//!
56//! [`components`]: Path::components
57//! [`push`]: PathBuf::push
58
59
60mod sys;
61#[cfg(test)]
62mod tests;
63
64use std::borrow::{Borrow, Cow};
65use std::cmp;
66use std::error::Error;
67use std::fmt;
68use std::hash::{Hash, Hasher};
69use std::iter::{self, FusedIterator};
70use std::ops::{self, Deref};
71use std::rc::Rc;
72use std::str::FromStr;
73use std::sync::Arc;
74
75use sys::{is_sep_char, MAIN_SEP_STR, MAIN_SEP};
76
77
78////////////////////////////////////////////////////////////////////////////////
79// Exposed parsing helpers
80////////////////////////////////////////////////////////////////////////////////
81
82/// Determines whether the character is one of the permitted path
83/// separators for the current platform.
84///
85/// # Examples
86///
87/// ```
88/// use uni_path as path;
89///
90/// assert!(path::is_separator('/'));
91/// assert!(!path::is_separator('❤'));
92/// ```
93pub fn is_separator(c: char) -> bool {
94 is_sep_char(c)
95}
96
97/// The primary separator of path components for the current platform.
98///
99/// It is always `/`.
100pub const MAIN_SEPARATOR: char = sys::MAIN_SEP;
101
102////////////////////////////////////////////////////////////////////////////////
103// Misc helpers
104////////////////////////////////////////////////////////////////////////////////
105
106// Iterate through `iter` while it matches `prefix`; return `None` if `prefix`
107// is not a prefix of `iter`, otherwise return `Some(iter_after_prefix)` giving
108// `iter` after having exhausted `prefix`.
109fn iter_after<'a, 'b, I, J>(mut iter: I, mut prefix: J) -> Option<I>
110where
111 I: Iterator<Item = Component<'a>> + Clone,
112 J: Iterator<Item = Component<'b>>,
113{
114 loop {
115 let mut iter_next = iter.clone();
116 match (iter_next.next(), prefix.next()) {
117 (Some(ref x), Some(ref y)) if x == y => (),
118 (Some(_), Some(_)) => return None,
119 (Some(_), None) => return Some(iter),
120 (None, None) => return Some(iter),
121 (None, Some(_)) => return None,
122 }
123 iter = iter_next;
124 }
125}
126
127////////////////////////////////////////////////////////////////////////////////
128// Cross-platform, iterator-independent parsing
129////////////////////////////////////////////////////////////////////////////////
130
131/// Says whether the first byte is a separator.
132fn has_physical_root(path: &str) -> bool {
133 !path.is_empty() && is_sep_char(path.chars().nth(0).unwrap())
134}
135
136// basic workhorse for splitting stem and extension
137fn split_file_at_dot(file: &str) -> (Option<&str>, Option<&str>) {
138 if file == ".." {
139 return (Some(file), None);
140 }
141
142 let mut iter = file.rsplitn(2, '.');
143 let after = iter.next();
144 let before = iter.next();
145 if before == Some("") {
146 (Some(file), None)
147 } else {
148 (before, after)
149 }
150}
151
152////////////////////////////////////////////////////////////////////////////////
153// The core iterators
154////////////////////////////////////////////////////////////////////////////////
155
156/// Component parsing works by a double-ended state machine; the cursors at the
157/// front and back of the path each keep track of what parts of the path have
158/// been consumed so far.
159///
160/// Going front to back, a path is made up of a starting
161/// directory component, and a body (of normal components)
162#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
163enum State {
164 StartDir = 1, // / or . or nothing
165 Body = 2, // foo/bar/baz
166 Done = 3,
167}
168
169/// A single component of a path.
170///
171/// A `Component` roughly corresponds to a substring between path separators
172/// (`/`).
173///
174/// This `enum` is created by iterating over [`Components`], which in turn is
175/// created by the [`components`](Path::components) method on [`Path`].
176///
177/// # Examples
178///
179/// ```rust
180/// use uni_path::{Component, Path};
181///
182/// let path = Path::new("/tmp/foo/bar.txt");
183/// let components = path.components().collect::<Vec<_>>();
184/// assert_eq!(&components, &[
185/// Component::RootDir,
186/// Component::Normal("tmp".as_ref()),
187/// Component::Normal("foo".as_ref()),
188/// Component::Normal("bar.txt".as_ref()),
189/// ]);
190/// ```
191#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
192pub enum Component<'a> {
193 /// The root directory component, appears after any prefix and before anything else.
194 ///
195 /// It represents a separator that designates that a path starts from root.
196 RootDir,
197
198 /// A reference to the current directory, i.e., `.`.
199 CurDir,
200
201 /// A reference to the parent directory, i.e., `..`.
202 ParentDir,
203
204 /// A normal component, e.g., `a` and `b` in `a/b`.
205 ///
206 /// This variant is the most common one, it represents references to files
207 /// or directories.
208 Normal(&'a str),
209}
210
211impl<'a> Component<'a> {
212 /// Extracts the underlying [`str`] slice.
213 ///
214 /// # Examples
215 ///
216 /// ```
217 /// use uni_path::Path;
218 ///
219 /// let path = Path::new("./tmp/foo/bar.txt");
220 /// let components: Vec<_> = path.components().map(|comp| comp.as_str()).collect();
221 /// assert_eq!(&components, &[".", "tmp", "foo", "bar.txt"]);
222 /// ```
223 pub fn as_str(self) -> &'a str {
224 match self {
225 Component::RootDir => MAIN_SEP_STR,
226 Component::CurDir => ".",
227 Component::ParentDir => "..",
228 Component::Normal(path) => path,
229 }
230 }
231}
232
233impl AsRef<str> for Component<'_> {
234 #[inline]
235 fn as_ref(&self) -> &str {
236 self.as_str()
237 }
238}
239
240impl AsRef<Path> for Component<'_> {
241 #[inline]
242 fn as_ref(&self) -> &Path {
243 self.as_str().as_ref()
244 }
245}
246
247/// An iterator over the [`Component`]s of a [`Path`].
248///
249/// This `struct` is created by the [`components`] method on [`Path`].
250/// See its documentation for more.
251///
252/// # Examples
253///
254/// ```
255/// use uni_path::Path;
256///
257/// let path = Path::new("/tmp/foo/bar.txt");
258///
259/// for component in path.components() {
260/// println!("{:?}", component);
261/// }
262/// ```
263///
264/// [`components`]: Path::components
265#[derive(Clone)]
266pub struct Components<'a> {
267 // The path left to parse components from
268 path: &'a str,
269
270 // true if path *physically* has a root separator;
271 has_physical_root: bool,
272
273 // The iterator is double-ended, and these two states keep track of what has
274 // been produced from either end
275 front: State,
276 back: State,
277}
278
279/// An iterator over the [`Component`]s of a [`Path`], as [`str`] slices.
280///
281/// This `struct` is created by the [`iter`] method on [`Path`].
282/// See its documentation for more.
283///
284/// [`iter`]: Path::iter
285#[derive(Clone)]
286pub struct Iter<'a> {
287 inner: Components<'a>,
288}
289
290impl fmt::Debug for Components<'_> {
291 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
292 struct DebugHelper<'a>(&'a Path);
293
294 impl fmt::Debug for DebugHelper<'_> {
295 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
296 f.debug_list().entries(self.0.components()).finish()
297 }
298 }
299
300 f.debug_tuple("Components").field(&DebugHelper(self.as_path())).finish()
301 }
302}
303
304impl<'a> Components<'a> {
305 // Given the iteration so far, how much of the pre-State::Body path is left?
306 #[inline]
307 fn len_before_body(&self) -> usize {
308 let root = if self.front <= State::StartDir && self.has_physical_root { 1 } else { 0 };
309 let cur_dir = if self.front <= State::StartDir && self.include_cur_dir() { 1 } else { 0 };
310 root + cur_dir
311 }
312
313 // is the iteration complete?
314 #[inline]
315 fn finished(&self) -> bool {
316 self.front == State::Done || self.back == State::Done || self.front > self.back
317 }
318
319 #[inline]
320 fn is_sep_char(&self, b: char) -> bool {
321 is_sep_char(b)
322 }
323
324 /// Extracts a slice corresponding to the portion of the path remaining for iteration.
325 ///
326 /// # Examples
327 ///
328 /// ```
329 /// use uni_path::Path;
330 ///
331 /// let mut components = Path::new("/tmp/foo/bar.txt").components();
332 /// components.next();
333 /// components.next();
334 ///
335 /// assert_eq!(Path::new("foo/bar.txt"), components.as_path());
336 /// ```
337 pub fn as_path(&self) -> &'a Path {
338 let mut comps = self.clone();
339 if comps.front == State::Body {
340 comps.trim_left();
341 }
342 if comps.back == State::Body {
343 comps.trim_right();
344 }
345 Path::from_str(comps.path)
346 }
347
348 /// Is the *original* path rooted?
349 fn has_root(&self) -> bool {
350 self.has_physical_root
351 }
352
353 /// Should the normalized path include a leading . ?
354 fn include_cur_dir(&self) -> bool {
355 if self.has_root() {
356 return false;
357 }
358 let mut iter = self.path.chars();
359 match (iter.next(), iter.next()) {
360 (Some('.'), None) => true,
361 (Some('.'), Some(b)) => self.is_sep_char(b),
362 _ => false,
363 }
364 }
365
366 // parse a given byte sequence into the corresponding path component
367 fn parse_single_component<'b>(&self, comp: &'b str) -> Option<Component<'b>> {
368 match comp {
369 "." => None, // . components are normalized away, except at
370 // the beginning of a path, which is treated
371 // separately via `include_cur_dir`
372 ".." => Some(Component::ParentDir),
373 "" => None,
374 _ => Some(Component::Normal(comp)),
375 }
376 }
377
378 // parse a component from the left, saying how many bytes to consume to
379 // remove the component
380 fn parse_next_component(&self) -> (usize, Option<Component<'a>>) {
381 debug_assert!(self.front == State::Body);
382 let (extra, comp) = match self.path.chars().position(|b| self.is_sep_char(b)) {
383 None => (0, self.path),
384 Some(i) => (1, &self.path[..i]),
385 };
386 (comp.len() + extra, self.parse_single_component(comp))
387 }
388
389 // parse a component from the right, saying how many bytes to consume to
390 // remove the component
391 fn parse_next_component_back(&self) -> (usize, Option<Component<'a>>) {
392 debug_assert!(self.back == State::Body);
393 let start = self.len_before_body();
394 // @@ rewrite
395 let path = &self.path[start..];
396 let (extra, comp) = match path.chars().rev().position(|b| self.is_sep_char(b)).map(|p| path.len() - p - 1) {
397 None => (0, &self.path[start..]),
398 Some(i) => (1, &self.path[start + i + 1..]),
399 };
400 (comp.len() + extra, self.parse_single_component(comp))
401 }
402
403 // trim away repeated separators (i.e., empty components) on the left
404 fn trim_left(&mut self) {
405 while !self.path.is_empty() {
406 let (size, comp) = self.parse_next_component();
407 if comp.is_some() {
408 return;
409 } else {
410 self.path = &self.path[size..];
411 }
412 }
413 }
414
415 // trim away repeated separators (i.e., empty components) on the right
416 fn trim_right(&mut self) {
417 while self.path.len() > self.len_before_body() {
418 let (size, comp) = self.parse_next_component_back();
419 if comp.is_some() {
420 return;
421 } else {
422 self.path = &self.path[..self.path.len() - size];
423 }
424 }
425 }
426}
427
428impl AsRef<Path> for Components<'_> {
429 #[inline]
430 fn as_ref(&self) -> &Path {
431 self.as_path()
432 }
433}
434
435impl AsRef<str> for Components<'_> {
436 #[inline]
437 fn as_ref(&self) -> &str {
438 self.as_path().as_str()
439 }
440}
441
442impl fmt::Debug for Iter<'_> {
443 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
444 struct DebugHelper<'a>(&'a Path);
445
446 impl fmt::Debug for DebugHelper<'_> {
447 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
448 f.debug_list().entries(self.0.iter()).finish()
449 }
450 }
451
452 f.debug_tuple("Iter").field(&DebugHelper(self.as_path())).finish()
453 }
454}
455
456impl<'a> Iter<'a> {
457 /// Extracts a slice corresponding to the portion of the path remaining for iteration.
458 ///
459 /// # Examples
460 ///
461 /// ```
462 /// use uni_path::Path;
463 ///
464 /// let mut iter = Path::new("/tmp/foo/bar.txt").iter();
465 /// iter.next();
466 /// iter.next();
467 ///
468 /// assert_eq!(Path::new("foo/bar.txt"), iter.as_path());
469 /// ```
470 #[inline]
471 pub fn as_path(&self) -> &'a Path {
472 self.inner.as_path()
473 }
474}
475
476impl AsRef<Path> for Iter<'_> {
477 #[inline]
478 fn as_ref(&self) -> &Path {
479 self.as_path()
480 }
481}
482
483impl AsRef<str> for Iter<'_> {
484 #[inline]
485 fn as_ref(&self) -> &str {
486 self.as_path().as_str()
487 }
488}
489
490impl<'a> Iterator for Iter<'a> {
491 type Item = &'a str;
492
493 #[inline]
494 fn next(&mut self) -> Option<&'a str> {
495 self.inner.next().map(Component::as_str)
496 }
497}
498
499impl<'a> DoubleEndedIterator for Iter<'a> {
500 #[inline]
501 fn next_back(&mut self) -> Option<&'a str> {
502 self.inner.next_back().map(Component::as_str)
503 }
504}
505
506impl FusedIterator for Iter<'_> {}
507
508impl<'a> Iterator for Components<'a> {
509 type Item = Component<'a>;
510
511 fn next(&mut self) -> Option<Component<'a>> {
512 while !self.finished() {
513 match self.front {
514 State::StartDir => {
515 self.front = State::Body;
516 if self.has_physical_root {
517 debug_assert!(!self.path.is_empty());
518 self.path = &self.path[1..];
519 return Some(Component::RootDir);
520 } else if self.include_cur_dir() {
521 debug_assert!(!self.path.is_empty());
522 self.path = &self.path[1..];
523 return Some(Component::CurDir);
524 }
525 }
526 State::Body if !self.path.is_empty() => {
527 let (size, comp) = self.parse_next_component();
528 self.path = &self.path[size..];
529 if comp.is_some() {
530 return comp;
531 }
532 }
533 State::Body => {
534 self.front = State::Done;
535 }
536 State::Done => unreachable!(),
537 }
538 }
539 None
540 }
541}
542
543impl<'a> DoubleEndedIterator for Components<'a> {
544 fn next_back(&mut self) -> Option<Component<'a>> {
545 while !self.finished() {
546 match self.back {
547 State::Body if self.path.len() > self.len_before_body() => {
548 let (size, comp) = self.parse_next_component_back();
549 self.path = &self.path[..self.path.len() - size];
550 if comp.is_some() {
551 return comp;
552 }
553 }
554 State::Body => {
555 self.back = State::StartDir;
556 }
557 State::StartDir => {
558 self.back = State::Done;
559 if self.has_physical_root {
560 self.path = &self.path[..self.path.len() - 1];
561 return Some(Component::RootDir);
562 } else if self.include_cur_dir() {
563 self.path = &self.path[..self.path.len() - 1];
564 return Some(Component::CurDir);
565 }
566 }
567 State::Done => unreachable!(),
568 }
569 }
570 None
571 }
572}
573
574impl FusedIterator for Components<'_> {}
575
576impl<'a> cmp::PartialEq for Components<'a> {
577 #[inline]
578 fn eq(&self, other: &Components<'a>) -> bool {
579 Iterator::eq(self.clone(), other.clone())
580 }
581}
582
583impl cmp::Eq for Components<'_> {}
584
585impl<'a> cmp::PartialOrd for Components<'a> {
586 #[inline]
587 fn partial_cmp(&self, other: &Components<'a>) -> Option<cmp::Ordering> {
588 Iterator::partial_cmp(self.clone(), other.clone())
589 }
590}
591
592impl cmp::Ord for Components<'_> {
593 #[inline]
594 fn cmp(&self, other: &Self) -> cmp::Ordering {
595 Iterator::cmp(self.clone(), other.clone())
596 }
597}
598
599/// An iterator over [`Path`] and its ancestors.
600///
601/// This `struct` is created by the [`ancestors`] method on [`Path`].
602/// See its documentation for more.
603///
604/// # Examples
605///
606/// ```
607/// use uni_path::Path;
608///
609/// let path = Path::new("/foo/bar");
610///
611/// for ancestor in path.ancestors() {
612/// println!("{}", ancestor);
613/// }
614/// ```
615///
616/// [`ancestors`]: Path::ancestors
617#[derive(Copy, Clone, Debug)]
618pub struct Ancestors<'a> {
619 next: Option<&'a Path>,
620}
621
622impl<'a> Iterator for Ancestors<'a> {
623 type Item = &'a Path;
624
625 #[inline]
626 fn next(&mut self) -> Option<Self::Item> {
627 let next = self.next;
628 self.next = next.and_then(Path::parent);
629 next
630 }
631}
632
633impl FusedIterator for Ancestors<'_> {}
634
635////////////////////////////////////////////////////////////////////////////////
636// Basic types and traits
637////////////////////////////////////////////////////////////////////////////////
638
639/// An owned, mutable path (akin to [`String`]).
640///
641/// This type provides methods like [`push`] and [`set_extension`] that mutate
642/// the path in place. It also implements [`Deref`] to [`Path`], meaning that
643/// all methods on [`Path`] slices are available on `PathBuf` values as well.
644///
645/// [`push`]: PathBuf::push
646/// [`set_extension`]: PathBuf::set_extension
647///
648/// More details about the overall approach can be found in
649/// the [module documentation](self).
650///
651/// # Examples
652///
653/// You can use [`push`] to build up a `PathBuf` from
654/// components:
655///
656/// ```
657/// use uni_path::PathBuf;
658///
659/// let mut path = PathBuf::new();
660///
661/// path.push(r"/");
662/// path.push("lib");
663/// path.push("libc");
664///
665/// path.set_extension("so");
666/// ```
667///
668/// However, [`push`] is best used for dynamic situations. This is a better way
669/// to do this when you know all of the components ahead of time:
670///
671/// ```
672/// use uni_path::PathBuf;
673///
674/// let path: PathBuf = [r"/", "lib", "libc.so"].iter().collect();
675/// ```
676///
677/// We can still do better than this! Since these are all strings, we can use
678/// `From::from`:
679///
680/// ```
681/// use uni_path::PathBuf;
682///
683/// let path = PathBuf::from("/lib/libc.so");
684/// ```
685///
686/// Which method works best depends on what kind of situation you're in.
687#[derive(Clone)]
688#[repr(transparent)]
689pub struct PathBuf {
690 inner: String,
691}
692
693impl PathBuf {
694 #[inline]
695 fn as_mut_string(&mut self) -> &mut String {
696 &mut self.inner
697 }
698
699 /// Allocates an empty `PathBuf`.
700 ///
701 /// # Examples
702 ///
703 /// ```
704 /// use uni_path::PathBuf;
705 ///
706 /// let path = PathBuf::new();
707 /// ```
708 #[inline]
709 pub fn new() -> PathBuf {
710 PathBuf { inner: String::new() }
711 }
712
713 /// Creates a new `PathBuf` with a given capacity used to create the
714 /// internal [`String`]. See [`with_capacity`] defined on [`String`].
715 ///
716 /// # Examples
717 ///
718 /// ```
719 /// use uni_path::PathBuf;
720 ///
721 /// let mut path = PathBuf::with_capacity(10);
722 /// let capacity = path.capacity();
723 ///
724 /// // This push is done without reallocating
725 /// path.push(r"/");
726 ///
727 /// assert_eq!(capacity, path.capacity());
728 /// ```
729 ///
730 /// [`with_capacity`]: String::with_capacity
731 #[inline]
732 pub fn with_capacity(capacity: usize) -> PathBuf {
733 PathBuf { inner: String::with_capacity(capacity) }
734 }
735
736 /// Coerces to a [`Path`] slice.
737 ///
738 /// # Examples
739 ///
740 /// ```
741 /// use uni_path::{Path, PathBuf};
742 ///
743 /// let p = PathBuf::from("/test");
744 /// assert_eq!(Path::new("/test"), p.as_path());
745 /// ```
746 #[inline]
747 pub fn as_path(&self) -> &Path {
748 self
749 }
750
751 /// Extends `self` with `path`.
752 ///
753 /// If `path` is absolute, it replaces the current path.
754 ///
755 /// # Examples
756 ///
757 /// Pushing a relative path extends the existing path:
758 ///
759 /// ```
760 /// use uni_path::PathBuf;
761 ///
762 /// let mut path = PathBuf::from("/tmp");
763 /// path.push("file.bk");
764 /// assert_eq!(path, PathBuf::from("/tmp/file.bk"));
765 /// ```
766 ///
767 /// Pushing an absolute path replaces the existing path:
768 ///
769 /// ```
770 /// use uni_path::PathBuf;
771 ///
772 /// let mut path = PathBuf::from("/tmp");
773 /// path.push("/etc");
774 /// assert_eq!(path, PathBuf::from("/etc"));
775 /// ```
776 pub fn push<P: AsRef<Path>>(&mut self, path: P) {
777 self._push(path.as_ref())
778 }
779
780 fn _push(&mut self, path: &Path) {
781 // in general, a separator is needed if the rightmost byte is not a separator
782 let need_sep = self.as_mut_string().chars().last().map(|c| !is_sep_char(c)).unwrap_or(false);
783
784 // absolute `path` replaces `self`
785 if path.is_absolute() {
786 self.as_mut_string().truncate(0);
787
788 // `path` has a root
789 } else if path.has_root() {
790 self.as_mut_string().truncate(0);
791
792 // `path` is a pure relative path
793 } else if need_sep {
794 self.inner.push(MAIN_SEP);
795 }
796
797 self.inner.push_str(path.as_str());
798 }
799
800 /// Truncates `self` to [`self.parent`].
801 ///
802 /// Returns `false` and does nothing if [`self.parent`] is [`None`].
803 /// Otherwise, returns `true`.
804 ///
805 /// [`self.parent`]: Path::parent
806 ///
807 /// # Examples
808 ///
809 /// ```
810 /// use uni_path::{Path, PathBuf};
811 ///
812 /// let mut p = PathBuf::from("/spirited/away.rs");
813 ///
814 /// p.pop();
815 /// assert_eq!(Path::new("/spirited"), p);
816 /// p.pop();
817 /// assert_eq!(Path::new("/"), p);
818 /// ```
819 pub fn pop(&mut self) -> bool {
820 match self.parent().map(|p| p.as_str().len()) {
821 Some(len) => {
822 self.as_mut_string().truncate(len);
823 true
824 }
825 None => false,
826 }
827 }
828
829 /// Updates [`self.file_name`] to `file_name`.
830 ///
831 /// If [`self.file_name`] was [`None`], this is equivalent to pushing
832 /// `file_name`.
833 ///
834 /// Otherwise it is equivalent to calling [`pop`] and then pushing
835 /// `file_name`. The new path will be a sibling of the original path.
836 /// (That is, it will have the same parent.)
837 ///
838 /// [`self.file_name`]: Path::file_name
839 /// [`pop`]: PathBuf::pop
840 ///
841 /// # Examples
842 ///
843 /// ```
844 /// use uni_path::PathBuf;
845 ///
846 /// let mut buf = PathBuf::from("/");
847 /// assert!(buf.file_name() == None);
848 /// buf.set_file_name("bar");
849 /// assert!(buf == PathBuf::from("/bar"));
850 /// assert!(buf.file_name().is_some());
851 /// buf.set_file_name("baz.txt");
852 /// assert!(buf == PathBuf::from("/baz.txt"));
853 /// ```
854 pub fn set_file_name<S: AsRef<str>>(&mut self, file_name: S) {
855 self._set_file_name(file_name.as_ref())
856 }
857
858 fn _set_file_name(&mut self, file_name: &str) {
859 if self.file_name().is_some() {
860 let popped = self.pop();
861 debug_assert!(popped);
862 }
863 self.push(file_name);
864 }
865
866 /// Updates [`self.extension`] to `extension`.
867 ///
868 /// Returns `false` and does nothing if [`self.file_name`] is [`None`],
869 /// returns `true` and updates the extension otherwise.
870 ///
871 /// If [`self.extension`] is [`None`], the extension is added; otherwise
872 /// it is replaced.
873 ///
874 /// [`self.file_name`]: Path::file_name
875 /// [`self.extension`]: Path::extension
876 ///
877 /// # Examples
878 ///
879 /// ```
880 /// use uni_path::{Path, PathBuf};
881 ///
882 /// let mut p = PathBuf::from("/feel/the");
883 ///
884 /// p.set_extension("force");
885 /// assert_eq!(Path::new("/feel/the.force"), p.as_path());
886 ///
887 /// p.set_extension("dark_side");
888 /// assert_eq!(Path::new("/feel/the.dark_side"), p.as_path());
889 /// ```
890 pub fn set_extension<S: AsRef<str>>(&mut self, extension: S) -> bool {
891 self._set_extension(extension.as_ref())
892 }
893
894 fn _set_extension(&mut self, extension: &str) -> bool {
895 let file_stem = match self.file_stem() {
896 None => return false,
897 Some(f) => f,
898 };
899
900 // truncate until right after the file stem
901 let start = self.inner.as_ptr() as usize;
902 let end_file_stem = file_stem[file_stem.len()..].as_ptr() as usize;
903 let v = &mut self.inner;
904 v.truncate(end_file_stem.wrapping_sub(start));
905
906 // add the new extension, if any
907 if !extension.is_empty() {
908 v.reserve_exact(extension.len() + 1);
909 v.push('.');
910 v.push_str(extension);
911 }
912
913 true
914 }
915
916 /// Consumes the `PathBuf`, yielding its internal [`String`] storage.
917 ///
918 /// # Examples
919 ///
920 /// ```
921 /// use uni_path::PathBuf;
922 ///
923 /// let p = PathBuf::from("/the/head");
924 /// let str = p.into_string();
925 /// ```
926 #[inline]
927 pub fn into_string(self) -> String {
928 self.inner
929 }
930
931 /// Converts this `PathBuf` into a [boxed](Box) [`Path`].
932 #[inline]
933 pub fn into_boxed_path(self) -> Box<Path> {
934 let rw = Box::into_raw(self.inner.into_boxed_str()) as *mut Path;
935 unsafe { Box::from_raw(rw) }
936 }
937
938 /// Invokes [`capacity`] on the underlying instance of [`String`].
939 ///
940 /// [`capacity`]: String::capacity
941 #[inline]
942 pub fn capacity(&self) -> usize {
943 self.inner.capacity()
944 }
945
946 /// Invokes [`clear`] on the underlying instance of [`String`].
947 ///
948 /// [`clear`]: String::clear=
949 #[inline]
950 pub fn clear(&mut self) {
951 self.inner.clear()
952 }
953
954 /// Invokes [`reserve`] on the underlying instance of [`String`].
955 ///
956 /// [`reserve`]: String::reserve
957 #[inline]
958 pub fn reserve(&mut self, additional: usize) {
959 self.inner.reserve(additional)
960 }
961
962 /// Invokes [`reserve_exact`] on the underlying instance of [`String`].
963 ///
964 /// [`reserve_exact`]: String::reserve_exact
965 #[inline]
966 pub fn reserve_exact(&mut self, additional: usize) {
967 self.inner.reserve_exact(additional)
968 }
969
970 /// Invokes [`shrink_to_fit`] on the underlying instance of [`String`].
971 ///
972 /// [`shrink_to_fit`]: String::shrink_to_fit
973 #[inline]
974 pub fn shrink_to_fit(&mut self) {
975 self.inner.shrink_to_fit()
976 }
977
978 /*
979 /// Invokes [`shrink_to`] on the underlying instance of [`String`].
980 ///
981 /// [`shrink_to`]: String::shrink_to
982 #[inline]
983 pub fn shrink_to(&mut self, min_capacity: usize) {
984 self.inner.shrink_to(min_capacity)
985 }
986 */
987}
988
989impl From<&Path> for Box<Path> {
990 fn from(path: &Path) -> Box<Path> {
991 let boxed: Box<str> = path.inner.into();
992 let rw = Box::into_raw(boxed) as *mut Path;
993 unsafe { Box::from_raw(rw) }
994 }
995}
996
997impl From<Cow<'_, Path>> for Box<Path> {
998 #[inline]
999 fn from(cow: Cow<'_, Path>) -> Box<Path> {
1000 match cow {
1001 Cow::Borrowed(path) => Box::from(path),
1002 Cow::Owned(path) => Box::from(path),
1003 }
1004 }
1005}
1006
1007impl From<Box<Path>> for PathBuf {
1008 /// Converts a `Box<Path>` into a `PathBuf`
1009 ///
1010 /// This conversion does not allocate or copy memory.
1011 #[inline]
1012 fn from(boxed: Box<Path>) -> PathBuf {
1013 boxed.into_path_buf()
1014 }
1015}
1016
1017impl From<PathBuf> for Box<Path> {
1018 /// Converts a `PathBuf` into a `Box<Path>`
1019 ///
1020 /// This conversion currently should not allocate memory,
1021 /// but this behavior is not guaranteed on all platforms or in all future versions.
1022 #[inline]
1023 fn from(p: PathBuf) -> Box<Path> {
1024 p.into_boxed_path()
1025 }
1026}
1027
1028impl Clone for Box<Path> {
1029 #[inline]
1030 fn clone(&self) -> Self {
1031 self.to_path_buf().into_boxed_path()
1032 }
1033}
1034
1035impl<T: ?Sized + AsRef<str>> From<&T> for PathBuf {
1036 #[inline]
1037 fn from(s: &T) -> PathBuf {
1038 PathBuf::from(s.as_ref().to_string())
1039 }
1040}
1041
1042impl From<String> for PathBuf {
1043 /// Converts a `String` into a `PathBuf`
1044 ///
1045 /// This conversion does not allocate or copy memory.
1046 #[inline]
1047 fn from(s: String) -> PathBuf {
1048 PathBuf { inner: s }
1049 }
1050}
1051
1052impl From<PathBuf> for String {
1053 /// Converts a `PathBuf` into a `String`
1054 ///
1055 /// This conversion does not allocate or copy memory.
1056 #[inline]
1057 fn from(path_buf: PathBuf) -> String {
1058 path_buf.inner
1059 }
1060}
1061
1062impl FromStr for PathBuf {
1063 type Err = core::convert::Infallible;
1064
1065 #[inline]
1066 fn from_str(s: &str) -> Result<Self, Self::Err> {
1067 Ok(PathBuf::from(s))
1068 }
1069}
1070
1071impl<P: AsRef<Path>> iter::FromIterator<P> for PathBuf {
1072 fn from_iter<I: IntoIterator<Item = P>>(iter: I) -> PathBuf {
1073 let mut buf = PathBuf::new();
1074 buf.extend(iter);
1075 buf
1076 }
1077}
1078
1079impl<P: AsRef<Path>> iter::Extend<P> for PathBuf {
1080 fn extend<I: IntoIterator<Item = P>>(&mut self, iter: I) {
1081 iter.into_iter().for_each(move |p| self.push(p.as_ref()));
1082 }
1083 /*
1084 #[inline]
1085 fn extend_one(&mut self, p: P) {
1086 self.push(p.as_ref());
1087 }
1088 */
1089}
1090
1091impl fmt::Debug for PathBuf {
1092 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1093 fmt::Debug::fmt(&**self, formatter)
1094 }
1095}
1096
1097impl fmt::Display for PathBuf {
1098 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1099 fmt::Display::fmt(&**self, formatter)
1100 }
1101}
1102
1103impl ops::Deref for PathBuf {
1104 type Target = Path;
1105 #[inline]
1106 fn deref(&self) -> &Path {
1107 Path::new(&self.inner)
1108 }
1109}
1110
1111impl Borrow<Path> for PathBuf {
1112 #[inline]
1113 fn borrow(&self) -> &Path {
1114 self.deref()
1115 }
1116}
1117
1118impl Default for PathBuf {
1119 #[inline]
1120 fn default() -> Self {
1121 PathBuf::new()
1122 }
1123}
1124
1125impl<'a> From<&'a Path> for Cow<'a, Path> {
1126 #[inline]
1127 fn from(s: &'a Path) -> Cow<'a, Path> {
1128 Cow::Borrowed(s)
1129 }
1130}
1131
1132impl<'a> From<PathBuf> for Cow<'a, Path> {
1133 #[inline]
1134 fn from(s: PathBuf) -> Cow<'a, Path> {
1135 Cow::Owned(s)
1136 }
1137}
1138
1139impl<'a> From<&'a PathBuf> for Cow<'a, Path> {
1140 #[inline]
1141 fn from(p: &'a PathBuf) -> Cow<'a, Path> {
1142 Cow::Borrowed(p.as_path())
1143 }
1144}
1145
1146impl<'a> From<Cow<'a, Path>> for PathBuf {
1147 #[inline]
1148 fn from(p: Cow<'a, Path>) -> Self {
1149 p.into_owned()
1150 }
1151}
1152
1153impl From<PathBuf> for Arc<Path> {
1154 /// Converts a `PathBuf` into an `Arc` by moving the `PathBuf` data into a new `Arc` buffer.
1155 #[inline]
1156 fn from(s: PathBuf) -> Arc<Path> {
1157 let arc: Arc<str> = Arc::from(s.into_string());
1158 unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Path) }
1159 }
1160}
1161
1162impl From<&Path> for Arc<Path> {
1163 /// Converts a `Path` into an `Arc` by copying the `Path` data into a new `Arc` buffer.
1164 #[inline]
1165 fn from(s: &Path) -> Arc<Path> {
1166 let arc: Arc<str> = Arc::from(s.as_str());
1167 unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Path) }
1168 }
1169}
1170
1171impl From<PathBuf> for Rc<Path> {
1172 /// Converts a `PathBuf` into an `Rc` by moving the `PathBuf` data into a new `Rc` buffer.
1173 #[inline]
1174 fn from(s: PathBuf) -> Rc<Path> {
1175 let rc: Rc<str> = Rc::from(s.into_string());
1176 unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Path) }
1177 }
1178}
1179
1180impl From<&Path> for Rc<Path> {
1181 /// Converts a `Path` into an `Rc` by copying the `Path` data into a new `Rc` buffer.
1182 #[inline]
1183 fn from(s: &Path) -> Rc<Path> {
1184 let rc: Rc<str> = Rc::from(s.as_str());
1185 unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Path) }
1186 }
1187}
1188
1189impl ToOwned for Path {
1190 type Owned = PathBuf;
1191 #[inline]
1192 fn to_owned(&self) -> PathBuf {
1193 self.to_path_buf()
1194 }
1195 /*
1196 #[inline]
1197 fn clone_into(&self, target: &mut PathBuf) {
1198 self.inner.clone_into(&mut target.inner);
1199 }
1200 */
1201}
1202
1203impl cmp::PartialEq for PathBuf {
1204 #[inline]
1205 fn eq(&self, other: &PathBuf) -> bool {
1206 self.components() == other.components()
1207 }
1208}
1209
1210impl Hash for PathBuf {
1211 fn hash<H: Hasher>(&self, h: &mut H) {
1212 self.as_path().hash(h)
1213 }
1214}
1215
1216impl cmp::Eq for PathBuf {}
1217
1218impl cmp::PartialOrd for PathBuf {
1219 #[inline]
1220 fn partial_cmp(&self, other: &PathBuf) -> Option<cmp::Ordering> {
1221 self.components().partial_cmp(other.components())
1222 }
1223}
1224
1225impl cmp::Ord for PathBuf {
1226 #[inline]
1227 fn cmp(&self, other: &PathBuf) -> cmp::Ordering {
1228 self.components().cmp(other.components())
1229 }
1230}
1231
1232impl AsRef<str> for PathBuf {
1233 #[inline]
1234 fn as_ref(&self) -> &str {
1235 &self.inner[..]
1236 }
1237}
1238
1239/// A slice of a path (akin to [`str`]).
1240///
1241/// This type supports a number of operations for inspecting a path, including
1242/// breaking the path into its components (separated by `/`),
1243/// extracting the file name, determining whether the path
1244/// is absolute, and so on.
1245///
1246/// This is an *unsized* type, meaning that it must always be used behind a
1247/// pointer like `&` or [`Box`]. For an owned version of this type,
1248/// see [`PathBuf`].
1249///
1250/// More details about the overall approach can be found in
1251/// the [module documentation](self).
1252///
1253/// # Examples
1254///
1255/// ```
1256/// use uni_path::Path;
1257///
1258/// let path = Path::new("./foo/bar.txt");
1259///
1260/// let parent = path.parent();
1261/// assert_eq!(parent, Some(Path::new("./foo")));
1262///
1263/// let file_stem = path.file_stem();
1264/// assert_eq!(file_stem, Some("bar"));
1265///
1266/// let extension = path.extension();
1267/// assert_eq!(extension, Some("txt"));
1268/// ```
1269#[repr(transparent)]
1270pub struct Path {
1271 inner: str,
1272}
1273
1274/// An error returned from [`Path::strip_prefix`] if the prefix was not found.
1275///
1276/// This `struct` is created by the [`strip_prefix`] method on [`Path`].
1277/// See its documentation for more.
1278///
1279/// [`strip_prefix`]: Path::strip_prefix
1280#[derive(Debug, Clone, PartialEq, Eq)]
1281pub struct StripPrefixError(());
1282
1283impl Path {
1284 fn from_str(s: &str) -> &Path {
1285 Path::new(s)
1286 }
1287
1288 /// Directly wraps a string slice as a `Path` slice.
1289 ///
1290 /// This is a cost-free conversion.
1291 ///
1292 /// # Examples
1293 ///
1294 /// ```
1295 /// use uni_path::Path;
1296 ///
1297 /// Path::new("foo.txt");
1298 /// ```
1299 ///
1300 /// You can create `Path`s from `String`s, or even other `Path`s:
1301 ///
1302 /// ```
1303 /// use uni_path::Path;
1304 ///
1305 /// let string = String::from("foo.txt");
1306 /// let from_string = Path::new(&string);
1307 /// let from_path = Path::new(&from_string);
1308 /// assert_eq!(from_string, from_path);
1309 /// ```
1310 pub fn new<S: AsRef<str> + ?Sized>(s: &S) -> &Path {
1311 unsafe { &*(s.as_ref() as *const str as *const Path) }
1312 }
1313
1314 /// Yields the underlying [`str`] slice.
1315 ///
1316 /// # Examples
1317 ///
1318 /// ```
1319 /// use uni_path::Path;
1320 ///
1321 /// let str = Path::new("foo.txt").as_str();
1322 /// assert_eq!(str, "foo.txt");
1323 /// ```
1324 #[inline]
1325 pub fn as_str(&self) -> &str {
1326 &self.inner
1327 }
1328
1329 /// Yields a [`&str`] slice if the `Path` is valid unicode.
1330 ///
1331 /// This conversion may entail doing a check for UTF-8 validity.
1332 /// Note that validation is performed because non-UTF-8 strings are
1333 /// perfectly valid for some OS.
1334 ///
1335 /// [`&str`]: str
1336 ///
1337 /// # Examples
1338 ///
1339 /// ```
1340 /// use uni_path::Path;
1341 ///
1342 /// let path = Path::new("foo.txt");
1343 /// assert_eq!(path.to_str(), "foo.txt");
1344 /// ```
1345 #[inline]
1346 pub fn to_str(&self) -> &str {
1347 &self.inner
1348 }
1349
1350 /// Converts a `Path` to a [`Cow<str>`].
1351 ///
1352 /// # Examples
1353 ///
1354 /// ```
1355 /// use uni_path::Path;
1356 ///
1357 /// let path = Path::new("foo.txt");
1358 /// assert_eq!(path.to_str_cow(), "foo.txt");
1359 /// ```
1360 #[inline]
1361 pub fn to_str_cow(&self) -> Cow<'_, str> {
1362 Cow::from(&self.inner)
1363 }
1364
1365 /// Converts a `Path` to an owned [`PathBuf`].
1366 ///
1367 /// # Examples
1368 ///
1369 /// ```
1370 /// use uni_path::Path;
1371 ///
1372 /// let path_buf = Path::new("foo.txt").to_path_buf();
1373 /// assert_eq!(path_buf, uni_path::PathBuf::from("foo.txt"));
1374 /// ```
1375 pub fn to_path_buf(&self) -> PathBuf {
1376 PathBuf::from(self.inner.to_string())
1377 }
1378
1379 /// Returns `true` if the `Path` is absolute, i.e., if it is independent of
1380 /// the current directory.
1381 ///
1382 /// A path is absolute if it starts with the root, so
1383 /// `is_absolute` and [`has_root`] are equivalent.
1384 /// # Examples
1385 ///
1386 /// ```
1387 /// use uni_path::Path;
1388 ///
1389 /// assert!(!Path::new("foo.txt").is_absolute());
1390 /// ```
1391 ///
1392 /// [`has_root`]: Path::has_root
1393 #[inline]
1394 pub fn is_absolute(&self) -> bool {
1395 self.has_root()
1396 }
1397
1398 /// Returns `true` if the `Path` is relative, i.e., not absolute.
1399 ///
1400 /// See [`is_absolute`]'s documentation for more details.
1401 ///
1402 /// # Examples
1403 ///
1404 /// ```
1405 /// use uni_path::Path;
1406 ///
1407 /// assert!(Path::new("foo.txt").is_relative());
1408 /// ```
1409 ///
1410 /// [`is_absolute`]: Path::is_absolute
1411 #[inline]
1412 pub fn is_relative(&self) -> bool {
1413 !self.is_absolute()
1414 }
1415
1416 /// Returns `true` if the `Path` has a root.
1417 ///
1418 /// A path has a root if it begins with `/`.
1419 ///
1420 /// # Examples
1421 ///
1422 /// ```
1423 /// use uni_path::Path;
1424 ///
1425 /// assert!(Path::new("/etc/passwd").has_root());
1426 /// ```
1427 #[inline]
1428 pub fn has_root(&self) -> bool {
1429 self.components().has_root()
1430 }
1431
1432 /// Returns the `Path` without its final component, if there is one.
1433 ///
1434 /// Returns [`None`] if the path terminates in a root or prefix.
1435 ///
1436 /// # Examples
1437 ///
1438 /// ```
1439 /// use uni_path::Path;
1440 ///
1441 /// let path = Path::new("/foo/bar");
1442 /// let parent = path.parent().unwrap();
1443 /// assert_eq!(parent, Path::new("/foo"));
1444 ///
1445 /// let grand_parent = parent.parent().unwrap();
1446 /// assert_eq!(grand_parent, Path::new("/"));
1447 /// assert_eq!(grand_parent.parent(), None);
1448 /// ```
1449 pub fn parent(&self) -> Option<&Path> {
1450 let mut comps = self.components();
1451 let comp = comps.next_back();
1452 comp.and_then(|p| match p {
1453 Component::Normal(_) | Component::CurDir | Component::ParentDir => {
1454 Some(comps.as_path())
1455 }
1456 _ => None,
1457 })
1458 }
1459
1460 /// Produces an iterator over `Path` and its ancestors.
1461 ///
1462 /// The iterator will yield the `Path` that is returned if the [`parent`] method is used zero
1463 /// or more times. That means, the iterator will yield `&self`, `&self.parent().unwrap()`,
1464 /// `&self.parent().unwrap().parent().unwrap()` and so on. If the [`parent`] method returns
1465 /// [`None`], the iterator will do likewise. The iterator will always yield at least one value,
1466 /// namely `&self`.
1467 ///
1468 /// # Examples
1469 ///
1470 /// ```
1471 /// use uni_path::Path;
1472 ///
1473 /// let mut ancestors = Path::new("/foo/bar").ancestors();
1474 /// assert_eq!(ancestors.next(), Some(Path::new("/foo/bar")));
1475 /// assert_eq!(ancestors.next(), Some(Path::new("/foo")));
1476 /// assert_eq!(ancestors.next(), Some(Path::new("/")));
1477 /// assert_eq!(ancestors.next(), None);
1478 ///
1479 /// let mut ancestors = Path::new("../foo/bar").ancestors();
1480 /// assert_eq!(ancestors.next(), Some(Path::new("../foo/bar")));
1481 /// assert_eq!(ancestors.next(), Some(Path::new("../foo")));
1482 /// assert_eq!(ancestors.next(), Some(Path::new("..")));
1483 /// assert_eq!(ancestors.next(), Some(Path::new("")));
1484 /// assert_eq!(ancestors.next(), None);
1485 /// ```
1486 ///
1487 /// [`parent`]: Path::parent
1488 #[inline]
1489 pub fn ancestors(&self) -> Ancestors<'_> {
1490 Ancestors { next: Some(&self) }
1491 }
1492
1493 /// Returns the final component of the `Path`, if there is one.
1494 ///
1495 /// If the path is a normal file, this is the file name. If it's the path of a directory, this
1496 /// is the directory name.
1497 ///
1498 /// Returns [`None`] if the path terminates in `..`.
1499 ///
1500 /// # Examples
1501 ///
1502 /// ```
1503 /// use uni_path::Path;
1504 ///
1505 /// assert_eq!(Some("bin"), Path::new("/usr/bin/").file_name());
1506 /// assert_eq!(Some("foo.txt"), Path::new("tmp/foo.txt").file_name());
1507 /// assert_eq!(Some("foo.txt"), Path::new("foo.txt/.").file_name());
1508 /// assert_eq!(Some("foo.txt"), Path::new("foo.txt/.//").file_name());
1509 /// assert_eq!(None, Path::new("foo.txt/..").file_name());
1510 /// assert_eq!(None, Path::new("/").file_name());
1511 /// ```
1512 pub fn file_name(&self) -> Option<&str> {
1513 self.components().next_back().and_then(|p| match p {
1514 Component::Normal(p) => Some(p),
1515 _ => None,
1516 })
1517 }
1518
1519 /// Returns a path that, when joined onto `base`, yields `self`.
1520 ///
1521 /// # Errors
1522 ///
1523 /// If `base` is not a prefix of `self` (i.e., [`starts_with`]
1524 /// returns `false`), returns [`Err`].
1525 ///
1526 /// [`starts_with`]: Path::starts_with
1527 ///
1528 /// # Examples
1529 ///
1530 /// ```
1531 /// use uni_path::{Path, PathBuf};
1532 ///
1533 /// let path = Path::new("/test/haha/foo.txt");
1534 ///
1535 /// assert_eq!(path.strip_prefix("/"), Ok(Path::new("test/haha/foo.txt")));
1536 /// assert_eq!(path.strip_prefix("/test"), Ok(Path::new("haha/foo.txt")));
1537 /// assert_eq!(path.strip_prefix("/test/"), Ok(Path::new("haha/foo.txt")));
1538 /// assert_eq!(path.strip_prefix("/test/haha/foo.txt"), Ok(Path::new("")));
1539 /// assert_eq!(path.strip_prefix("/test/haha/foo.txt/"), Ok(Path::new("")));
1540 ///
1541 /// assert!(path.strip_prefix("test").is_err());
1542 /// assert!(path.strip_prefix("/haha").is_err());
1543 ///
1544 /// let prefix = PathBuf::from("/test/");
1545 /// assert_eq!(path.strip_prefix(prefix), Ok(Path::new("haha/foo.txt")));
1546 /// ```
1547 pub fn strip_prefix<P>(&self, base: P) -> Result<&Path, StripPrefixError>
1548 where
1549 P: AsRef<Path>,
1550 {
1551 self._strip_prefix(base.as_ref())
1552 }
1553
1554 fn _strip_prefix(&self, base: &Path) -> Result<&Path, StripPrefixError> {
1555 iter_after(self.components(), base.components())
1556 .map(|c| c.as_path())
1557 .ok_or(StripPrefixError(()))
1558 }
1559
1560 /// Determines whether `base` is a prefix of `self`.
1561 ///
1562 /// Only considers whole path components to match.
1563 ///
1564 /// # Examples
1565 ///
1566 /// ```
1567 /// use uni_path::Path;
1568 ///
1569 /// let path = Path::new("/etc/passwd");
1570 ///
1571 /// assert!(path.starts_with("/etc"));
1572 /// assert!(path.starts_with("/etc/"));
1573 /// assert!(path.starts_with("/etc/passwd"));
1574 /// assert!(path.starts_with("/etc/passwd/")); // extra slash is okay
1575 /// assert!(path.starts_with("/etc/passwd///")); // multiple extra slashes are okay
1576 ///
1577 /// assert!(!path.starts_with("/e"));
1578 /// assert!(!path.starts_with("/etc/passwd.txt"));
1579 ///
1580 /// assert!(!Path::new("/etc/foo.rs").starts_with("/etc/foo"));
1581 /// ```
1582 pub fn starts_with<P: AsRef<Path>>(&self, base: P) -> bool {
1583 self._starts_with(base.as_ref())
1584 }
1585
1586 fn _starts_with(&self, base: &Path) -> bool {
1587 iter_after(self.components(), base.components()).is_some()
1588 }
1589
1590 /// Determines whether `child` is a suffix of `self`.
1591 ///
1592 /// Only considers whole path components to match.
1593 ///
1594 /// # Examples
1595 ///
1596 /// ```
1597 /// use uni_path::Path;
1598 ///
1599 /// let path = Path::new("/etc/resolv.conf");
1600 ///
1601 /// assert!(path.ends_with("resolv.conf"));
1602 /// assert!(path.ends_with("etc/resolv.conf"));
1603 /// assert!(path.ends_with("/etc/resolv.conf"));
1604 ///
1605 /// assert!(!path.ends_with("/resolv.conf"));
1606 /// assert!(!path.ends_with("conf")); // use .extension() instead
1607 /// ```
1608 pub fn ends_with<P: AsRef<Path>>(&self, child: P) -> bool {
1609 self._ends_with(child.as_ref())
1610 }
1611
1612 fn _ends_with(&self, child: &Path) -> bool {
1613 iter_after(self.components().rev(), child.components().rev()).is_some()
1614 }
1615
1616 /// Extracts the stem (non-extension) portion of [`self.file_name`].
1617 ///
1618 /// [`self.file_name`]: Path::file_name
1619 ///
1620 /// The stem is:
1621 ///
1622 /// * [`None`], if there is no file name;
1623 /// * The entire file name if there is no embedded `.`;
1624 /// * The entire file name if the file name begins with `.` and has no other `.`s within;
1625 /// * Otherwise, the portion of the file name before the final `.`
1626 ///
1627 /// # Examples
1628 ///
1629 /// ```
1630 /// use uni_path::Path;
1631 ///
1632 /// assert_eq!("foo", Path::new("foo.rs").file_stem().unwrap());
1633 /// assert_eq!("foo.tar", Path::new("foo.tar.gz").file_stem().unwrap());
1634 /// ```
1635 pub fn file_stem(&self) -> Option<&str> {
1636 self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.or(after))
1637 }
1638
1639 /// Extracts the extension of [`self.file_name`], if possible.
1640 ///
1641 /// The extension is:
1642 ///
1643 /// * [`None`], if there is no file name;
1644 /// * [`None`], if there is no embedded `.`;
1645 /// * [`None`], if the file name begins with `.` and has no other `.`s within;
1646 /// * Otherwise, the portion of the file name after the final `.`
1647 ///
1648 /// [`self.file_name`]: Path::file_name
1649 ///
1650 /// # Examples
1651 ///
1652 /// ```
1653 /// use uni_path::Path;
1654 ///
1655 /// assert_eq!("rs", Path::new("foo.rs").extension().unwrap());
1656 /// assert_eq!("gz", Path::new("foo.tar.gz").extension().unwrap());
1657 /// ```
1658 pub fn extension(&self) -> Option<&str> {
1659 self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.and(after))
1660 }
1661
1662 /// Creates an owned [`PathBuf`] with `path` adjoined to `self`.
1663 ///
1664 /// See [`PathBuf::push`] for more details on what it means to adjoin a path.
1665 ///
1666 /// # Examples
1667 ///
1668 /// ```
1669 /// use uni_path::{Path, PathBuf};
1670 ///
1671 /// assert_eq!(Path::new("/etc").join("passwd"), PathBuf::from("/etc/passwd"));
1672 /// ```
1673 #[must_use]
1674 pub fn join<P: AsRef<Path>>(&self, path: P) -> PathBuf {
1675 self._join(path.as_ref())
1676 }
1677
1678 fn _join(&self, path: &Path) -> PathBuf {
1679 let mut buf = self.to_path_buf();
1680 buf.push(path);
1681 buf
1682 }
1683
1684 /// Creates an owned [`PathBuf`] like `self` but with the given file name.
1685 ///
1686 /// See [`PathBuf::set_file_name`] for more details.
1687 ///
1688 /// # Examples
1689 ///
1690 /// ```
1691 /// use uni_path::{Path, PathBuf};
1692 ///
1693 /// let path = Path::new("/tmp/foo.txt");
1694 /// assert_eq!(path.with_file_name("bar.txt"), PathBuf::from("/tmp/bar.txt"));
1695 ///
1696 /// let path = Path::new("/tmp");
1697 /// assert_eq!(path.with_file_name("var"), PathBuf::from("/var"));
1698 /// ```
1699 pub fn with_file_name<S: AsRef<str>>(&self, file_name: S) -> PathBuf {
1700 self._with_file_name(file_name.as_ref())
1701 }
1702
1703 fn _with_file_name(&self, file_name: &str) -> PathBuf {
1704 let mut buf = self.to_path_buf();
1705 buf.set_file_name(file_name);
1706 buf
1707 }
1708
1709 /// Creates an owned [`PathBuf`] like `self` but with the given extension.
1710 ///
1711 /// See [`PathBuf::set_extension`] for more details.
1712 ///
1713 /// # Examples
1714 ///
1715 /// ```
1716 /// use uni_path::{Path, PathBuf};
1717 ///
1718 /// let path = Path::new("foo.rs");
1719 /// assert_eq!(path.with_extension("txt"), PathBuf::from("foo.txt"));
1720 ///
1721 /// let path = Path::new("foo.tar.gz");
1722 /// assert_eq!(path.with_extension(""), PathBuf::from("foo.tar"));
1723 /// assert_eq!(path.with_extension("xz"), PathBuf::from("foo.tar.xz"));
1724 /// assert_eq!(path.with_extension("").with_extension("txt"), PathBuf::from("foo.txt"));
1725 /// ```
1726 pub fn with_extension<S: AsRef<str>>(&self, extension: S) -> PathBuf {
1727 self._with_extension(extension.as_ref())
1728 }
1729
1730 fn _with_extension(&self, extension: &str) -> PathBuf {
1731 let mut buf = self.to_path_buf();
1732 buf.set_extension(extension);
1733 buf
1734 }
1735
1736 /// Produces an iterator over the [`Component`]s of the path.
1737 ///
1738 /// When parsing the path, there is a small amount of normalization:
1739 ///
1740 /// * Repeated separators are ignored, so `a/b` and `a//b` both have
1741 /// `a` and `b` as components.
1742 ///
1743 /// * Occurrences of `.` are normalized away, except if they are at the
1744 /// beginning of the path. For example, `a/./b`, `a/b/`, `a/b/.` and
1745 /// `a/b` all have `a` and `b` as components, but `./a/b` starts with
1746 /// an additional [`CurDir`] component.
1747 ///
1748 /// * A trailing slash is normalized away, `/a/b` and `/a/b/` are equivalent.
1749 ///
1750 /// Note that no other normalization takes place; in particular, `a/c`
1751 /// and `a/b/../c` are distinct, to account for the possibility that `b`
1752 /// is a symbolic link (so its parent isn't `a`).
1753 ///
1754 /// # Examples
1755 ///
1756 /// ```
1757 /// use uni_path::{Path, Component};
1758 ///
1759 /// let mut components = Path::new("/tmp/foo.txt").components();
1760 ///
1761 /// assert_eq!(components.next(), Some(Component::RootDir));
1762 /// assert_eq!(components.next(), Some(Component::Normal("tmp")));
1763 /// assert_eq!(components.next(), Some(Component::Normal("foo.txt")));
1764 /// assert_eq!(components.next(), None)
1765 /// ```
1766 ///
1767 /// [`CurDir`]: Component::CurDir
1768 pub fn components(&self) -> Components<'_> {
1769 Components {
1770 path: self.as_str(),
1771 has_physical_root: has_physical_root(self.as_str()),
1772 front: State::StartDir,
1773 back: State::Body,
1774 }
1775 }
1776
1777 /// Produces an iterator over the path's components viewed as [`str`]
1778 /// slices.
1779 ///
1780 /// For more information about the particulars of how the path is separated
1781 /// into components, see [`components`].
1782 ///
1783 /// [`components`]: Path::components
1784 ///
1785 /// # Examples
1786 ///
1787 /// ```
1788 /// use uni_path::{self as path, Path};
1789 ///
1790 /// let mut it = Path::new("/tmp/foo.txt").iter();
1791 /// assert_eq!(it.next().unwrap(), &path::MAIN_SEPARATOR.to_string());
1792 /// assert_eq!(it.next(), Some("tmp"));
1793 /// assert_eq!(it.next(), Some("foo.txt"));
1794 /// assert_eq!(it.next(), None)
1795 /// ```
1796 #[inline]
1797 pub fn iter(&self) -> Iter<'_> {
1798 Iter { inner: self.components() }
1799 }
1800
1801 /// Converts a [`Box<Path>`](Box) into a [`PathBuf`] without copying or
1802 /// allocating.
1803 pub fn into_path_buf(self: Box<Path>) -> PathBuf {
1804 let rw = Box::into_raw(self) as *mut str;
1805 let inner = unsafe { Box::from_raw(rw) };
1806 PathBuf { inner: String::from(inner) }
1807 }
1808}
1809
1810impl AsRef<str> for Path {
1811 #[inline]
1812 fn as_ref(&self) -> &str {
1813 &self.inner
1814 }
1815}
1816
1817impl fmt::Debug for Path {
1818 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1819 fmt::Debug::fmt(&self.inner, formatter)
1820 }
1821}
1822
1823impl fmt::Display for Path {
1824 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1825 fmt::Display::fmt(&self.inner, formatter)
1826 }
1827}
1828
1829impl cmp::PartialEq for Path {
1830 #[inline]
1831 fn eq(&self, other: &Path) -> bool {
1832 self.components().eq(other.components())
1833 }
1834}
1835
1836impl Hash for Path {
1837 fn hash<H: Hasher>(&self, h: &mut H) {
1838 for component in self.components() {
1839 component.hash(h);
1840 }
1841 }
1842}
1843
1844impl cmp::Eq for Path {}
1845
1846impl cmp::PartialOrd for Path {
1847 #[inline]
1848 fn partial_cmp(&self, other: &Path) -> Option<cmp::Ordering> {
1849 self.components().partial_cmp(other.components())
1850 }
1851}
1852
1853impl cmp::Ord for Path {
1854 #[inline]
1855 fn cmp(&self, other: &Path) -> cmp::Ordering {
1856 self.components().cmp(other.components())
1857 }
1858}
1859
1860impl AsRef<Path> for Path {
1861 #[inline]
1862 fn as_ref(&self) -> &Path {
1863 self
1864 }
1865}
1866
1867impl AsRef<Path> for str {
1868 #[inline]
1869 fn as_ref(&self) -> &Path {
1870 Path::new(self)
1871 }
1872}
1873
1874impl AsRef<Path> for Cow<'_, str> {
1875 #[inline]
1876 fn as_ref(&self) -> &Path {
1877 Path::new(self)
1878 }
1879}
1880
1881impl AsRef<Path> for String {
1882 #[inline]
1883 fn as_ref(&self) -> &Path {
1884 Path::new(self)
1885 }
1886}
1887
1888impl AsRef<Path> for PathBuf {
1889 #[inline]
1890 fn as_ref(&self) -> &Path {
1891 self
1892 }
1893}
1894
1895impl<'a> IntoIterator for &'a PathBuf {
1896 type Item = &'a str;
1897 type IntoIter = Iter<'a>;
1898 #[inline]
1899 fn into_iter(self) -> Iter<'a> {
1900 self.iter()
1901 }
1902}
1903
1904impl<'a> IntoIterator for &'a Path {
1905 type Item = &'a str;
1906 type IntoIter = Iter<'a>;
1907 #[inline]
1908 fn into_iter(self) -> Iter<'a> {
1909 self.iter()
1910 }
1911}
1912
1913macro_rules! impl_cmp {
1914 ($lhs:ty, $rhs: ty) => {
1915 impl<'a, 'b> PartialEq<$rhs> for $lhs {
1916 #[inline]
1917 fn eq(&self, other: &$rhs) -> bool {
1918 <Path as PartialEq>::eq(self, other)
1919 }
1920 }
1921
1922 impl<'a, 'b> PartialEq<$lhs> for $rhs {
1923 #[inline]
1924 fn eq(&self, other: &$lhs) -> bool {
1925 <Path as PartialEq>::eq(self, other)
1926 }
1927 }
1928
1929 impl<'a, 'b> PartialOrd<$rhs> for $lhs {
1930 #[inline]
1931 fn partial_cmp(&self, other: &$rhs) -> Option<cmp::Ordering> {
1932 <Path as PartialOrd>::partial_cmp(self, other)
1933 }
1934 }
1935
1936 impl<'a, 'b> PartialOrd<$lhs> for $rhs {
1937 #[inline]
1938 fn partial_cmp(&self, other: &$lhs) -> Option<cmp::Ordering> {
1939 <Path as PartialOrd>::partial_cmp(self, other)
1940 }
1941 }
1942 };
1943}
1944
1945impl_cmp!(PathBuf, Path);
1946impl_cmp!(PathBuf, &'a Path);
1947impl_cmp!(Cow<'a, Path>, Path);
1948impl_cmp!(Cow<'a, Path>, &'b Path);
1949impl_cmp!(Cow<'a, Path>, PathBuf);
1950
1951impl fmt::Display for StripPrefixError {
1952 #[allow(deprecated, deprecated_in_future)]
1953 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1954 self.description().fmt(f)
1955 }
1956}
1957
1958impl Error for StripPrefixError {
1959 #[allow(deprecated)]
1960 fn description(&self) -> &str {
1961 "prefix not found"
1962 }
1963}