camino/
lib.rs

1// Copyright (c) The camino Contributors
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4#![warn(missing_docs)]
5#![cfg_attr(doc_cfg, feature(doc_cfg, doc_auto_cfg))]
6
7//! UTF-8 encoded paths.
8//!
9//! `camino` is an extension of the [`std::path`] module that adds new [`Utf8PathBuf`] and [`Utf8Path`]
10//! types. These are like the standard library's [`PathBuf`] and [`Path`] types, except they are
11//! guaranteed to only contain UTF-8 encoded data. Therefore, they expose the ability to get their
12//! contents as strings, they implement [`Display`], etc.
13//!
14//! The [`std::path`] types are not guaranteed to be valid UTF-8. This is the right decision for the standard library,
15//! since it must be as general as possible. However, on all platforms, non-Unicode paths are vanishingly uncommon for a
16//! number of reasons:
17//! * Unicode won. There are still some legacy codebases that store paths in encodings like Shift-JIS, but most
18//!   have been converted to Unicode at this point.
19//! * Unicode is the common subset of supported paths across Windows and Unix platforms. (On Windows, Rust stores paths
20//!   as [an extension to UTF-8](https://simonsapin.github.io/wtf-8/), and converts them to UTF-16 at Win32
21//!   API boundaries.)
22//! * There are already many systems, such as Cargo, that only support UTF-8 paths. If your own tool interacts with any such
23//!   system, you can assume that paths are valid UTF-8 without creating any additional burdens on consumers.
24//! * The ["makefile problem"](https://www.mercurial-scm.org/wiki/EncodingStrategy#The_.22makefile_problem.22)
25//!   (which also applies to `Cargo.toml`, and any other metadata file that lists the names of other files) has *no general,
26//!   cross-platform solution* in systems that support non-UTF-8 paths. However, restricting paths to UTF-8 eliminates
27//!   this problem.
28//!
29//! Therefore, many programs that want to manipulate paths *do* assume they contain UTF-8 data, and convert them to [`str`]s
30//! as  necessary. However, because this invariant is not encoded in the [`Path`] type, conversions such as
31//! `path.to_str().unwrap()` need to be repeated again and again, creating a frustrating experience.
32//!
33//! Instead, `camino` allows you to check that your paths are UTF-8 *once*, and then manipulate them
34//! as valid UTF-8 from there on, avoiding repeated lossy and confusing conversions.
35
36// General note: we use #[allow(clippy::incompatible_msrv)] for code that's already guarded by a
37// version-specific cfg conditional.
38
39use std::{
40    borrow::{Borrow, Cow},
41    cmp::Ordering,
42    convert::{Infallible, TryFrom, TryInto},
43    error,
44    ffi::{OsStr, OsString},
45    fmt,
46    fs::{self, Metadata},
47    hash::{Hash, Hasher},
48    io,
49    iter::FusedIterator,
50    ops::Deref,
51    path::*,
52    rc::Rc,
53    str::FromStr,
54    sync::Arc,
55};
56
57#[cfg(feature = "proptest1")]
58mod proptest_impls;
59#[cfg(feature = "serde1")]
60mod serde_impls;
61#[cfg(test)]
62mod tests;
63
64/// An owned, mutable UTF-8 path (akin to [`String`]).
65///
66/// This type provides methods like [`push`] and [`set_extension`] that mutate
67/// the path in place. It also implements [`Deref`] to [`Utf8Path`], meaning that
68/// all methods on [`Utf8Path`] slices are available on [`Utf8PathBuf`] values as well.
69///
70/// [`push`]: Utf8PathBuf::push
71/// [`set_extension`]: Utf8PathBuf::set_extension
72///
73/// # Examples
74///
75/// You can use [`push`] to build up a [`Utf8PathBuf`] from
76/// components:
77///
78/// ```
79/// use camino::Utf8PathBuf;
80///
81/// let mut path = Utf8PathBuf::new();
82///
83/// path.push(r"C:\");
84/// path.push("windows");
85/// path.push("system32");
86///
87/// path.set_extension("dll");
88/// ```
89///
90/// However, [`push`] is best used for dynamic situations. This is a better way
91/// to do this when you know all of the components ahead of time:
92///
93/// ```
94/// use camino::Utf8PathBuf;
95///
96/// let path: Utf8PathBuf = [r"C:\", "windows", "system32.dll"].iter().collect();
97/// ```
98///
99/// We can still do better than this! Since these are all strings, we can use
100/// [`From::from`]:
101///
102/// ```
103/// use camino::Utf8PathBuf;
104///
105/// let path = Utf8PathBuf::from(r"C:\windows\system32.dll");
106/// ```
107///
108/// Which method works best depends on what kind of situation you're in.
109// NB: Internal PathBuf must only contain utf8 data
110#[derive(Clone, Default)]
111#[repr(transparent)]
112pub struct Utf8PathBuf(PathBuf);
113
114impl Utf8PathBuf {
115    /// Allocates an empty [`Utf8PathBuf`].
116    ///
117    /// # Examples
118    ///
119    /// ```
120    /// use camino::Utf8PathBuf;
121    ///
122    /// let path = Utf8PathBuf::new();
123    /// ```
124    #[must_use]
125    pub fn new() -> Utf8PathBuf {
126        Utf8PathBuf(PathBuf::new())
127    }
128
129    /// Creates a new [`Utf8PathBuf`] from a [`PathBuf`] containing valid UTF-8 characters.
130    ///
131    /// Errors with the original [`PathBuf`] if it is not valid UTF-8.
132    ///
133    /// For a version that returns a type that implements [`std::error::Error`],
134    /// see [`TryFrom<&PathBuf>`][tryfrom].
135    ///
136    /// [tryfrom]: #impl-TryFrom<PathBuf>-for-Utf8PathBuf
137    ///
138    /// # Examples
139    ///
140    /// ```
141    /// use camino::Utf8PathBuf;
142    /// use std::ffi::OsStr;
143    /// # #[cfg(unix)]
144    /// use std::os::unix::ffi::OsStrExt;
145    /// use std::path::PathBuf;
146    ///
147    /// let unicode_path = PathBuf::from("/valid/unicode");
148    /// Utf8PathBuf::from_path_buf(unicode_path).expect("valid Unicode path succeeded");
149    ///
150    /// // Paths on Unix can be non-UTF-8.
151    /// # #[cfg(unix)]
152    /// let non_unicode_str = OsStr::from_bytes(b"\xFF\xFF\xFF");
153    /// # #[cfg(unix)]
154    /// let non_unicode_path = PathBuf::from(non_unicode_str);
155    /// # #[cfg(unix)]
156    /// Utf8PathBuf::from_path_buf(non_unicode_path).expect_err("non-Unicode path failed");
157    /// ```
158    pub fn from_path_buf(path: PathBuf) -> Result<Utf8PathBuf, PathBuf> {
159        match path.into_os_string().into_string() {
160            Ok(string) => Ok(Utf8PathBuf::from(string)),
161            Err(os_string) => Err(PathBuf::from(os_string)),
162        }
163    }
164
165    /// Creates a new [`Utf8PathBuf`] from an [`OsString`] containing valid UTF-8 characters.
166    ///
167    /// Errors with the original [`OsString`] if it is not valid UTF-8.
168    ///
169    /// For a version that returns a type that implements [`std::error::Error`], use the
170    /// [`TryFrom<OsString>`] impl.
171    ///
172    /// [`TryFrom<OsString>`]: #impl-TryFrom<OsString>-for-Utf8PathBuf
173    ///
174    /// # Examples
175    ///
176    /// ```
177    /// # #[cfg(osstring_from_str)] {
178    /// use camino::Utf8PathBuf;
179    /// use std::ffi::OsStr;
180    /// use std::ffi::OsString;
181    /// use std::convert::TryFrom;
182    /// use std::str::FromStr;
183    /// # #[cfg(unix)]
184    /// use std::os::unix::ffi::OsStrExt;
185    ///
186    /// let unicode_string = OsString::from_str("/valid/unicode").unwrap();
187    /// Utf8PathBuf::from_os_string(unicode_string).expect("valid Unicode path succeeded");
188    ///
189    /// // Paths on Unix can be non-UTF-8.
190    /// # #[cfg(unix)]
191    /// let non_unicode_string = OsStr::from_bytes(b"\xFF\xFF\xFF").into();
192    /// # #[cfg(unix)]
193    /// Utf8PathBuf::from_os_string(non_unicode_string).expect_err("non-Unicode path failed");
194    /// # }
195    /// ```
196    pub fn from_os_string(os_string: OsString) -> Result<Utf8PathBuf, OsString> {
197        match os_string.into_string() {
198            Ok(string) => Ok(Utf8PathBuf::from(string)),
199            Err(os_string) => Err(os_string),
200        }
201    }
202
203    /// Converts a [`Utf8PathBuf`] to a [`PathBuf`].
204    ///
205    /// This is equivalent to the [`From<Utf8PathBuf> for PathBuf`][from] implementation,
206    /// but may aid in type inference.
207    ///
208    /// [from]: #impl-From<Utf8PathBuf>-for-PathBuf
209    ///
210    /// # Examples
211    ///
212    /// ```
213    /// use camino::Utf8PathBuf;
214    /// use std::path::PathBuf;
215    ///
216    /// let utf8_path_buf = Utf8PathBuf::from("foo.txt");
217    /// let std_path_buf = utf8_path_buf.into_std_path_buf();
218    /// assert_eq!(std_path_buf.to_str(), Some("foo.txt"));
219    ///
220    /// // Convert back to a Utf8PathBuf.
221    /// let new_utf8_path_buf = Utf8PathBuf::from_path_buf(std_path_buf).unwrap();
222    /// assert_eq!(new_utf8_path_buf, "foo.txt");
223    /// ```
224    #[must_use = "`self` will be dropped if the result is not used"]
225    pub fn into_std_path_buf(self) -> PathBuf {
226        self.into()
227    }
228
229    /// Creates a new [`Utf8PathBuf`] with a given capacity used to create the internal [`PathBuf`].
230    /// See [`with_capacity`] defined on [`PathBuf`].
231    ///
232    /// *Requires Rust 1.44 or newer.*
233    ///
234    /// # Examples
235    ///
236    /// ```
237    /// use camino::Utf8PathBuf;
238    ///
239    /// let mut path = Utf8PathBuf::with_capacity(10);
240    /// let capacity = path.capacity();
241    ///
242    /// // This push is done without reallocating
243    /// path.push(r"C:\");
244    ///
245    /// assert_eq!(capacity, path.capacity());
246    /// ```
247    ///
248    /// [`with_capacity`]: PathBuf::with_capacity
249    #[cfg(path_buf_capacity)]
250    #[allow(clippy::incompatible_msrv)]
251    #[must_use]
252    pub fn with_capacity(capacity: usize) -> Utf8PathBuf {
253        Utf8PathBuf(PathBuf::with_capacity(capacity))
254    }
255
256    /// Coerces to a [`Utf8Path`] slice.
257    ///
258    /// # Examples
259    ///
260    /// ```
261    /// use camino::{Utf8Path, Utf8PathBuf};
262    ///
263    /// let p = Utf8PathBuf::from("/test");
264    /// assert_eq!(Utf8Path::new("/test"), p.as_path());
265    /// ```
266    #[must_use]
267    pub fn as_path(&self) -> &Utf8Path {
268        // SAFETY: every Utf8PathBuf constructor ensures that self is valid UTF-8
269        unsafe { Utf8Path::assume_utf8(&self.0) }
270    }
271
272    /// Consumes and leaks the [`Utf8PathBuf`], returning a mutable reference to the contents,
273    /// `&'a mut Utf8Path`.
274    ///
275    /// The caller has free choice over the returned lifetime, including 'static.
276    /// Indeed, this function is ideally used for data that lives for the remainder of
277    /// the program’s life, as dropping the returned reference will cause a memory leak.
278    ///
279    /// It does not reallocate or shrink the [`Utf8PathBuf`], so the leaked allocation may include
280    /// unused capacity that is not part of the returned slice. If you want to discard excess
281    /// capacity, call [`into_boxed_path`], and then [`Box::leak`] instead.
282    /// However, keep in mind that trimming the capacity may result in a reallocation and copy.
283    ///
284    /// [`into_boxed_path`]: Self::into_boxed_path
285    #[cfg(os_string_pathbuf_leak)]
286    #[allow(clippy::incompatible_msrv)]
287    #[inline]
288    pub fn leak<'a>(self) -> &'a mut Utf8Path {
289        // SAFETY: every Utf8PathBuf constructor ensures that self is valid UTF-8
290        unsafe { Utf8Path::assume_utf8_mut(self.0.leak()) }
291    }
292
293    /// Extends `self` with `path`.
294    ///
295    /// If `path` is absolute, it replaces the current path.
296    ///
297    /// On Windows:
298    ///
299    /// * if `path` has a root but no prefix (e.g., `\windows`), it
300    ///   replaces everything except for the prefix (if any) of `self`.
301    /// * if `path` has a prefix but no root, it replaces `self`.
302    ///
303    /// # Examples
304    ///
305    /// Pushing a relative path extends the existing path:
306    ///
307    /// ```
308    /// use camino::Utf8PathBuf;
309    ///
310    /// let mut path = Utf8PathBuf::from("/tmp");
311    /// path.push("file.bk");
312    /// assert_eq!(path, Utf8PathBuf::from("/tmp/file.bk"));
313    /// ```
314    ///
315    /// Pushing an absolute path replaces the existing path:
316    ///
317    /// ```
318    /// use camino::Utf8PathBuf;
319    ///
320    /// let mut path = Utf8PathBuf::from("/tmp");
321    /// path.push("/etc");
322    /// assert_eq!(path, Utf8PathBuf::from("/etc"));
323    /// ```
324    pub fn push(&mut self, path: impl AsRef<Utf8Path>) {
325        self.0.push(&path.as_ref().0)
326    }
327
328    /// Truncates `self` to [`self.parent`].
329    ///
330    /// Returns `false` and does nothing if [`self.parent`] is [`None`].
331    /// Otherwise, returns `true`.
332    ///
333    /// [`self.parent`]: Utf8Path::parent
334    ///
335    /// # Examples
336    ///
337    /// ```
338    /// use camino::{Utf8Path, Utf8PathBuf};
339    ///
340    /// let mut p = Utf8PathBuf::from("/spirited/away.rs");
341    ///
342    /// p.pop();
343    /// assert_eq!(Utf8Path::new("/spirited"), p);
344    /// p.pop();
345    /// assert_eq!(Utf8Path::new("/"), p);
346    /// ```
347    pub fn pop(&mut self) -> bool {
348        self.0.pop()
349    }
350
351    /// Updates [`self.file_name`] to `file_name`.
352    ///
353    /// If [`self.file_name`] was [`None`], this is equivalent to pushing
354    /// `file_name`.
355    ///
356    /// Otherwise it is equivalent to calling [`pop`] and then pushing
357    /// `file_name`. The new path will be a sibling of the original path.
358    /// (That is, it will have the same parent.)
359    ///
360    /// [`self.file_name`]: Utf8Path::file_name
361    /// [`pop`]: Utf8PathBuf::pop
362    ///
363    /// # Examples
364    ///
365    /// ```
366    /// use camino::Utf8PathBuf;
367    ///
368    /// let mut buf = Utf8PathBuf::from("/");
369    /// assert_eq!(buf.file_name(), None);
370    /// buf.set_file_name("bar");
371    /// assert_eq!(buf, Utf8PathBuf::from("/bar"));
372    /// assert!(buf.file_name().is_some());
373    /// buf.set_file_name("baz.txt");
374    /// assert_eq!(buf, Utf8PathBuf::from("/baz.txt"));
375    /// ```
376    pub fn set_file_name(&mut self, file_name: impl AsRef<str>) {
377        self.0.set_file_name(file_name.as_ref())
378    }
379
380    /// Updates [`self.extension`] to `extension`.
381    ///
382    /// Returns `false` and does nothing if [`self.file_name`] is [`None`],
383    /// returns `true` and updates the extension otherwise.
384    ///
385    /// If [`self.extension`] is [`None`], the extension is added; otherwise
386    /// it is replaced.
387    ///
388    /// [`self.file_name`]: Utf8Path::file_name
389    /// [`self.extension`]: Utf8Path::extension
390    ///
391    /// # Examples
392    ///
393    /// ```
394    /// use camino::{Utf8Path, Utf8PathBuf};
395    ///
396    /// let mut p = Utf8PathBuf::from("/feel/the");
397    ///
398    /// p.set_extension("force");
399    /// assert_eq!(Utf8Path::new("/feel/the.force"), p.as_path());
400    ///
401    /// p.set_extension("dark_side");
402    /// assert_eq!(Utf8Path::new("/feel/the.dark_side"), p.as_path());
403    /// ```
404    pub fn set_extension(&mut self, extension: impl AsRef<str>) -> bool {
405        self.0.set_extension(extension.as_ref())
406    }
407
408    /// Consumes the [`Utf8PathBuf`], yielding its internal [`String`] storage.
409    ///
410    /// # Examples
411    ///
412    /// ```
413    /// use camino::Utf8PathBuf;
414    ///
415    /// let p = Utf8PathBuf::from("/the/head");
416    /// let s = p.into_string();
417    /// assert_eq!(s, "/the/head");
418    /// ```
419    #[must_use = "`self` will be dropped if the result is not used"]
420    pub fn into_string(self) -> String {
421        self.into_os_string().into_string().unwrap()
422    }
423
424    /// Consumes the [`Utf8PathBuf`], yielding its internal [`OsString`] storage.
425    ///
426    /// # Examples
427    ///
428    /// ```
429    /// use camino::Utf8PathBuf;
430    /// use std::ffi::OsStr;
431    ///
432    /// let p = Utf8PathBuf::from("/the/head");
433    /// let s = p.into_os_string();
434    /// assert_eq!(s, OsStr::new("/the/head"));
435    /// ```
436    #[must_use = "`self` will be dropped if the result is not used"]
437    pub fn into_os_string(self) -> OsString {
438        self.0.into_os_string()
439    }
440
441    /// Converts this [`Utf8PathBuf`] into a [boxed](Box) [`Utf8Path`].
442    #[must_use = "`self` will be dropped if the result is not used"]
443    pub fn into_boxed_path(self) -> Box<Utf8Path> {
444        let ptr = Box::into_raw(self.0.into_boxed_path()) as *mut Utf8Path;
445        // SAFETY:
446        // * self is valid UTF-8
447        // * ptr was constructed by consuming self so it represents an owned path
448        // * Utf8Path is marked as #[repr(transparent)] so the conversion from *mut Path to
449        //   *mut Utf8Path is valid
450        unsafe { Box::from_raw(ptr) }
451    }
452
453    /// Invokes [`capacity`] on the underlying instance of [`PathBuf`].
454    ///
455    /// *Requires Rust 1.44 or newer.*
456    ///
457    /// [`capacity`]: PathBuf::capacity
458    #[cfg(path_buf_capacity)]
459    #[allow(clippy::incompatible_msrv)]
460    #[must_use]
461    pub fn capacity(&self) -> usize {
462        self.0.capacity()
463    }
464
465    /// Invokes [`clear`] on the underlying instance of [`PathBuf`].
466    ///
467    /// *Requires Rust 1.44 or newer.*
468    ///
469    /// [`clear`]: PathBuf::clear
470    #[cfg(path_buf_capacity)]
471    #[allow(clippy::incompatible_msrv)]
472    pub fn clear(&mut self) {
473        self.0.clear()
474    }
475
476    /// Invokes [`reserve`] on the underlying instance of [`PathBuf`].
477    ///
478    /// *Requires Rust 1.44 or newer.*
479    ///
480    /// [`reserve`]: PathBuf::reserve
481    #[cfg(path_buf_capacity)]
482    #[allow(clippy::incompatible_msrv)]
483    pub fn reserve(&mut self, additional: usize) {
484        self.0.reserve(additional)
485    }
486
487    /// Invokes [`try_reserve`] on the underlying instance of [`PathBuf`].
488    ///
489    /// *Requires Rust 1.63 or newer.*
490    ///
491    /// [`try_reserve`]: PathBuf::try_reserve
492    #[cfg(try_reserve_2)]
493    #[allow(clippy::incompatible_msrv)]
494    #[inline]
495    pub fn try_reserve(
496        &mut self,
497        additional: usize,
498    ) -> Result<(), std::collections::TryReserveError> {
499        self.0.try_reserve(additional)
500    }
501
502    /// Invokes [`reserve_exact`] on the underlying instance of [`PathBuf`].
503    ///
504    /// *Requires Rust 1.44 or newer.*
505    ///
506    /// [`reserve_exact`]: PathBuf::reserve_exact
507    #[cfg(path_buf_capacity)]
508    #[allow(clippy::incompatible_msrv)]
509    pub fn reserve_exact(&mut self, additional: usize) {
510        self.0.reserve_exact(additional)
511    }
512
513    /// Invokes [`try_reserve_exact`] on the underlying instance of [`PathBuf`].
514    ///
515    /// *Requires Rust 1.63 or newer.*
516    ///
517    /// [`try_reserve_exact`]: PathBuf::try_reserve_exact
518    #[cfg(try_reserve_2)]
519    #[allow(clippy::incompatible_msrv)]
520    #[inline]
521    pub fn try_reserve_exact(
522        &mut self,
523        additional: usize,
524    ) -> Result<(), std::collections::TryReserveError> {
525        self.0.try_reserve_exact(additional)
526    }
527
528    /// Invokes [`shrink_to_fit`] on the underlying instance of [`PathBuf`].
529    ///
530    /// *Requires Rust 1.44 or newer.*
531    ///
532    /// [`shrink_to_fit`]: PathBuf::shrink_to_fit
533    #[cfg(path_buf_capacity)]
534    #[allow(clippy::incompatible_msrv)]
535    pub fn shrink_to_fit(&mut self) {
536        self.0.shrink_to_fit()
537    }
538
539    /// Invokes [`shrink_to`] on the underlying instance of [`PathBuf`].
540    ///
541    /// *Requires Rust 1.56 or newer.*
542    ///
543    /// [`shrink_to`]: PathBuf::shrink_to
544    #[cfg(shrink_to)]
545    #[allow(clippy::incompatible_msrv)]
546    #[inline]
547    pub fn shrink_to(&mut self, min_capacity: usize) {
548        self.0.shrink_to(min_capacity)
549    }
550}
551
552impl Deref for Utf8PathBuf {
553    type Target = Utf8Path;
554
555    fn deref(&self) -> &Utf8Path {
556        self.as_path()
557    }
558}
559
560/// *Requires Rust 1.68 or newer.*
561#[cfg(path_buf_deref_mut)]
562#[allow(clippy::incompatible_msrv)]
563impl std::ops::DerefMut for Utf8PathBuf {
564    fn deref_mut(&mut self) -> &mut Self::Target {
565        unsafe { Utf8Path::assume_utf8_mut(&mut self.0) }
566    }
567}
568
569impl fmt::Debug for Utf8PathBuf {
570    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
571        fmt::Debug::fmt(&**self, f)
572    }
573}
574
575impl fmt::Display for Utf8PathBuf {
576    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
577        fmt::Display::fmt(self.as_str(), f)
578    }
579}
580
581impl<P: AsRef<Utf8Path>> Extend<P> for Utf8PathBuf {
582    fn extend<I: IntoIterator<Item = P>>(&mut self, iter: I) {
583        for path in iter {
584            self.push(path);
585        }
586    }
587}
588
589/// A slice of a UTF-8 path (akin to [`str`]).
590///
591/// This type supports a number of operations for inspecting a path, including
592/// breaking the path into its components (separated by `/` on Unix and by either
593/// `/` or `\` on Windows), extracting the file name, determining whether the path
594/// is absolute, and so on.
595///
596/// This is an *unsized* type, meaning that it must always be used behind a
597/// pointer like `&` or [`Box`]. For an owned version of this type,
598/// see [`Utf8PathBuf`].
599///
600/// # Examples
601///
602/// ```
603/// use camino::Utf8Path;
604///
605/// // Note: this example does work on Windows
606/// let path = Utf8Path::new("./foo/bar.txt");
607///
608/// let parent = path.parent();
609/// assert_eq!(parent, Some(Utf8Path::new("./foo")));
610///
611/// let file_stem = path.file_stem();
612/// assert_eq!(file_stem, Some("bar"));
613///
614/// let extension = path.extension();
615/// assert_eq!(extension, Some("txt"));
616/// ```
617// NB: Internal Path must only contain utf8 data
618#[repr(transparent)]
619pub struct Utf8Path(Path);
620
621impl Utf8Path {
622    /// Directly wraps a string slice as a [`Utf8Path`] slice.
623    ///
624    /// This is a cost-free conversion.
625    ///
626    /// # Examples
627    ///
628    /// ```
629    /// use camino::Utf8Path;
630    ///
631    /// Utf8Path::new("foo.txt");
632    /// ```
633    ///
634    /// You can create [`Utf8Path`]s from [`String`]s, or even other [`Utf8Path`]s:
635    ///
636    /// ```
637    /// use camino::Utf8Path;
638    ///
639    /// let string = String::from("foo.txt");
640    /// let from_string = Utf8Path::new(&string);
641    /// let from_path = Utf8Path::new(&from_string);
642    /// assert_eq!(from_string, from_path);
643    /// ```
644    pub fn new(s: &(impl AsRef<str> + ?Sized)) -> &Utf8Path {
645        let path = Path::new(s.as_ref());
646        // SAFETY: s is a str which means it is always valid UTF-8
647        unsafe { Utf8Path::assume_utf8(path) }
648    }
649
650    /// Converts a [`Path`] to a [`Utf8Path`].
651    ///
652    /// Returns [`None`] if the path is not valid UTF-8.
653    ///
654    /// For a version that returns a type that implements [`std::error::Error`],
655    /// see [`TryFrom<&Path>`][tryfrom].
656    ///
657    /// [tryfrom]: #impl-TryFrom<%26Path>-for-%26Utf8Path
658    ///
659    /// # Examples
660    ///
661    /// ```
662    /// use camino::Utf8Path;
663    /// use std::ffi::OsStr;
664    /// # #[cfg(unix)]
665    /// use std::os::unix::ffi::OsStrExt;
666    /// use std::path::Path;
667    ///
668    /// let unicode_path = Path::new("/valid/unicode");
669    /// Utf8Path::from_path(unicode_path).expect("valid Unicode path succeeded");
670    ///
671    /// // Paths on Unix can be non-UTF-8.
672    /// # #[cfg(unix)]
673    /// let non_unicode_str = OsStr::from_bytes(b"\xFF\xFF\xFF");
674    /// # #[cfg(unix)]
675    /// let non_unicode_path = Path::new(non_unicode_str);
676    /// # #[cfg(unix)]
677    /// assert!(Utf8Path::from_path(non_unicode_path).is_none(), "non-Unicode path failed");
678    /// ```
679    pub fn from_path(path: &Path) -> Option<&Utf8Path> {
680        path.as_os_str().to_str().map(Utf8Path::new)
681    }
682
683    /// Converts an [`OsStr`] to a [`Utf8Path`].
684    ///
685    /// Returns [`None`] if the path is not valid UTF-8.
686    ///
687    /// For a version that returns a type that implements [`std::error::Error`], use the
688    /// [`TryFrom<&OsStr>`][tryfrom] impl.
689    ///
690    /// [tryfrom]: #impl-TryFrom<%26OsStr>-for-%26Utf8Path
691    ///
692    /// # Examples
693    ///
694    /// ```
695    /// use camino::Utf8Path;
696    /// use std::ffi::OsStr;
697    /// # #[cfg(unix)]
698    /// use std::os::unix::ffi::OsStrExt;
699    /// use std::path::Path;
700    ///
701    /// let unicode_string = OsStr::new("/valid/unicode");
702    /// Utf8Path::from_os_str(unicode_string).expect("valid Unicode string succeeded");
703    ///
704    /// // Paths on Unix can be non-UTF-8.
705    /// # #[cfg(unix)]
706    /// let non_unicode_str = OsStr::from_bytes(b"\xFF\xFF\xFF");
707    /// # #[cfg(unix)]
708    /// assert!(Utf8Path::from_os_str(non_unicode_str).is_none(), "non-Unicode string failed");
709    /// ```
710    pub fn from_os_str(path: &OsStr) -> Option<&Utf8Path> {
711        path.to_str().map(Utf8Path::new)
712    }
713
714    /// Converts a [`Utf8Path`] to a [`Path`].
715    ///
716    /// This is equivalent to the [`AsRef<Path> for Utf8PathBuf`][asref] implementation,
717    /// but may aid in type inference.
718    ///
719    /// [asref]: Utf8PathBuf#impl-AsRef<Path>-for-Utf8PathBuf
720    ///
721    /// # Examples
722    ///
723    /// ```
724    /// use camino::Utf8Path;
725    /// use std::path::Path;
726    ///
727    /// let utf8_path = Utf8Path::new("foo.txt");
728    /// let std_path: &Path = utf8_path.as_std_path();
729    /// assert_eq!(std_path.to_str(), Some("foo.txt"));
730    ///
731    /// // Convert back to a Utf8Path.
732    /// let new_utf8_path = Utf8Path::from_path(std_path).unwrap();
733    /// assert_eq!(new_utf8_path, "foo.txt");
734    /// ```
735    #[inline]
736    pub fn as_std_path(&self) -> &Path {
737        self.as_ref()
738    }
739
740    /// Yields the underlying [`str`] slice.
741    ///
742    /// Unlike [`Path::to_str`], this always returns a slice because the contents
743    /// of a [`Utf8Path`] are guaranteed to be valid UTF-8.
744    ///
745    /// # Examples
746    ///
747    /// ```
748    /// use camino::Utf8Path;
749    ///
750    /// let s = Utf8Path::new("foo.txt").as_str();
751    /// assert_eq!(s, "foo.txt");
752    /// ```
753    ///
754    /// [`str`]: str
755    #[inline]
756    #[must_use]
757    pub fn as_str(&self) -> &str {
758        // SAFETY: every Utf8Path constructor ensures that self is valid UTF-8
759        unsafe { str_assume_utf8(self.as_os_str()) }
760    }
761
762    /// Yields the underlying [`OsStr`] slice.
763    ///
764    /// # Examples
765    ///
766    /// ```
767    /// use camino::Utf8Path;
768    ///
769    /// let os_str = Utf8Path::new("foo.txt").as_os_str();
770    /// assert_eq!(os_str, std::ffi::OsStr::new("foo.txt"));
771    /// ```
772    #[inline]
773    #[must_use]
774    pub fn as_os_str(&self) -> &OsStr {
775        self.0.as_os_str()
776    }
777
778    /// Converts a [`Utf8Path`] to an owned [`Utf8PathBuf`].
779    ///
780    /// # Examples
781    ///
782    /// ```
783    /// use camino::{Utf8Path, Utf8PathBuf};
784    ///
785    /// let path_buf = Utf8Path::new("foo.txt").to_path_buf();
786    /// assert_eq!(path_buf, Utf8PathBuf::from("foo.txt"));
787    /// ```
788    #[inline]
789    #[must_use = "this returns the result of the operation, \
790                  without modifying the original"]
791    pub fn to_path_buf(&self) -> Utf8PathBuf {
792        Utf8PathBuf(self.0.to_path_buf())
793    }
794
795    /// Returns `true` if the [`Utf8Path`] is absolute, i.e., if it is independent of
796    /// the current directory.
797    ///
798    /// * On Unix, a path is absolute if it starts with the root, so
799    ///   `is_absolute` and [`has_root`] are equivalent.
800    ///
801    /// * On Windows, a path is absolute if it has a prefix and starts with the
802    ///   root: `C:\windows` is absolute, while `C:temp` and `\temp` are not.
803    ///
804    /// # Examples
805    ///
806    /// ```
807    /// use camino::Utf8Path;
808    ///
809    /// assert!(!Utf8Path::new("foo.txt").is_absolute());
810    /// ```
811    ///
812    /// [`has_root`]: Utf8Path::has_root
813    #[inline]
814    #[must_use]
815    pub fn is_absolute(&self) -> bool {
816        self.0.is_absolute()
817    }
818
819    /// Returns `true` if the [`Utf8Path`] is relative, i.e., not absolute.
820    ///
821    /// See [`is_absolute`]'s documentation for more details.
822    ///
823    /// # Examples
824    ///
825    /// ```
826    /// use camino::Utf8Path;
827    ///
828    /// assert!(Utf8Path::new("foo.txt").is_relative());
829    /// ```
830    ///
831    /// [`is_absolute`]: Utf8Path::is_absolute
832    #[inline]
833    #[must_use]
834    pub fn is_relative(&self) -> bool {
835        self.0.is_relative()
836    }
837
838    /// Returns `true` if the [`Utf8Path`] has a root.
839    ///
840    /// * On Unix, a path has a root if it begins with `/`.
841    ///
842    /// * On Windows, a path has a root if it:
843    ///     * has no prefix and begins with a separator, e.g., `\windows`
844    ///     * has a prefix followed by a separator, e.g., `C:\windows` but not `C:windows`
845    ///     * has any non-disk prefix, e.g., `\\server\share`
846    ///
847    /// # Examples
848    ///
849    /// ```
850    /// use camino::Utf8Path;
851    ///
852    /// assert!(Utf8Path::new("/etc/passwd").has_root());
853    /// ```
854    #[inline]
855    #[must_use]
856    pub fn has_root(&self) -> bool {
857        self.0.has_root()
858    }
859
860    /// Returns the [`Path`] without its final component, if there is one.
861    ///
862    /// Returns [`None`] if the path terminates in a root or prefix.
863    ///
864    /// # Examples
865    ///
866    /// ```
867    /// use camino::Utf8Path;
868    ///
869    /// let path = Utf8Path::new("/foo/bar");
870    /// let parent = path.parent().unwrap();
871    /// assert_eq!(parent, Utf8Path::new("/foo"));
872    ///
873    /// let grand_parent = parent.parent().unwrap();
874    /// assert_eq!(grand_parent, Utf8Path::new("/"));
875    /// assert_eq!(grand_parent.parent(), None);
876    /// ```
877    #[inline]
878    #[must_use]
879    pub fn parent(&self) -> Option<&Utf8Path> {
880        self.0.parent().map(|path| {
881            // SAFETY: self is valid UTF-8, so parent is valid UTF-8 as well
882            unsafe { Utf8Path::assume_utf8(path) }
883        })
884    }
885
886    /// Produces an iterator over [`Utf8Path`] and its ancestors.
887    ///
888    /// The iterator will yield the [`Utf8Path`] that is returned if the [`parent`] method is used zero
889    /// or more times. That means, the iterator will yield `&self`, `&self.parent().unwrap()`,
890    /// `&self.parent().unwrap().parent().unwrap()` and so on. If the [`parent`] method returns
891    /// [`None`], the iterator will do likewise. The iterator will always yield at least one value,
892    /// namely `&self`.
893    ///
894    /// # Examples
895    ///
896    /// ```
897    /// use camino::Utf8Path;
898    ///
899    /// let mut ancestors = Utf8Path::new("/foo/bar").ancestors();
900    /// assert_eq!(ancestors.next(), Some(Utf8Path::new("/foo/bar")));
901    /// assert_eq!(ancestors.next(), Some(Utf8Path::new("/foo")));
902    /// assert_eq!(ancestors.next(), Some(Utf8Path::new("/")));
903    /// assert_eq!(ancestors.next(), None);
904    ///
905    /// let mut ancestors = Utf8Path::new("../foo/bar").ancestors();
906    /// assert_eq!(ancestors.next(), Some(Utf8Path::new("../foo/bar")));
907    /// assert_eq!(ancestors.next(), Some(Utf8Path::new("../foo")));
908    /// assert_eq!(ancestors.next(), Some(Utf8Path::new("..")));
909    /// assert_eq!(ancestors.next(), Some(Utf8Path::new("")));
910    /// assert_eq!(ancestors.next(), None);
911    /// ```
912    ///
913    /// [`parent`]: Utf8Path::parent
914    #[inline]
915    pub fn ancestors(&self) -> Utf8Ancestors<'_> {
916        Utf8Ancestors(self.0.ancestors())
917    }
918
919    /// Returns the final component of the [`Utf8Path`], if there is one.
920    ///
921    /// If the path is a normal file, this is the file name. If it's the path of a directory, this
922    /// is the directory name.
923    ///
924    /// Returns [`None`] if the path terminates in `..`.
925    ///
926    /// # Examples
927    ///
928    /// ```
929    /// use camino::Utf8Path;
930    ///
931    /// assert_eq!(Some("bin"), Utf8Path::new("/usr/bin/").file_name());
932    /// assert_eq!(Some("foo.txt"), Utf8Path::new("tmp/foo.txt").file_name());
933    /// assert_eq!(Some("foo.txt"), Utf8Path::new("foo.txt/.").file_name());
934    /// assert_eq!(Some("foo.txt"), Utf8Path::new("foo.txt/.//").file_name());
935    /// assert_eq!(None, Utf8Path::new("foo.txt/..").file_name());
936    /// assert_eq!(None, Utf8Path::new("/").file_name());
937    /// ```
938    #[inline]
939    #[must_use]
940    pub fn file_name(&self) -> Option<&str> {
941        self.0.file_name().map(|s| {
942            // SAFETY: self is valid UTF-8, so file_name is valid UTF-8 as well
943            unsafe { str_assume_utf8(s) }
944        })
945    }
946
947    /// Returns a path that, when joined onto `base`, yields `self`.
948    ///
949    /// # Errors
950    ///
951    /// If `base` is not a prefix of `self` (i.e., [`starts_with`]
952    /// returns `false`), returns [`Err`].
953    ///
954    /// [`starts_with`]: Utf8Path::starts_with
955    ///
956    /// # Examples
957    ///
958    /// ```
959    /// use camino::{Utf8Path, Utf8PathBuf};
960    ///
961    /// let path = Utf8Path::new("/test/haha/foo.txt");
962    ///
963    /// assert_eq!(path.strip_prefix("/"), Ok(Utf8Path::new("test/haha/foo.txt")));
964    /// assert_eq!(path.strip_prefix("/test"), Ok(Utf8Path::new("haha/foo.txt")));
965    /// assert_eq!(path.strip_prefix("/test/"), Ok(Utf8Path::new("haha/foo.txt")));
966    /// assert_eq!(path.strip_prefix("/test/haha/foo.txt"), Ok(Utf8Path::new("")));
967    /// assert_eq!(path.strip_prefix("/test/haha/foo.txt/"), Ok(Utf8Path::new("")));
968    ///
969    /// assert!(path.strip_prefix("test").is_err());
970    /// assert!(path.strip_prefix("/haha").is_err());
971    ///
972    /// let prefix = Utf8PathBuf::from("/test/");
973    /// assert_eq!(path.strip_prefix(prefix), Ok(Utf8Path::new("haha/foo.txt")));
974    /// ```
975    #[inline]
976    pub fn strip_prefix(&self, base: impl AsRef<Path>) -> Result<&Utf8Path, StripPrefixError> {
977        self.0.strip_prefix(base).map(|path| {
978            // SAFETY: self is valid UTF-8, and strip_prefix returns a part of self (or an empty
979            // string), so it is valid UTF-8 as well.
980            unsafe { Utf8Path::assume_utf8(path) }
981        })
982    }
983
984    /// Determines whether `base` is a prefix of `self`.
985    ///
986    /// Only considers whole path components to match.
987    ///
988    /// # Examples
989    ///
990    /// ```
991    /// use camino::Utf8Path;
992    ///
993    /// let path = Utf8Path::new("/etc/passwd");
994    ///
995    /// assert!(path.starts_with("/etc"));
996    /// assert!(path.starts_with("/etc/"));
997    /// assert!(path.starts_with("/etc/passwd"));
998    /// assert!(path.starts_with("/etc/passwd/")); // extra slash is okay
999    /// assert!(path.starts_with("/etc/passwd///")); // multiple extra slashes are okay
1000    ///
1001    /// assert!(!path.starts_with("/e"));
1002    /// assert!(!path.starts_with("/etc/passwd.txt"));
1003    ///
1004    /// assert!(!Utf8Path::new("/etc/foo.rs").starts_with("/etc/foo"));
1005    /// ```
1006    #[inline]
1007    #[must_use]
1008    pub fn starts_with(&self, base: impl AsRef<Path>) -> bool {
1009        self.0.starts_with(base)
1010    }
1011
1012    /// Determines whether `child` is a suffix of `self`.
1013    ///
1014    /// Only considers whole path components to match.
1015    ///
1016    /// # Examples
1017    ///
1018    /// ```
1019    /// use camino::Utf8Path;
1020    ///
1021    /// let path = Utf8Path::new("/etc/resolv.conf");
1022    ///
1023    /// assert!(path.ends_with("resolv.conf"));
1024    /// assert!(path.ends_with("etc/resolv.conf"));
1025    /// assert!(path.ends_with("/etc/resolv.conf"));
1026    ///
1027    /// assert!(!path.ends_with("/resolv.conf"));
1028    /// assert!(!path.ends_with("conf")); // use .extension() instead
1029    /// ```
1030    #[inline]
1031    #[must_use]
1032    pub fn ends_with(&self, base: impl AsRef<Path>) -> bool {
1033        self.0.ends_with(base)
1034    }
1035
1036    /// Extracts the stem (non-extension) portion of [`self.file_name`].
1037    ///
1038    /// [`self.file_name`]: Utf8Path::file_name
1039    ///
1040    /// The stem is:
1041    ///
1042    /// * [`None`], if there is no file name;
1043    /// * The entire file name if there is no embedded `.`;
1044    /// * The entire file name if the file name begins with `.` and has no other `.`s within;
1045    /// * Otherwise, the portion of the file name before the final `.`
1046    ///
1047    /// # Examples
1048    ///
1049    /// ```
1050    /// use camino::Utf8Path;
1051    ///
1052    /// assert_eq!("foo", Utf8Path::new("foo.rs").file_stem().unwrap());
1053    /// assert_eq!("foo.tar", Utf8Path::new("foo.tar.gz").file_stem().unwrap());
1054    /// ```
1055    #[inline]
1056    #[must_use]
1057    pub fn file_stem(&self) -> Option<&str> {
1058        self.0.file_stem().map(|s| {
1059            // SAFETY: self is valid UTF-8, so file_stem is valid UTF-8 as well
1060            unsafe { str_assume_utf8(s) }
1061        })
1062    }
1063
1064    /// Extracts the extension of [`self.file_name`], if possible.
1065    ///
1066    /// The extension is:
1067    ///
1068    /// * [`None`], if there is no file name;
1069    /// * [`None`], if there is no embedded `.`;
1070    /// * [`None`], if the file name begins with `.` and has no other `.`s within;
1071    /// * Otherwise, the portion of the file name after the final `.`
1072    ///
1073    /// [`self.file_name`]: Utf8Path::file_name
1074    ///
1075    /// # Examples
1076    ///
1077    /// ```
1078    /// use camino::Utf8Path;
1079    ///
1080    /// assert_eq!("rs", Utf8Path::new("foo.rs").extension().unwrap());
1081    /// assert_eq!("gz", Utf8Path::new("foo.tar.gz").extension().unwrap());
1082    /// ```
1083    #[inline]
1084    #[must_use]
1085    pub fn extension(&self) -> Option<&str> {
1086        self.0.extension().map(|s| {
1087            // SAFETY: self is valid UTF-8, so extension is valid UTF-8 as well
1088            unsafe { str_assume_utf8(s) }
1089        })
1090    }
1091
1092    /// Creates an owned [`Utf8PathBuf`] with `path` adjoined to `self`.
1093    ///
1094    /// See [`Utf8PathBuf::push`] for more details on what it means to adjoin a path.
1095    ///
1096    /// # Examples
1097    ///
1098    /// ```
1099    /// use camino::{Utf8Path, Utf8PathBuf};
1100    ///
1101    /// assert_eq!(Utf8Path::new("/etc").join("passwd"), Utf8PathBuf::from("/etc/passwd"));
1102    /// ```
1103    #[inline]
1104    #[must_use]
1105    pub fn join(&self, path: impl AsRef<Utf8Path>) -> Utf8PathBuf {
1106        Utf8PathBuf(self.0.join(&path.as_ref().0))
1107    }
1108
1109    /// Creates an owned [`PathBuf`] with `path` adjoined to `self`.
1110    ///
1111    /// See [`PathBuf::push`] for more details on what it means to adjoin a path.
1112    ///
1113    /// # Examples
1114    ///
1115    /// ```
1116    /// use camino::Utf8Path;
1117    /// use std::path::PathBuf;
1118    ///
1119    /// assert_eq!(Utf8Path::new("/etc").join_os("passwd"), PathBuf::from("/etc/passwd"));
1120    /// ```
1121    #[inline]
1122    #[must_use]
1123    pub fn join_os(&self, path: impl AsRef<Path>) -> PathBuf {
1124        self.0.join(path)
1125    }
1126
1127    /// Creates an owned [`Utf8PathBuf`] like `self` but with the given file name.
1128    ///
1129    /// See [`Utf8PathBuf::set_file_name`] for more details.
1130    ///
1131    /// # Examples
1132    ///
1133    /// ```
1134    /// use camino::{Utf8Path, Utf8PathBuf};
1135    ///
1136    /// let path = Utf8Path::new("/tmp/foo.txt");
1137    /// assert_eq!(path.with_file_name("bar.txt"), Utf8PathBuf::from("/tmp/bar.txt"));
1138    ///
1139    /// let path = Utf8Path::new("/tmp");
1140    /// assert_eq!(path.with_file_name("var"), Utf8PathBuf::from("/var"));
1141    /// ```
1142    #[inline]
1143    #[must_use]
1144    pub fn with_file_name(&self, file_name: impl AsRef<str>) -> Utf8PathBuf {
1145        Utf8PathBuf(self.0.with_file_name(file_name.as_ref()))
1146    }
1147
1148    /// Creates an owned [`Utf8PathBuf`] like `self` but with the given extension.
1149    ///
1150    /// See [`Utf8PathBuf::set_extension`] for more details.
1151    ///
1152    /// # Examples
1153    ///
1154    /// ```
1155    /// use camino::{Utf8Path, Utf8PathBuf};
1156    ///
1157    /// let path = Utf8Path::new("foo.rs");
1158    /// assert_eq!(path.with_extension("txt"), Utf8PathBuf::from("foo.txt"));
1159    ///
1160    /// let path = Utf8Path::new("foo.tar.gz");
1161    /// assert_eq!(path.with_extension(""), Utf8PathBuf::from("foo.tar"));
1162    /// assert_eq!(path.with_extension("xz"), Utf8PathBuf::from("foo.tar.xz"));
1163    /// assert_eq!(path.with_extension("").with_extension("txt"), Utf8PathBuf::from("foo.txt"));
1164    /// ```
1165    #[inline]
1166    pub fn with_extension(&self, extension: impl AsRef<str>) -> Utf8PathBuf {
1167        Utf8PathBuf(self.0.with_extension(extension.as_ref()))
1168    }
1169
1170    /// Produces an iterator over the [`Utf8Component`]s of the path.
1171    ///
1172    /// When parsing the path, there is a small amount of normalization:
1173    ///
1174    /// * Repeated separators are ignored, so `a/b` and `a//b` both have
1175    ///   `a` and `b` as components.
1176    ///
1177    /// * Occurrences of `.` are normalized away, except if they are at the
1178    ///   beginning of the path. For example, `a/./b`, `a/b/`, `a/b/.` and
1179    ///   `a/b` all have `a` and `b` as components, but `./a/b` starts with
1180    ///   an additional [`CurDir`] component.
1181    ///
1182    /// * A trailing slash is normalized away, `/a/b` and `/a/b/` are equivalent.
1183    ///
1184    /// Note that no other normalization takes place; in particular, `a/c`
1185    /// and `a/b/../c` are distinct, to account for the possibility that `b`
1186    /// is a symbolic link (so its parent isn't `a`).
1187    ///
1188    /// # Examples
1189    ///
1190    /// ```
1191    /// use camino::{Utf8Component, Utf8Path};
1192    ///
1193    /// let mut components = Utf8Path::new("/tmp/foo.txt").components();
1194    ///
1195    /// assert_eq!(components.next(), Some(Utf8Component::RootDir));
1196    /// assert_eq!(components.next(), Some(Utf8Component::Normal("tmp")));
1197    /// assert_eq!(components.next(), Some(Utf8Component::Normal("foo.txt")));
1198    /// assert_eq!(components.next(), None)
1199    /// ```
1200    ///
1201    /// [`CurDir`]: Utf8Component::CurDir
1202    #[inline]
1203    pub fn components(&self) -> Utf8Components<'_> {
1204        Utf8Components(self.0.components())
1205    }
1206
1207    /// Produces an iterator over the path's components viewed as [`str`]
1208    /// slices.
1209    ///
1210    /// For more information about the particulars of how the path is separated
1211    /// into components, see [`components`].
1212    ///
1213    /// [`components`]: Utf8Path::components
1214    ///
1215    /// # Examples
1216    ///
1217    /// ```
1218    /// use camino::Utf8Path;
1219    ///
1220    /// let mut it = Utf8Path::new("/tmp/foo.txt").iter();
1221    /// assert_eq!(it.next(), Some(std::path::MAIN_SEPARATOR.to_string().as_str()));
1222    /// assert_eq!(it.next(), Some("tmp"));
1223    /// assert_eq!(it.next(), Some("foo.txt"));
1224    /// assert_eq!(it.next(), None)
1225    /// ```
1226    #[inline]
1227    pub fn iter(&self) -> Iter<'_> {
1228        Iter {
1229            inner: self.components(),
1230        }
1231    }
1232
1233    /// Queries the file system to get information about a file, directory, etc.
1234    ///
1235    /// This function will traverse symbolic links to query information about the
1236    /// destination file.
1237    ///
1238    /// This is an alias to [`fs::metadata`].
1239    ///
1240    /// # Examples
1241    ///
1242    /// ```no_run
1243    /// use camino::Utf8Path;
1244    ///
1245    /// let path = Utf8Path::new("/Minas/tirith");
1246    /// let metadata = path.metadata().expect("metadata call failed");
1247    /// println!("{:?}", metadata.file_type());
1248    /// ```
1249    #[inline]
1250    pub fn metadata(&self) -> io::Result<fs::Metadata> {
1251        self.0.metadata()
1252    }
1253
1254    /// Queries the metadata about a file without following symlinks.
1255    ///
1256    /// This is an alias to [`fs::symlink_metadata`].
1257    ///
1258    /// # Examples
1259    ///
1260    /// ```no_run
1261    /// use camino::Utf8Path;
1262    ///
1263    /// let path = Utf8Path::new("/Minas/tirith");
1264    /// let metadata = path.symlink_metadata().expect("symlink_metadata call failed");
1265    /// println!("{:?}", metadata.file_type());
1266    /// ```
1267    #[inline]
1268    pub fn symlink_metadata(&self) -> io::Result<fs::Metadata> {
1269        self.0.symlink_metadata()
1270    }
1271
1272    /// Returns the canonical, absolute form of the path with all intermediate
1273    /// components normalized and symbolic links resolved.
1274    ///
1275    /// This returns a [`PathBuf`] because even if a symlink is valid Unicode, its target may not
1276    /// be. For a version that returns a [`Utf8PathBuf`], see
1277    /// [`canonicalize_utf8`](Self::canonicalize_utf8).
1278    ///
1279    /// This is an alias to [`fs::canonicalize`].
1280    ///
1281    /// # Examples
1282    ///
1283    /// ```no_run
1284    /// use camino::Utf8Path;
1285    /// use std::path::PathBuf;
1286    ///
1287    /// let path = Utf8Path::new("/foo/test/../test/bar.rs");
1288    /// assert_eq!(path.canonicalize().unwrap(), PathBuf::from("/foo/test/bar.rs"));
1289    /// ```
1290    #[inline]
1291    pub fn canonicalize(&self) -> io::Result<PathBuf> {
1292        self.0.canonicalize()
1293    }
1294
1295    /// Returns the canonical, absolute form of the path with all intermediate
1296    /// components normalized and symbolic links resolved.
1297    ///
1298    /// This method attempts to convert the resulting [`PathBuf`] into a [`Utf8PathBuf`]. For a
1299    /// version that does not attempt to do this conversion, see
1300    /// [`canonicalize`](Self::canonicalize).
1301    ///
1302    /// # Errors
1303    ///
1304    /// The I/O operation may return an error: see the [`fs::canonicalize`]
1305    /// documentation for more.
1306    ///
1307    /// If the resulting path is not UTF-8, an [`io::Error`] is returned with the
1308    /// [`ErrorKind`](io::ErrorKind) set to [`InvalidData`](io::ErrorKind::InvalidData)
1309    /// and the payload set to a [`FromPathBufError`].
1310    ///
1311    /// # Examples
1312    ///
1313    /// ```no_run
1314    /// use camino::{Utf8Path, Utf8PathBuf};
1315    ///
1316    /// let path = Utf8Path::new("/foo/test/../test/bar.rs");
1317    /// assert_eq!(path.canonicalize_utf8().unwrap(), Utf8PathBuf::from("/foo/test/bar.rs"));
1318    /// ```
1319    pub fn canonicalize_utf8(&self) -> io::Result<Utf8PathBuf> {
1320        self.canonicalize()
1321            .and_then(|path| path.try_into().map_err(FromPathBufError::into_io_error))
1322    }
1323
1324    /// Reads a symbolic link, returning the file that the link points to.
1325    ///
1326    /// This returns a [`PathBuf`] because even if a symlink is valid Unicode, its target may not
1327    /// be. For a version that returns a [`Utf8PathBuf`], see
1328    /// [`read_link_utf8`](Self::read_link_utf8).
1329    ///
1330    /// This is an alias to [`fs::read_link`].
1331    ///
1332    /// # Examples
1333    ///
1334    /// ```no_run
1335    /// use camino::Utf8Path;
1336    ///
1337    /// let path = Utf8Path::new("/laputa/sky_castle.rs");
1338    /// let path_link = path.read_link().expect("read_link call failed");
1339    /// ```
1340    #[inline]
1341    pub fn read_link(&self) -> io::Result<PathBuf> {
1342        self.0.read_link()
1343    }
1344
1345    /// Reads a symbolic link, returning the file that the link points to.
1346    ///
1347    /// This method attempts to convert the resulting [`PathBuf`] into a [`Utf8PathBuf`]. For a
1348    /// version that does not attempt to do this conversion, see [`read_link`](Self::read_link).
1349    ///
1350    /// # Errors
1351    ///
1352    /// The I/O operation may return an error: see the [`fs::read_link`]
1353    /// documentation for more.
1354    ///
1355    /// If the resulting path is not UTF-8, an [`io::Error`] is returned with the
1356    /// [`ErrorKind`](io::ErrorKind) set to [`InvalidData`](io::ErrorKind::InvalidData)
1357    /// and the payload set to a [`FromPathBufError`].
1358    ///
1359    /// # Examples
1360    ///
1361    /// ```no_run
1362    /// use camino::Utf8Path;
1363    ///
1364    /// let path = Utf8Path::new("/laputa/sky_castle.rs");
1365    /// let path_link = path.read_link_utf8().expect("read_link call failed");
1366    /// ```
1367    pub fn read_link_utf8(&self) -> io::Result<Utf8PathBuf> {
1368        self.read_link()
1369            .and_then(|path| path.try_into().map_err(FromPathBufError::into_io_error))
1370    }
1371
1372    /// Returns an iterator over the entries within a directory.
1373    ///
1374    /// The iterator will yield instances of [`io::Result`]`<`[`fs::DirEntry`]`>`. New
1375    /// errors may be encountered after an iterator is initially constructed.
1376    ///
1377    /// This is an alias to [`fs::read_dir`].
1378    ///
1379    /// # Examples
1380    ///
1381    /// ```no_run
1382    /// use camino::Utf8Path;
1383    ///
1384    /// let path = Utf8Path::new("/laputa");
1385    /// for entry in path.read_dir().expect("read_dir call failed") {
1386    ///     if let Ok(entry) = entry {
1387    ///         println!("{:?}", entry.path());
1388    ///     }
1389    /// }
1390    /// ```
1391    #[inline]
1392    pub fn read_dir(&self) -> io::Result<fs::ReadDir> {
1393        self.0.read_dir()
1394    }
1395
1396    /// Returns an iterator over the entries within a directory.
1397    ///
1398    /// The iterator will yield instances of [`io::Result`]`<`[`Utf8DirEntry`]`>`. New
1399    /// errors may be encountered after an iterator is initially constructed.
1400    ///
1401    /// # Errors
1402    ///
1403    /// The I/O operation may return an error: see the [`fs::read_dir`]
1404    /// documentation for more.
1405    ///
1406    /// If a directory entry is not UTF-8, an [`io::Error`] is returned with the
1407    /// [`ErrorKind`](io::ErrorKind) set to [`InvalidData`](io::ErrorKind::InvalidData)
1408    /// and the payload set to a [`FromPathBufError`].
1409    ///
1410    /// # Examples
1411    ///
1412    /// ```no_run
1413    /// use camino::Utf8Path;
1414    ///
1415    /// let path = Utf8Path::new("/laputa");
1416    /// for entry in path.read_dir_utf8().expect("read_dir call failed") {
1417    ///     if let Ok(entry) = entry {
1418    ///         println!("{}", entry.path());
1419    ///     }
1420    /// }
1421    /// ```
1422    #[inline]
1423    pub fn read_dir_utf8(&self) -> io::Result<ReadDirUtf8> {
1424        self.0.read_dir().map(|inner| ReadDirUtf8 { inner })
1425    }
1426
1427    /// Returns `true` if the path points at an existing entity.
1428    ///
1429    /// Warning: this method may be error-prone, consider using [`try_exists()`] instead!
1430    /// It also has a risk of introducing time-of-check to time-of-use (TOCTOU) bugs.
1431    ///
1432    /// This function will traverse symbolic links to query information about the
1433    /// destination file. In case of broken symbolic links this will return `false`.
1434    ///
1435    /// If you cannot access the directory containing the file, e.g., because of a
1436    /// permission error, this will return `false`.
1437    ///
1438    /// # Examples
1439    ///
1440    /// ```no_run
1441    /// use camino::Utf8Path;
1442    /// assert!(!Utf8Path::new("does_not_exist.txt").exists());
1443    /// ```
1444    ///
1445    /// # See Also
1446    ///
1447    /// This is a convenience function that coerces errors to false. If you want to
1448    /// check errors, call [`fs::metadata`].
1449    ///
1450    /// [`try_exists()`]: Self::try_exists
1451    #[must_use]
1452    #[inline]
1453    pub fn exists(&self) -> bool {
1454        self.0.exists()
1455    }
1456
1457    /// Returns `Ok(true)` if the path points at an existing entity.
1458    ///
1459    /// This function will traverse symbolic links to query information about the
1460    /// destination file. In case of broken symbolic links this will return `Ok(false)`.
1461    ///
1462    /// As opposed to the [`exists()`] method, this one doesn't silently ignore errors
1463    /// unrelated to the path not existing. (E.g. it will return [`Err`] in case of permission
1464    /// denied on some of the parent directories.)
1465    ///
1466    /// Note that while this avoids some pitfalls of the `exists()` method, it still can not
1467    /// prevent time-of-check to time-of-use (TOCTOU) bugs. You should only use it in scenarios
1468    /// where those bugs are not an issue.
1469    ///
1470    /// # Examples
1471    ///
1472    /// ```no_run
1473    /// use camino::Utf8Path;
1474    /// assert!(
1475    ///     !Utf8Path::new("does_not_exist.txt")
1476    ///         .try_exists()
1477    ///         .expect("Can't check existence of file does_not_exist.txt")
1478    /// );
1479    /// assert!(Utf8Path::new("/root/secret_file.txt").try_exists().is_err());
1480    /// ```
1481    ///
1482    /// [`exists()`]: Self::exists
1483    #[inline]
1484    pub fn try_exists(&self) -> io::Result<bool> {
1485        // Note: this block is written this way rather than with a pattern guard to appease Rust
1486        // 1.34.
1487        match fs::metadata(self) {
1488            Ok(_) => Ok(true),
1489            Err(error) => {
1490                if error.kind() == io::ErrorKind::NotFound {
1491                    Ok(false)
1492                } else {
1493                    Err(error)
1494                }
1495            }
1496        }
1497    }
1498
1499    /// Returns `true` if the path exists on disk and is pointing at a regular file.
1500    ///
1501    /// This function will traverse symbolic links to query information about the
1502    /// destination file. In case of broken symbolic links this will return `false`.
1503    ///
1504    /// If you cannot access the directory containing the file, e.g., because of a
1505    /// permission error, this will return `false`.
1506    ///
1507    /// # Examples
1508    ///
1509    /// ```no_run
1510    /// use camino::Utf8Path;
1511    /// assert_eq!(Utf8Path::new("./is_a_directory/").is_file(), false);
1512    /// assert_eq!(Utf8Path::new("a_file.txt").is_file(), true);
1513    /// ```
1514    ///
1515    /// # See Also
1516    ///
1517    /// This is a convenience function that coerces errors to false. If you want to
1518    /// check errors, call [`fs::metadata`] and handle its [`Result`]. Then call
1519    /// [`fs::Metadata::is_file`] if it was [`Ok`].
1520    ///
1521    /// When the goal is simply to read from (or write to) the source, the most
1522    /// reliable way to test the source can be read (or written to) is to open
1523    /// it. Only using `is_file` can break workflows like `diff <( prog_a )` on
1524    /// a Unix-like system for example. See [`fs::File::open`] or
1525    /// [`fs::OpenOptions::open`] for more information.
1526    #[must_use]
1527    #[inline]
1528    pub fn is_file(&self) -> bool {
1529        self.0.is_file()
1530    }
1531
1532    /// Returns `true` if the path exists on disk and is pointing at a directory.
1533    ///
1534    /// This function will traverse symbolic links to query information about the
1535    /// destination file. In case of broken symbolic links this will return `false`.
1536    ///
1537    /// If you cannot access the directory containing the file, e.g., because of a
1538    /// permission error, this will return `false`.
1539    ///
1540    /// # Examples
1541    ///
1542    /// ```no_run
1543    /// use camino::Utf8Path;
1544    /// assert_eq!(Utf8Path::new("./is_a_directory/").is_dir(), true);
1545    /// assert_eq!(Utf8Path::new("a_file.txt").is_dir(), false);
1546    /// ```
1547    ///
1548    /// # See Also
1549    ///
1550    /// This is a convenience function that coerces errors to false. If you want to
1551    /// check errors, call [`fs::metadata`] and handle its [`Result`]. Then call
1552    /// [`fs::Metadata::is_dir`] if it was [`Ok`].
1553    #[must_use]
1554    #[inline]
1555    pub fn is_dir(&self) -> bool {
1556        self.0.is_dir()
1557    }
1558
1559    /// Returns `true` if the path exists on disk and is pointing at a symbolic link.
1560    ///
1561    /// This function will not traverse symbolic links.
1562    /// In case of a broken symbolic link this will also return true.
1563    ///
1564    /// If you cannot access the directory containing the file, e.g., because of a
1565    /// permission error, this will return false.
1566    ///
1567    /// # Examples
1568    ///
1569    #[cfg_attr(unix, doc = "```no_run")]
1570    #[cfg_attr(not(unix), doc = "```ignore")]
1571    /// use camino::Utf8Path;
1572    /// use std::os::unix::fs::symlink;
1573    ///
1574    /// let link_path = Utf8Path::new("link");
1575    /// symlink("/origin_does_not_exist/", link_path).unwrap();
1576    /// assert_eq!(link_path.is_symlink(), true);
1577    /// assert_eq!(link_path.exists(), false);
1578    /// ```
1579    ///
1580    /// # See Also
1581    ///
1582    /// This is a convenience function that coerces errors to false. If you want to
1583    /// check errors, call [`Utf8Path::symlink_metadata`] and handle its [`Result`]. Then call
1584    /// [`fs::Metadata::is_symlink`] if it was [`Ok`].
1585    #[must_use]
1586    pub fn is_symlink(&self) -> bool {
1587        self.symlink_metadata()
1588            .map(|m| m.file_type().is_symlink())
1589            .unwrap_or(false)
1590    }
1591
1592    /// Converts a [`Box<Utf8Path>`] into a [`Utf8PathBuf`] without copying or allocating.
1593    #[must_use = "`self` will be dropped if the result is not used"]
1594    #[inline]
1595    pub fn into_path_buf(self: Box<Utf8Path>) -> Utf8PathBuf {
1596        let ptr = Box::into_raw(self) as *mut Path;
1597        // SAFETY:
1598        // * self is valid UTF-8
1599        // * ptr was constructed by consuming self so it represents an owned path.
1600        // * Utf8Path is marked as #[repr(transparent)] so the conversion from a *mut Utf8Path to a
1601        //   *mut Path is valid.
1602        let boxed_path = unsafe { Box::from_raw(ptr) };
1603        Utf8PathBuf(boxed_path.into_path_buf())
1604    }
1605
1606    // invariant: Path must be guaranteed to be utf-8 data
1607    #[inline]
1608    unsafe fn assume_utf8(path: &Path) -> &Utf8Path {
1609        // SAFETY: Utf8Path is marked as #[repr(transparent)] so the conversion from a
1610        // *const Path to a *const Utf8Path is valid.
1611        &*(path as *const Path as *const Utf8Path)
1612    }
1613
1614    #[cfg(path_buf_deref_mut)]
1615    #[inline]
1616    unsafe fn assume_utf8_mut(path: &mut Path) -> &mut Utf8Path {
1617        &mut *(path as *mut Path as *mut Utf8Path)
1618    }
1619}
1620
1621impl Clone for Box<Utf8Path> {
1622    fn clone(&self) -> Self {
1623        let boxed: Box<Path> = self.0.into();
1624        let ptr = Box::into_raw(boxed) as *mut Utf8Path;
1625        // SAFETY:
1626        // * self is valid UTF-8
1627        // * ptr was created by consuming a Box<Path> so it represents an rced pointer
1628        // * Utf8Path is marked as #[repr(transparent)] so the conversion from *mut Path to
1629        //   *mut Utf8Path is valid
1630        unsafe { Box::from_raw(ptr) }
1631    }
1632}
1633
1634impl fmt::Display for Utf8Path {
1635    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1636        fmt::Display::fmt(self.as_str(), f)
1637    }
1638}
1639
1640impl fmt::Debug for Utf8Path {
1641    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1642        fmt::Debug::fmt(self.as_str(), f)
1643    }
1644}
1645
1646/// An iterator over [`Utf8Path`] and its ancestors.
1647///
1648/// This `struct` is created by the [`ancestors`] method on [`Utf8Path`].
1649/// See its documentation for more.
1650///
1651/// # Examples
1652///
1653/// ```
1654/// use camino::Utf8Path;
1655///
1656/// let path = Utf8Path::new("/foo/bar");
1657///
1658/// for ancestor in path.ancestors() {
1659///     println!("{}", ancestor);
1660/// }
1661/// ```
1662///
1663/// [`ancestors`]: Utf8Path::ancestors
1664#[derive(Copy, Clone)]
1665#[must_use = "iterators are lazy and do nothing unless consumed"]
1666#[repr(transparent)]
1667pub struct Utf8Ancestors<'a>(Ancestors<'a>);
1668
1669impl fmt::Debug for Utf8Ancestors<'_> {
1670    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1671        fmt::Debug::fmt(&self.0, f)
1672    }
1673}
1674
1675impl<'a> Iterator for Utf8Ancestors<'a> {
1676    type Item = &'a Utf8Path;
1677
1678    #[inline]
1679    fn next(&mut self) -> Option<Self::Item> {
1680        self.0.next().map(|path| {
1681            // SAFETY: Utf8Ancestors was constructed from a Utf8Path, so it is guaranteed to
1682            // be valid UTF-8
1683            unsafe { Utf8Path::assume_utf8(path) }
1684        })
1685    }
1686}
1687
1688impl FusedIterator for Utf8Ancestors<'_> {}
1689
1690/// An iterator over the [`Utf8Component`]s of a [`Utf8Path`].
1691///
1692/// This `struct` is created by the [`components`] method on [`Utf8Path`].
1693/// See its documentation for more.
1694///
1695/// # Examples
1696///
1697/// ```
1698/// use camino::Utf8Path;
1699///
1700/// let path = Utf8Path::new("/tmp/foo/bar.txt");
1701///
1702/// for component in path.components() {
1703///     println!("{:?}", component);
1704/// }
1705/// ```
1706///
1707/// [`components`]: Utf8Path::components
1708#[derive(Clone, Eq, Ord, PartialEq, PartialOrd)]
1709#[must_use = "iterators are lazy and do nothing unless consumed"]
1710pub struct Utf8Components<'a>(Components<'a>);
1711
1712impl<'a> Utf8Components<'a> {
1713    /// Extracts a slice corresponding to the portion of the path remaining for iteration.
1714    ///
1715    /// # Examples
1716    ///
1717    /// ```
1718    /// use camino::Utf8Path;
1719    ///
1720    /// let mut components = Utf8Path::new("/tmp/foo/bar.txt").components();
1721    /// components.next();
1722    /// components.next();
1723    ///
1724    /// assert_eq!(Utf8Path::new("foo/bar.txt"), components.as_path());
1725    /// ```
1726    #[must_use]
1727    #[inline]
1728    pub fn as_path(&self) -> &'a Utf8Path {
1729        // SAFETY: Utf8Components was constructed from a Utf8Path, so it is guaranteed to be valid
1730        // UTF-8
1731        unsafe { Utf8Path::assume_utf8(self.0.as_path()) }
1732    }
1733}
1734
1735impl<'a> Iterator for Utf8Components<'a> {
1736    type Item = Utf8Component<'a>;
1737
1738    #[inline]
1739    fn next(&mut self) -> Option<Self::Item> {
1740        self.0.next().map(|component| {
1741            // SAFETY: Utf8Component was constructed from a Utf8Path, so it is guaranteed to be
1742            // valid UTF-8
1743            unsafe { Utf8Component::new(component) }
1744        })
1745    }
1746}
1747
1748impl FusedIterator for Utf8Components<'_> {}
1749
1750impl DoubleEndedIterator for Utf8Components<'_> {
1751    #[inline]
1752    fn next_back(&mut self) -> Option<Self::Item> {
1753        self.0.next_back().map(|component| {
1754            // SAFETY: Utf8Component was constructed from a Utf8Path, so it is guaranteed to be
1755            // valid UTF-8
1756            unsafe { Utf8Component::new(component) }
1757        })
1758    }
1759}
1760
1761impl fmt::Debug for Utf8Components<'_> {
1762    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1763        fmt::Debug::fmt(&self.0, f)
1764    }
1765}
1766
1767impl AsRef<Utf8Path> for Utf8Components<'_> {
1768    #[inline]
1769    fn as_ref(&self) -> &Utf8Path {
1770        self.as_path()
1771    }
1772}
1773
1774impl AsRef<Path> for Utf8Components<'_> {
1775    #[inline]
1776    fn as_ref(&self) -> &Path {
1777        self.as_path().as_ref()
1778    }
1779}
1780
1781impl AsRef<str> for Utf8Components<'_> {
1782    #[inline]
1783    fn as_ref(&self) -> &str {
1784        self.as_path().as_ref()
1785    }
1786}
1787
1788impl AsRef<OsStr> for Utf8Components<'_> {
1789    #[inline]
1790    fn as_ref(&self) -> &OsStr {
1791        self.as_path().as_os_str()
1792    }
1793}
1794
1795/// An iterator over the [`Utf8Component`]s of a [`Utf8Path`], as [`str`] slices.
1796///
1797/// This `struct` is created by the [`iter`] method on [`Utf8Path`].
1798/// See its documentation for more.
1799///
1800/// [`iter`]: Utf8Path::iter
1801#[derive(Clone)]
1802#[must_use = "iterators are lazy and do nothing unless consumed"]
1803pub struct Iter<'a> {
1804    inner: Utf8Components<'a>,
1805}
1806
1807impl fmt::Debug for Iter<'_> {
1808    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1809        struct DebugHelper<'a>(&'a Utf8Path);
1810
1811        impl fmt::Debug for DebugHelper<'_> {
1812            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1813                f.debug_list().entries(self.0.iter()).finish()
1814            }
1815        }
1816
1817        f.debug_tuple("Iter")
1818            .field(&DebugHelper(self.as_path()))
1819            .finish()
1820    }
1821}
1822
1823impl<'a> Iter<'a> {
1824    /// Extracts a slice corresponding to the portion of the path remaining for iteration.
1825    ///
1826    /// # Examples
1827    ///
1828    /// ```
1829    /// use camino::Utf8Path;
1830    ///
1831    /// let mut iter = Utf8Path::new("/tmp/foo/bar.txt").iter();
1832    /// iter.next();
1833    /// iter.next();
1834    ///
1835    /// assert_eq!(Utf8Path::new("foo/bar.txt"), iter.as_path());
1836    /// ```
1837    #[must_use]
1838    #[inline]
1839    pub fn as_path(&self) -> &'a Utf8Path {
1840        self.inner.as_path()
1841    }
1842}
1843
1844impl AsRef<Utf8Path> for Iter<'_> {
1845    #[inline]
1846    fn as_ref(&self) -> &Utf8Path {
1847        self.as_path()
1848    }
1849}
1850
1851impl AsRef<Path> for Iter<'_> {
1852    #[inline]
1853    fn as_ref(&self) -> &Path {
1854        self.as_path().as_ref()
1855    }
1856}
1857
1858impl AsRef<str> for Iter<'_> {
1859    #[inline]
1860    fn as_ref(&self) -> &str {
1861        self.as_path().as_ref()
1862    }
1863}
1864
1865impl AsRef<OsStr> for Iter<'_> {
1866    #[inline]
1867    fn as_ref(&self) -> &OsStr {
1868        self.as_path().as_os_str()
1869    }
1870}
1871
1872impl<'a> Iterator for Iter<'a> {
1873    type Item = &'a str;
1874
1875    #[inline]
1876    fn next(&mut self) -> Option<&'a str> {
1877        self.inner.next().map(|component| component.as_str())
1878    }
1879}
1880
1881impl<'a> DoubleEndedIterator for Iter<'a> {
1882    #[inline]
1883    fn next_back(&mut self) -> Option<&'a str> {
1884        self.inner.next_back().map(|component| component.as_str())
1885    }
1886}
1887
1888impl FusedIterator for Iter<'_> {}
1889
1890/// A single component of a path.
1891///
1892/// A [`Utf8Component`] roughly corresponds to a substring between path separators
1893/// (`/` or `\`).
1894///
1895/// This `enum` is created by iterating over [`Utf8Components`], which in turn is
1896/// created by the [`components`](Utf8Path::components) method on [`Utf8Path`].
1897///
1898/// # Examples
1899///
1900/// ```rust
1901/// use camino::{Utf8Component, Utf8Path};
1902///
1903/// let path = Utf8Path::new("/tmp/foo/bar.txt");
1904/// let components = path.components().collect::<Vec<_>>();
1905/// assert_eq!(&components, &[
1906///     Utf8Component::RootDir,
1907///     Utf8Component::Normal("tmp"),
1908///     Utf8Component::Normal("foo"),
1909///     Utf8Component::Normal("bar.txt"),
1910/// ]);
1911/// ```
1912#[derive(Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
1913pub enum Utf8Component<'a> {
1914    /// A Windows path prefix, e.g., `C:` or `\\server\share`.
1915    ///
1916    /// There is a large variety of prefix types, see [`Utf8Prefix`]'s documentation
1917    /// for more.
1918    ///
1919    /// Does not occur on Unix.
1920    Prefix(Utf8PrefixComponent<'a>),
1921
1922    /// The root directory component, appears after any prefix and before anything else.
1923    ///
1924    /// It represents a separator that designates that a path starts from root.
1925    RootDir,
1926
1927    /// A reference to the current directory, i.e., `.`.
1928    CurDir,
1929
1930    /// A reference to the parent directory, i.e., `..`.
1931    ParentDir,
1932
1933    /// A normal component, e.g., `a` and `b` in `a/b`.
1934    ///
1935    /// This variant is the most common one, it represents references to files
1936    /// or directories.
1937    Normal(&'a str),
1938}
1939
1940impl<'a> Utf8Component<'a> {
1941    unsafe fn new(component: Component<'a>) -> Utf8Component<'a> {
1942        match component {
1943            Component::Prefix(prefix) => Utf8Component::Prefix(Utf8PrefixComponent(prefix)),
1944            Component::RootDir => Utf8Component::RootDir,
1945            Component::CurDir => Utf8Component::CurDir,
1946            Component::ParentDir => Utf8Component::ParentDir,
1947            Component::Normal(s) => Utf8Component::Normal(str_assume_utf8(s)),
1948        }
1949    }
1950
1951    /// Extracts the underlying [`str`] slice.
1952    ///
1953    /// # Examples
1954    ///
1955    /// ```
1956    /// use camino::Utf8Path;
1957    ///
1958    /// let path = Utf8Path::new("./tmp/foo/bar.txt");
1959    /// let components: Vec<_> = path.components().map(|comp| comp.as_str()).collect();
1960    /// assert_eq!(&components, &[".", "tmp", "foo", "bar.txt"]);
1961    /// ```
1962    #[must_use]
1963    #[inline]
1964    pub fn as_str(&self) -> &'a str {
1965        // SAFETY: Utf8Component was constructed from a Utf8Path, so it is guaranteed to be
1966        // valid UTF-8
1967        unsafe { str_assume_utf8(self.as_os_str()) }
1968    }
1969
1970    /// Extracts the underlying [`OsStr`] slice.
1971    ///
1972    /// # Examples
1973    ///
1974    /// ```
1975    /// use camino::Utf8Path;
1976    ///
1977    /// let path = Utf8Path::new("./tmp/foo/bar.txt");
1978    /// let components: Vec<_> = path.components().map(|comp| comp.as_os_str()).collect();
1979    /// assert_eq!(&components, &[".", "tmp", "foo", "bar.txt"]);
1980    /// ```
1981    #[must_use]
1982    pub fn as_os_str(&self) -> &'a OsStr {
1983        match *self {
1984            Utf8Component::Prefix(prefix) => prefix.as_os_str(),
1985            Utf8Component::RootDir => Component::RootDir.as_os_str(),
1986            Utf8Component::CurDir => Component::CurDir.as_os_str(),
1987            Utf8Component::ParentDir => Component::ParentDir.as_os_str(),
1988            Utf8Component::Normal(s) => OsStr::new(s),
1989        }
1990    }
1991}
1992
1993impl fmt::Debug for Utf8Component<'_> {
1994    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1995        fmt::Debug::fmt(self.as_os_str(), f)
1996    }
1997}
1998
1999impl fmt::Display for Utf8Component<'_> {
2000    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2001        fmt::Display::fmt(self.as_str(), f)
2002    }
2003}
2004
2005impl AsRef<Utf8Path> for Utf8Component<'_> {
2006    #[inline]
2007    fn as_ref(&self) -> &Utf8Path {
2008        self.as_str().as_ref()
2009    }
2010}
2011
2012impl AsRef<Path> for Utf8Component<'_> {
2013    #[inline]
2014    fn as_ref(&self) -> &Path {
2015        self.as_os_str().as_ref()
2016    }
2017}
2018
2019impl AsRef<str> for Utf8Component<'_> {
2020    #[inline]
2021    fn as_ref(&self) -> &str {
2022        self.as_str()
2023    }
2024}
2025
2026impl AsRef<OsStr> for Utf8Component<'_> {
2027    #[inline]
2028    fn as_ref(&self) -> &OsStr {
2029        self.as_os_str()
2030    }
2031}
2032
2033/// Windows path prefixes, e.g., `C:` or `\\server\share`.
2034///
2035/// Windows uses a variety of path prefix styles, including references to drive
2036/// volumes (like `C:`), network shared folders (like `\\server\share`), and
2037/// others. In addition, some path prefixes are "verbatim" (i.e., prefixed with
2038/// `\\?\`), in which case `/` is *not* treated as a separator and essentially
2039/// no normalization is performed.
2040///
2041/// # Examples
2042///
2043/// ```
2044/// use camino::{Utf8Component, Utf8Path, Utf8Prefix};
2045/// use camino::Utf8Prefix::*;
2046///
2047/// fn get_path_prefix(s: &str) -> Utf8Prefix {
2048///     let path = Utf8Path::new(s);
2049///     match path.components().next().unwrap() {
2050///         Utf8Component::Prefix(prefix_component) => prefix_component.kind(),
2051///         _ => panic!(),
2052///     }
2053/// }
2054///
2055/// # if cfg!(windows) {
2056/// assert_eq!(Verbatim("pictures"), get_path_prefix(r"\\?\pictures\kittens"));
2057/// assert_eq!(VerbatimUNC("server", "share"), get_path_prefix(r"\\?\UNC\server\share"));
2058/// assert_eq!(VerbatimDisk(b'C'), get_path_prefix(r"\\?\C:\"));
2059/// assert_eq!(DeviceNS("BrainInterface"), get_path_prefix(r"\\.\BrainInterface"));
2060/// assert_eq!(UNC("server", "share"), get_path_prefix(r"\\server\share"));
2061/// assert_eq!(Disk(b'C'), get_path_prefix(r"C:\Users\Rust\Pictures\Ferris"));
2062/// # }
2063/// ```
2064#[derive(Copy, Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
2065pub enum Utf8Prefix<'a> {
2066    /// Verbatim prefix, e.g., `\\?\cat_pics`.
2067    ///
2068    /// Verbatim prefixes consist of `\\?\` immediately followed by the given
2069    /// component.
2070    Verbatim(&'a str),
2071
2072    /// Verbatim prefix using Windows' _**U**niform **N**aming **C**onvention_,
2073    /// e.g., `\\?\UNC\server\share`.
2074    ///
2075    /// Verbatim UNC prefixes consist of `\\?\UNC\` immediately followed by the
2076    /// server's hostname and a share name.
2077    VerbatimUNC(&'a str, &'a str),
2078
2079    /// Verbatim disk prefix, e.g., `\\?\C:`.
2080    ///
2081    /// Verbatim disk prefixes consist of `\\?\` immediately followed by the
2082    /// drive letter and `:`.
2083    VerbatimDisk(u8),
2084
2085    /// Device namespace prefix, e.g., `\\.\COM42`.
2086    ///
2087    /// Device namespace prefixes consist of `\\.\` immediately followed by the
2088    /// device name.
2089    DeviceNS(&'a str),
2090
2091    /// Prefix using Windows' _**U**niform **N**aming **C**onvention_, e.g.
2092    /// `\\server\share`.
2093    ///
2094    /// UNC prefixes consist of the server's hostname and a share name.
2095    UNC(&'a str, &'a str),
2096
2097    /// Prefix `C:` for the given disk drive.
2098    Disk(u8),
2099}
2100
2101impl Utf8Prefix<'_> {
2102    /// Determines if the prefix is verbatim, i.e., begins with `\\?\`.
2103    ///
2104    /// # Examples
2105    ///
2106    /// ```
2107    /// use camino::Utf8Prefix::*;
2108    ///
2109    /// assert!(Verbatim("pictures").is_verbatim());
2110    /// assert!(VerbatimUNC("server", "share").is_verbatim());
2111    /// assert!(VerbatimDisk(b'C').is_verbatim());
2112    /// assert!(!DeviceNS("BrainInterface").is_verbatim());
2113    /// assert!(!UNC("server", "share").is_verbatim());
2114    /// assert!(!Disk(b'C').is_verbatim());
2115    /// ```
2116    #[must_use]
2117    pub fn is_verbatim(&self) -> bool {
2118        use Utf8Prefix::*;
2119        match self {
2120            Verbatim(_) | VerbatimDisk(_) | VerbatimUNC(..) => true,
2121            _ => false,
2122        }
2123    }
2124}
2125
2126/// A structure wrapping a Windows path prefix as well as its unparsed string
2127/// representation.
2128///
2129/// In addition to the parsed [`Utf8Prefix`] information returned by [`kind`],
2130/// [`Utf8PrefixComponent`] also holds the raw and unparsed [`str`] slice,
2131/// returned by [`as_str`].
2132///
2133/// Instances of this `struct` can be obtained by matching against the
2134/// [`Prefix` variant] on [`Utf8Component`].
2135///
2136/// Does not occur on Unix.
2137///
2138/// # Examples
2139///
2140/// ```
2141/// # if cfg!(windows) {
2142/// use camino::{Utf8Component, Utf8Path, Utf8Prefix};
2143/// use std::ffi::OsStr;
2144///
2145/// let path = Utf8Path::new(r"C:\you\later\");
2146/// match path.components().next().unwrap() {
2147///     Utf8Component::Prefix(prefix_component) => {
2148///         assert_eq!(Utf8Prefix::Disk(b'C'), prefix_component.kind());
2149///         assert_eq!("C:", prefix_component.as_str());
2150///     }
2151///     _ => unreachable!(),
2152/// }
2153/// # }
2154/// ```
2155///
2156/// [`as_str`]: Utf8PrefixComponent::as_str
2157/// [`kind`]: Utf8PrefixComponent::kind
2158/// [`Prefix` variant]: Utf8Component::Prefix
2159#[repr(transparent)]
2160#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd)]
2161pub struct Utf8PrefixComponent<'a>(PrefixComponent<'a>);
2162
2163impl<'a> Utf8PrefixComponent<'a> {
2164    /// Returns the parsed prefix data.
2165    ///
2166    /// See [`Utf8Prefix`]'s documentation for more information on the different
2167    /// kinds of prefixes.
2168    #[must_use]
2169    pub fn kind(&self) -> Utf8Prefix<'a> {
2170        // SAFETY for all the below unsafe blocks: the path self was originally constructed from was
2171        // UTF-8 so any parts of it are valid UTF-8
2172        match self.0.kind() {
2173            Prefix::Verbatim(prefix) => Utf8Prefix::Verbatim(unsafe { str_assume_utf8(prefix) }),
2174            Prefix::VerbatimUNC(server, share) => {
2175                let server = unsafe { str_assume_utf8(server) };
2176                let share = unsafe { str_assume_utf8(share) };
2177                Utf8Prefix::VerbatimUNC(server, share)
2178            }
2179            Prefix::VerbatimDisk(drive) => Utf8Prefix::VerbatimDisk(drive),
2180            Prefix::DeviceNS(prefix) => Utf8Prefix::DeviceNS(unsafe { str_assume_utf8(prefix) }),
2181            Prefix::UNC(server, share) => {
2182                let server = unsafe { str_assume_utf8(server) };
2183                let share = unsafe { str_assume_utf8(share) };
2184                Utf8Prefix::UNC(server, share)
2185            }
2186            Prefix::Disk(drive) => Utf8Prefix::Disk(drive),
2187        }
2188    }
2189
2190    /// Returns the [`str`] slice for this prefix.
2191    #[must_use]
2192    #[inline]
2193    pub fn as_str(&self) -> &'a str {
2194        // SAFETY: Utf8PrefixComponent was constructed from a Utf8Path, so it is guaranteed to be
2195        // valid UTF-8
2196        unsafe { str_assume_utf8(self.as_os_str()) }
2197    }
2198
2199    /// Returns the raw [`OsStr`] slice for this prefix.
2200    #[must_use]
2201    #[inline]
2202    pub fn as_os_str(&self) -> &'a OsStr {
2203        self.0.as_os_str()
2204    }
2205}
2206
2207impl fmt::Debug for Utf8PrefixComponent<'_> {
2208    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2209        fmt::Debug::fmt(&self.0, f)
2210    }
2211}
2212
2213impl fmt::Display for Utf8PrefixComponent<'_> {
2214    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2215        fmt::Display::fmt(self.as_str(), f)
2216    }
2217}
2218
2219// ---
2220// read_dir_utf8
2221// ---
2222
2223/// Iterator over the entries in a directory.
2224///
2225/// This iterator is returned from [`Utf8Path::read_dir_utf8`] and will yield instances of
2226/// <code>[io::Result]<[Utf8DirEntry]></code>. Through a [`Utf8DirEntry`] information like the entry's path
2227/// and possibly other metadata can be learned.
2228///
2229/// The order in which this iterator returns entries is platform and filesystem
2230/// dependent.
2231///
2232/// # Errors
2233///
2234/// This [`io::Result`] will be an [`Err`] if there's some sort of intermittent
2235/// IO error during iteration.
2236///
2237/// If a directory entry is not UTF-8, an [`io::Error`] is returned with the
2238/// [`ErrorKind`](io::ErrorKind) set to [`InvalidData`][io::ErrorKind::InvalidData]
2239/// and the payload set to a [`FromPathBufError`].
2240#[derive(Debug)]
2241pub struct ReadDirUtf8 {
2242    inner: fs::ReadDir,
2243}
2244
2245impl Iterator for ReadDirUtf8 {
2246    type Item = io::Result<Utf8DirEntry>;
2247
2248    fn next(&mut self) -> Option<io::Result<Utf8DirEntry>> {
2249        self.inner
2250            .next()
2251            .map(|entry| entry.and_then(Utf8DirEntry::new))
2252    }
2253}
2254
2255/// Entries returned by the [`ReadDirUtf8`] iterator.
2256///
2257/// An instance of [`Utf8DirEntry`] represents an entry inside of a directory on the filesystem. Each
2258/// entry can be inspected via methods to learn about the full path or possibly other metadata.
2259#[derive(Debug)]
2260pub struct Utf8DirEntry {
2261    inner: fs::DirEntry,
2262    path: Utf8PathBuf,
2263}
2264
2265impl Utf8DirEntry {
2266    fn new(inner: fs::DirEntry) -> io::Result<Self> {
2267        let path = inner
2268            .path()
2269            .try_into()
2270            .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
2271        Ok(Self { inner, path })
2272    }
2273
2274    /// Returns the full path to the file that this entry represents.
2275    ///
2276    /// The full path is created by joining the original path to `read_dir`
2277    /// with the filename of this entry.
2278    ///
2279    /// # Examples
2280    ///
2281    /// ```no_run
2282    /// use camino::Utf8Path;
2283    ///
2284    /// fn main() -> std::io::Result<()> {
2285    ///     for entry in Utf8Path::new(".").read_dir_utf8()? {
2286    ///         let dir = entry?;
2287    ///         println!("{}", dir.path());
2288    ///     }
2289    ///     Ok(())
2290    /// }
2291    /// ```
2292    ///
2293    /// This prints output like:
2294    ///
2295    /// ```text
2296    /// ./whatever.txt
2297    /// ./foo.html
2298    /// ./hello_world.rs
2299    /// ```
2300    ///
2301    /// The exact text, of course, depends on what files you have in `.`.
2302    #[inline]
2303    pub fn path(&self) -> &Utf8Path {
2304        &self.path
2305    }
2306
2307    /// Returns the metadata for the file that this entry points at.
2308    ///
2309    /// This function will not traverse symlinks if this entry points at a symlink. To traverse
2310    /// symlinks use [`Utf8Path::metadata`] or [`fs::File::metadata`].
2311    ///
2312    /// # Platform-specific behavior
2313    ///
2314    /// On Windows this function is cheap to call (no extra system calls
2315    /// needed), but on Unix platforms this function is the equivalent of
2316    /// calling `symlink_metadata` on the path.
2317    ///
2318    /// # Examples
2319    ///
2320    /// ```
2321    /// use camino::Utf8Path;
2322    ///
2323    /// if let Ok(entries) = Utf8Path::new(".").read_dir_utf8() {
2324    ///     for entry in entries {
2325    ///         if let Ok(entry) = entry {
2326    ///             // Here, `entry` is a `Utf8DirEntry`.
2327    ///             if let Ok(metadata) = entry.metadata() {
2328    ///                 // Now let's show our entry's permissions!
2329    ///                 println!("{}: {:?}", entry.path(), metadata.permissions());
2330    ///             } else {
2331    ///                 println!("Couldn't get metadata for {}", entry.path());
2332    ///             }
2333    ///         }
2334    ///     }
2335    /// }
2336    /// ```
2337    #[inline]
2338    pub fn metadata(&self) -> io::Result<Metadata> {
2339        self.inner.metadata()
2340    }
2341
2342    /// Returns the file type for the file that this entry points at.
2343    ///
2344    /// This function will not traverse symlinks if this entry points at a
2345    /// symlink.
2346    ///
2347    /// # Platform-specific behavior
2348    ///
2349    /// On Windows and most Unix platforms this function is free (no extra
2350    /// system calls needed), but some Unix platforms may require the equivalent
2351    /// call to `symlink_metadata` to learn about the target file type.
2352    ///
2353    /// # Examples
2354    ///
2355    /// ```
2356    /// use camino::Utf8Path;
2357    ///
2358    /// if let Ok(entries) = Utf8Path::new(".").read_dir_utf8() {
2359    ///     for entry in entries {
2360    ///         if let Ok(entry) = entry {
2361    ///             // Here, `entry` is a `DirEntry`.
2362    ///             if let Ok(file_type) = entry.file_type() {
2363    ///                 // Now let's show our entry's file type!
2364    ///                 println!("{}: {:?}", entry.path(), file_type);
2365    ///             } else {
2366    ///                 println!("Couldn't get file type for {}", entry.path());
2367    ///             }
2368    ///         }
2369    ///     }
2370    /// }
2371    /// ```
2372    #[inline]
2373    pub fn file_type(&self) -> io::Result<fs::FileType> {
2374        self.inner.file_type()
2375    }
2376
2377    /// Returns the bare file name of this directory entry without any other
2378    /// leading path component.
2379    ///
2380    /// # Examples
2381    ///
2382    /// ```
2383    /// use camino::Utf8Path;
2384    ///
2385    /// if let Ok(entries) = Utf8Path::new(".").read_dir_utf8() {
2386    ///     for entry in entries {
2387    ///         if let Ok(entry) = entry {
2388    ///             // Here, `entry` is a `DirEntry`.
2389    ///             println!("{}", entry.file_name());
2390    ///         }
2391    ///     }
2392    /// }
2393    /// ```
2394    pub fn file_name(&self) -> &str {
2395        self.path
2396            .file_name()
2397            .expect("path created through DirEntry must have a filename")
2398    }
2399
2400    /// Returns the original [`fs::DirEntry`] within this [`Utf8DirEntry`].
2401    #[inline]
2402    pub fn into_inner(self) -> fs::DirEntry {
2403        self.inner
2404    }
2405
2406    /// Returns the full path to the file that this entry represents.
2407    ///
2408    /// This is analogous to [`path`], but moves ownership of the path.
2409    ///
2410    /// [`path`]: struct.Utf8DirEntry.html#method.path
2411    #[inline]
2412    #[must_use = "`self` will be dropped if the result is not used"]
2413    pub fn into_path(self) -> Utf8PathBuf {
2414        self.path
2415    }
2416}
2417
2418impl From<String> for Utf8PathBuf {
2419    fn from(string: String) -> Utf8PathBuf {
2420        Utf8PathBuf(string.into())
2421    }
2422}
2423
2424impl FromStr for Utf8PathBuf {
2425    type Err = Infallible;
2426
2427    fn from_str(s: &str) -> Result<Self, Self::Err> {
2428        Ok(Utf8PathBuf(s.into()))
2429    }
2430}
2431
2432// ---
2433// From impls: borrowed -> borrowed
2434// ---
2435
2436impl<'a> From<&'a str> for &'a Utf8Path {
2437    fn from(s: &'a str) -> &'a Utf8Path {
2438        Utf8Path::new(s)
2439    }
2440}
2441
2442// ---
2443// From impls: borrowed -> owned
2444// ---
2445
2446impl<T: ?Sized + AsRef<str>> From<&T> for Utf8PathBuf {
2447    fn from(s: &T) -> Utf8PathBuf {
2448        Utf8PathBuf::from(s.as_ref().to_owned())
2449    }
2450}
2451
2452impl<T: ?Sized + AsRef<str>> From<&T> for Box<Utf8Path> {
2453    fn from(s: &T) -> Box<Utf8Path> {
2454        Utf8PathBuf::from(s).into_boxed_path()
2455    }
2456}
2457
2458impl From<&'_ Utf8Path> for Arc<Utf8Path> {
2459    fn from(path: &Utf8Path) -> Arc<Utf8Path> {
2460        let arc: Arc<Path> = Arc::from(AsRef::<Path>::as_ref(path));
2461        let ptr = Arc::into_raw(arc) as *const Utf8Path;
2462        // SAFETY:
2463        // * path is valid UTF-8
2464        // * ptr was created by consuming an Arc<Path> so it represents an arced pointer
2465        // * Utf8Path is marked as #[repr(transparent)] so the conversion from *const Path to
2466        //   *const Utf8Path is valid
2467        unsafe { Arc::from_raw(ptr) }
2468    }
2469}
2470
2471impl From<&'_ Utf8Path> for Rc<Utf8Path> {
2472    fn from(path: &Utf8Path) -> Rc<Utf8Path> {
2473        let rc: Rc<Path> = Rc::from(AsRef::<Path>::as_ref(path));
2474        let ptr = Rc::into_raw(rc) as *const Utf8Path;
2475        // SAFETY:
2476        // * path is valid UTF-8
2477        // * ptr was created by consuming an Rc<Path> so it represents an rced pointer
2478        // * Utf8Path is marked as #[repr(transparent)] so the conversion from *const Path to
2479        //   *const Utf8Path is valid
2480        unsafe { Rc::from_raw(ptr) }
2481    }
2482}
2483
2484impl<'a> From<&'a Utf8Path> for Cow<'a, Utf8Path> {
2485    fn from(path: &'a Utf8Path) -> Cow<'a, Utf8Path> {
2486        Cow::Borrowed(path)
2487    }
2488}
2489
2490impl From<&'_ Utf8Path> for Box<Path> {
2491    fn from(path: &Utf8Path) -> Box<Path> {
2492        AsRef::<Path>::as_ref(path).into()
2493    }
2494}
2495
2496impl From<&'_ Utf8Path> for Arc<Path> {
2497    fn from(path: &Utf8Path) -> Arc<Path> {
2498        AsRef::<Path>::as_ref(path).into()
2499    }
2500}
2501
2502impl From<&'_ Utf8Path> for Rc<Path> {
2503    fn from(path: &Utf8Path) -> Rc<Path> {
2504        AsRef::<Path>::as_ref(path).into()
2505    }
2506}
2507
2508impl<'a> From<&'a Utf8Path> for Cow<'a, Path> {
2509    fn from(path: &'a Utf8Path) -> Cow<'a, Path> {
2510        Cow::Borrowed(path.as_ref())
2511    }
2512}
2513
2514// ---
2515// From impls: owned -> owned
2516// ---
2517
2518impl From<Box<Utf8Path>> for Utf8PathBuf {
2519    fn from(path: Box<Utf8Path>) -> Utf8PathBuf {
2520        path.into_path_buf()
2521    }
2522}
2523
2524impl From<Utf8PathBuf> for Box<Utf8Path> {
2525    fn from(path: Utf8PathBuf) -> Box<Utf8Path> {
2526        path.into_boxed_path()
2527    }
2528}
2529
2530impl<'a> From<Cow<'a, Utf8Path>> for Utf8PathBuf {
2531    fn from(path: Cow<'a, Utf8Path>) -> Utf8PathBuf {
2532        path.into_owned()
2533    }
2534}
2535
2536impl From<Utf8PathBuf> for String {
2537    fn from(path: Utf8PathBuf) -> String {
2538        path.into_string()
2539    }
2540}
2541
2542impl From<Utf8PathBuf> for OsString {
2543    fn from(path: Utf8PathBuf) -> OsString {
2544        path.into_os_string()
2545    }
2546}
2547
2548impl<'a> From<Utf8PathBuf> for Cow<'a, Utf8Path> {
2549    fn from(path: Utf8PathBuf) -> Cow<'a, Utf8Path> {
2550        Cow::Owned(path)
2551    }
2552}
2553
2554impl From<Utf8PathBuf> for Arc<Utf8Path> {
2555    fn from(path: Utf8PathBuf) -> Arc<Utf8Path> {
2556        let arc: Arc<Path> = Arc::from(path.0);
2557        let ptr = Arc::into_raw(arc) as *const Utf8Path;
2558        // SAFETY:
2559        // * path is valid UTF-8
2560        // * ptr was created by consuming an Arc<Path> so it represents an arced pointer
2561        // * Utf8Path is marked as #[repr(transparent)] so the conversion from *const Path to
2562        //   *const Utf8Path is valid
2563        unsafe { Arc::from_raw(ptr) }
2564    }
2565}
2566
2567impl From<Utf8PathBuf> for Rc<Utf8Path> {
2568    fn from(path: Utf8PathBuf) -> Rc<Utf8Path> {
2569        let rc: Rc<Path> = Rc::from(path.0);
2570        let ptr = Rc::into_raw(rc) as *const Utf8Path;
2571        // SAFETY:
2572        // * path is valid UTF-8
2573        // * ptr was created by consuming an Rc<Path> so it represents an rced pointer
2574        // * Utf8Path is marked as #[repr(transparent)] so the conversion from *const Path to
2575        //   *const Utf8Path is valid
2576        unsafe { Rc::from_raw(ptr) }
2577    }
2578}
2579
2580impl From<Utf8PathBuf> for PathBuf {
2581    fn from(path: Utf8PathBuf) -> PathBuf {
2582        path.0
2583    }
2584}
2585
2586impl From<Utf8PathBuf> for Box<Path> {
2587    fn from(path: Utf8PathBuf) -> Box<Path> {
2588        PathBuf::from(path).into_boxed_path()
2589    }
2590}
2591
2592impl From<Utf8PathBuf> for Arc<Path> {
2593    fn from(path: Utf8PathBuf) -> Arc<Path> {
2594        PathBuf::from(path).into()
2595    }
2596}
2597
2598impl From<Utf8PathBuf> for Rc<Path> {
2599    fn from(path: Utf8PathBuf) -> Rc<Path> {
2600        PathBuf::from(path).into()
2601    }
2602}
2603
2604impl<'a> From<Utf8PathBuf> for Cow<'a, Path> {
2605    fn from(path: Utf8PathBuf) -> Cow<'a, Path> {
2606        PathBuf::from(path).into()
2607    }
2608}
2609
2610// ---
2611// TryFrom impls
2612// ---
2613
2614impl TryFrom<PathBuf> for Utf8PathBuf {
2615    type Error = FromPathBufError;
2616
2617    fn try_from(path: PathBuf) -> Result<Utf8PathBuf, Self::Error> {
2618        Utf8PathBuf::from_path_buf(path).map_err(|path| FromPathBufError {
2619            path,
2620            error: FromPathError(()),
2621        })
2622    }
2623}
2624
2625impl TryFrom<OsString> for Utf8PathBuf {
2626    type Error = FromOsStringError;
2627
2628    fn try_from(os_string: OsString) -> Result<Utf8PathBuf, Self::Error> {
2629        Utf8PathBuf::from_os_string(os_string).map_err(|os_string| FromOsStringError {
2630            os_string,
2631            error: FromOsStrError(()),
2632        })
2633    }
2634}
2635
2636/// Converts a [`Path`] to a [`Utf8Path`].
2637///
2638/// Returns [`FromPathError`] if the path is not valid UTF-8.
2639///
2640/// # Examples
2641///
2642/// ```
2643/// use camino::Utf8Path;
2644/// use std::convert::TryFrom;
2645/// use std::ffi::OsStr;
2646/// # #[cfg(unix)]
2647/// use std::os::unix::ffi::OsStrExt;
2648/// use std::path::Path;
2649///
2650/// let unicode_path = Path::new("/valid/unicode");
2651/// <&Utf8Path>::try_from(unicode_path).expect("valid Unicode path succeeded");
2652///
2653/// // Paths on Unix can be non-UTF-8.
2654/// # #[cfg(unix)]
2655/// let non_unicode_str = OsStr::from_bytes(b"\xFF\xFF\xFF");
2656/// # #[cfg(unix)]
2657/// let non_unicode_path = Path::new(non_unicode_str);
2658/// # #[cfg(unix)]
2659/// assert!(<&Utf8Path>::try_from(non_unicode_path).is_err(), "non-Unicode path failed");
2660/// ```
2661impl<'a> TryFrom<&'a Path> for &'a Utf8Path {
2662    type Error = FromPathError;
2663
2664    fn try_from(path: &'a Path) -> Result<&'a Utf8Path, Self::Error> {
2665        Utf8Path::from_path(path).ok_or(FromPathError(()))
2666    }
2667}
2668
2669/// Converts an [`OsStr`] to a [`Utf8Path`].
2670///
2671/// Returns the original [`OsStr`] if it is not valid UTF-8.
2672///
2673/// # Examples
2674///
2675/// ```
2676/// use camino::Utf8Path;
2677/// use std::convert::TryFrom;
2678/// use std::ffi::OsStr;
2679/// # #[cfg(unix)]
2680/// use std::os::unix::ffi::OsStrExt;
2681/// use std::path::Path;
2682///
2683/// # #[cfg(unix)]
2684/// let non_unicode_str = OsStr::from_bytes(b"\xFF\xFF\xFF");
2685/// # #[cfg(unix)]
2686/// assert!(<&Utf8Path>::try_from(non_unicode_str).is_err(), "non-Unicode string path failed");
2687/// ```
2688impl<'a> TryFrom<&'a OsStr> for &'a Utf8Path {
2689    type Error = FromOsStrError;
2690
2691    fn try_from(os_str: &'a OsStr) -> Result<&'a Utf8Path, Self::Error> {
2692        Utf8Path::from_os_str(os_str).ok_or(FromOsStrError(()))
2693    }
2694}
2695
2696/// A possible error value while converting a [`PathBuf`] to a [`Utf8PathBuf`].
2697///
2698/// Produced by the [`TryFrom<&PathBuf>`][tryfrom] implementation for [`Utf8PathBuf`].
2699///
2700/// [tryfrom]: Utf8PathBuf#impl-TryFrom<PathBuf>-for-Utf8PathBuf
2701///
2702/// # Examples
2703///
2704/// ```
2705/// use camino::{Utf8PathBuf, FromPathBufError};
2706/// use std::convert::{TryFrom, TryInto};
2707/// use std::ffi::OsStr;
2708/// # #[cfg(unix)]
2709/// use std::os::unix::ffi::OsStrExt;
2710/// use std::path::PathBuf;
2711///
2712/// let unicode_path = PathBuf::from("/valid/unicode");
2713/// let utf8_path_buf: Utf8PathBuf = unicode_path.try_into().expect("valid Unicode path succeeded");
2714///
2715/// // Paths on Unix can be non-UTF-8.
2716/// # #[cfg(unix)]
2717/// let non_unicode_str = OsStr::from_bytes(b"\xFF\xFF\xFF");
2718/// # #[cfg(unix)]
2719/// let non_unicode_path = PathBuf::from(non_unicode_str);
2720/// # #[cfg(unix)]
2721/// let err: FromPathBufError = Utf8PathBuf::try_from(non_unicode_path.clone())
2722///     .expect_err("non-Unicode path failed");
2723/// # #[cfg(unix)]
2724/// assert_eq!(err.as_path(), &non_unicode_path);
2725/// # #[cfg(unix)]
2726/// assert_eq!(err.into_path_buf(), non_unicode_path);
2727/// ```
2728#[derive(Clone, Debug, Eq, PartialEq)]
2729pub struct FromPathBufError {
2730    path: PathBuf,
2731    error: FromPathError,
2732}
2733
2734impl FromPathBufError {
2735    /// Returns the [`Path`] slice that was attempted to be converted to [`Utf8PathBuf`].
2736    #[inline]
2737    pub fn as_path(&self) -> &Path {
2738        &self.path
2739    }
2740
2741    /// Returns the [`PathBuf`] that was attempted to be converted to [`Utf8PathBuf`].
2742    #[inline]
2743    pub fn into_path_buf(self) -> PathBuf {
2744        self.path
2745    }
2746
2747    /// Fetches a [`FromPathError`] for more about the conversion failure.
2748    ///
2749    /// At the moment this struct does not contain any additional information, but is provided for
2750    /// completeness.
2751    #[inline]
2752    pub fn from_path_error(&self) -> FromPathError {
2753        self.error
2754    }
2755
2756    /// Converts self into a [`std::io::Error`] with kind
2757    /// [`InvalidData`](io::ErrorKind::InvalidData).
2758    ///
2759    /// Many users of [`FromPathBufError`] will want to convert it into an [`io::Error`]. This is a
2760    /// convenience method to do that.
2761    pub fn into_io_error(self) -> io::Error {
2762        // NOTE: we don't currently implement `From<FromPathBufError> for io::Error` because we want
2763        // to ensure the user actually desires that conversion.
2764        io::Error::new(io::ErrorKind::InvalidData, self)
2765    }
2766}
2767
2768impl fmt::Display for FromPathBufError {
2769    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2770        write!(f, "PathBuf contains invalid UTF-8: {}", self.path.display())
2771    }
2772}
2773
2774impl error::Error for FromPathBufError {
2775    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
2776        Some(&self.error)
2777    }
2778}
2779
2780/// A possible error value while converting a [`Path`] to a [`Utf8Path`].
2781///
2782/// Produced by the [`TryFrom<&Path>`][tryfrom] implementation for [`&Utf8Path`](Utf8Path).
2783///
2784/// [tryfrom]: Utf8Path#impl-TryFrom<%26Path>-for-%26Utf8Path
2785///
2786///
2787/// # Examples
2788///
2789/// ```
2790/// use camino::{Utf8Path, FromPathError};
2791/// use std::convert::{TryFrom, TryInto};
2792/// use std::ffi::OsStr;
2793/// # #[cfg(unix)]
2794/// use std::os::unix::ffi::OsStrExt;
2795/// use std::path::Path;
2796///
2797/// let unicode_path = Path::new("/valid/unicode");
2798/// let utf8_path: &Utf8Path = unicode_path.try_into().expect("valid Unicode path succeeded");
2799///
2800/// // Paths on Unix can be non-UTF-8.
2801/// # #[cfg(unix)]
2802/// let non_unicode_str = OsStr::from_bytes(b"\xFF\xFF\xFF");
2803/// # #[cfg(unix)]
2804/// let non_unicode_path = Path::new(non_unicode_str);
2805/// # #[cfg(unix)]
2806/// let err: FromPathError = <&Utf8Path>::try_from(non_unicode_path)
2807///     .expect_err("non-Unicode path failed");
2808/// ```
2809#[derive(Copy, Clone, Debug, Eq, PartialEq)]
2810pub struct FromPathError(());
2811
2812impl FromPathError {
2813    /// Converts self into a [`std::io::Error`] with kind
2814    /// [`InvalidData`](io::ErrorKind::InvalidData).
2815    ///
2816    /// Many users of [`FromPathError`] will want to convert it into an [`io::Error`]. This is a
2817    /// convenience method to do that.
2818    pub fn into_io_error(self) -> io::Error {
2819        // NOTE: we don't currently implement `From<FromPathError> for io::Error` because we want
2820        // to ensure the user actually desires that conversion.
2821        io::Error::new(io::ErrorKind::InvalidData, self)
2822    }
2823}
2824
2825impl fmt::Display for FromPathError {
2826    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2827        write!(f, "Path contains invalid UTF-8")
2828    }
2829}
2830
2831impl error::Error for FromPathError {
2832    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
2833        None
2834    }
2835}
2836
2837/// A possible error value while converting a [`OsString`] to a [`Utf8PathBuf`].
2838///
2839/// Produced by the `TryFrom<OsString>` implementation for [`Utf8PathBuf`].
2840///
2841/// # Examples
2842///
2843/// ```
2844/// # #[cfg(osstring_from_str)] {
2845/// use camino::{Utf8PathBuf, FromOsStringError};
2846/// use std::convert::{TryFrom, TryInto};
2847/// use std::ffi::OsStr;
2848/// use std::str::FromStr;
2849/// use std::ffi::OsString;
2850/// # #[cfg(unix)]
2851/// use std::os::unix::ffi::OsStrExt;
2852///
2853/// let unicode_string = OsString::from_str("/valid/unicode").unwrap();
2854/// let utf8_path_buf: Utf8PathBuf = unicode_string.try_into()
2855///     .expect("valid Unicode path succeeded");
2856///
2857/// // Paths on Unix can be non-UTF-8.
2858/// # #[cfg(unix)]
2859/// let non_unicode_string = OsStr::from_bytes(b"\xFF\xFF\xFF").to_owned();
2860/// # #[cfg(unix)]
2861/// let err: FromOsStringError = Utf8PathBuf::try_from(non_unicode_string.clone())
2862///     .expect_err("non-Unicode path failed");
2863/// # #[cfg(unix)]
2864/// assert_eq!(err.as_os_str(), &non_unicode_string);
2865/// # #[cfg(unix)]
2866/// assert_eq!(err.into_os_string(), non_unicode_string);
2867/// # }
2868/// ```
2869#[derive(Clone, Debug, Eq, PartialEq)]
2870pub struct FromOsStringError {
2871    os_string: OsString,
2872    error: FromOsStrError,
2873}
2874
2875impl FromOsStringError {
2876    /// Returns the [`OsStr`] slice that was attempted to be converted to [`Utf8PathBuf`].
2877    #[inline]
2878    pub fn as_os_str(&self) -> &OsStr {
2879        &self.os_string
2880    }
2881
2882    /// Returns the [`OsString`] that was attempted to be converted to [`Utf8PathBuf`].
2883    #[inline]
2884    pub fn into_os_string(self) -> OsString {
2885        self.os_string
2886    }
2887
2888    /// Fetches a [`FromOsStrError`] for more about the conversion failure.
2889    ///
2890    /// At the moment this struct does not contain any additional information, but is provided for
2891    /// completeness.
2892    #[inline]
2893    pub fn from_os_str_error(&self) -> FromOsStrError {
2894        self.error
2895    }
2896
2897    /// Converts self into a [`std::io::Error`] with kind
2898    /// [`InvalidData`](io::ErrorKind::InvalidData).
2899    ///
2900    /// Many users of [`FromOsStringError`] will want to convert it into an [`io::Error`].
2901    /// This is a convenience method to do that.
2902    pub fn into_io_error(self) -> io::Error {
2903        // NOTE: we don't currently implement `From<FromOsStringError> for io::Error`
2904        // because we want to ensure the user actually desires that conversion.
2905        io::Error::new(io::ErrorKind::InvalidData, self)
2906    }
2907}
2908
2909impl fmt::Display for FromOsStringError {
2910    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2911        write!(
2912            f,
2913            "OsString contains invalid UTF-8: {}",
2914            // self.os_string.display() // this item is stable since `1.87.0`
2915            PathBuf::from(&self.os_string).display() // msrv hack
2916        )
2917    }
2918}
2919
2920impl error::Error for FromOsStringError {
2921    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
2922        Some(&self.error)
2923    }
2924}
2925
2926/// A possible error value while converting a [`OsStr`] to a [`Utf8Path`].
2927///
2928/// Produced by the `TryFrom<&OsStr>` implementation for [`&Utf8Path`](Utf8Path).
2929///
2930///
2931/// # Examples
2932///
2933/// ```
2934/// use camino::{Utf8Path, FromOsStrError};
2935/// use std::convert::{TryFrom, TryInto};
2936/// use std::ffi::OsStr;
2937/// # #[cfg(unix)]
2938/// use std::os::unix::ffi::OsStrExt;
2939///
2940/// let unicode_str = OsStr::new("/valid/unicode");
2941/// let utf8_path: &Utf8Path = unicode_str.try_into().expect("valid Unicode path succeeded");
2942///
2943/// // Paths on Unix can be non-UTF-8.
2944/// # #[cfg(unix)]
2945/// let non_unicode_str = OsStr::from_bytes(b"\xFF\xFF\xFF");
2946/// # #[cfg(unix)]
2947/// let err: FromOsStrError = <&Utf8Path>::try_from(non_unicode_str)
2948///     .expect_err("non-Unicode path failed");
2949/// ```
2950#[derive(Copy, Clone, Debug, Eq, PartialEq)]
2951pub struct FromOsStrError(());
2952
2953impl FromOsStrError {
2954    /// Converts self into a [`std::io::Error`] with kind
2955    /// [`InvalidData`](io::ErrorKind::InvalidData).
2956    ///
2957    /// Many users of [`FromOsStrError`] will want to convert it into an [`io::Error`]. This is a
2958    /// convenience method to do that.
2959    pub fn into_io_error(self) -> io::Error {
2960        // NOTE: we don't currently implement `From<FromOsStrError> for io::Error`
2961        // because we want to ensure the user actually desires that conversion.
2962        io::Error::new(io::ErrorKind::InvalidData, self)
2963    }
2964}
2965
2966impl fmt::Display for FromOsStrError {
2967    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2968        write!(f, "OsStr contains invalid UTF-8")
2969    }
2970}
2971
2972impl error::Error for FromOsStrError {
2973    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
2974        None
2975    }
2976}
2977
2978// ---
2979// AsRef impls
2980// ---
2981
2982impl AsRef<Utf8Path> for Utf8Path {
2983    #[inline]
2984    fn as_ref(&self) -> &Utf8Path {
2985        self
2986    }
2987}
2988
2989impl AsRef<Utf8Path> for Utf8PathBuf {
2990    #[inline]
2991    fn as_ref(&self) -> &Utf8Path {
2992        self.as_path()
2993    }
2994}
2995
2996impl AsRef<Utf8Path> for str {
2997    #[inline]
2998    fn as_ref(&self) -> &Utf8Path {
2999        Utf8Path::new(self)
3000    }
3001}
3002
3003impl AsRef<Utf8Path> for String {
3004    #[inline]
3005    fn as_ref(&self) -> &Utf8Path {
3006        Utf8Path::new(self)
3007    }
3008}
3009
3010impl AsRef<Path> for Utf8Path {
3011    #[inline]
3012    fn as_ref(&self) -> &Path {
3013        &self.0
3014    }
3015}
3016
3017impl AsRef<Path> for Utf8PathBuf {
3018    #[inline]
3019    fn as_ref(&self) -> &Path {
3020        &self.0
3021    }
3022}
3023
3024impl AsRef<str> for Utf8Path {
3025    #[inline]
3026    fn as_ref(&self) -> &str {
3027        self.as_str()
3028    }
3029}
3030
3031impl AsRef<str> for Utf8PathBuf {
3032    #[inline]
3033    fn as_ref(&self) -> &str {
3034        self.as_str()
3035    }
3036}
3037
3038impl AsRef<OsStr> for Utf8Path {
3039    #[inline]
3040    fn as_ref(&self) -> &OsStr {
3041        self.as_os_str()
3042    }
3043}
3044
3045impl AsRef<OsStr> for Utf8PathBuf {
3046    #[inline]
3047    fn as_ref(&self) -> &OsStr {
3048        self.as_os_str()
3049    }
3050}
3051
3052// ---
3053// Borrow and ToOwned
3054// ---
3055
3056impl Borrow<Utf8Path> for Utf8PathBuf {
3057    #[inline]
3058    fn borrow(&self) -> &Utf8Path {
3059        self.as_path()
3060    }
3061}
3062
3063impl ToOwned for Utf8Path {
3064    type Owned = Utf8PathBuf;
3065
3066    #[inline]
3067    fn to_owned(&self) -> Utf8PathBuf {
3068        self.to_path_buf()
3069    }
3070}
3071
3072impl<P: AsRef<Utf8Path>> std::iter::FromIterator<P> for Utf8PathBuf {
3073    fn from_iter<I: IntoIterator<Item = P>>(iter: I) -> Utf8PathBuf {
3074        let mut buf = Utf8PathBuf::new();
3075        buf.extend(iter);
3076        buf
3077    }
3078}
3079
3080// ---
3081// [Partial]Eq, [Partial]Ord, Hash
3082// ---
3083
3084impl PartialEq for Utf8PathBuf {
3085    #[inline]
3086    fn eq(&self, other: &Utf8PathBuf) -> bool {
3087        self.components() == other.components()
3088    }
3089}
3090
3091impl Eq for Utf8PathBuf {}
3092
3093impl Hash for Utf8PathBuf {
3094    #[inline]
3095    fn hash<H: Hasher>(&self, state: &mut H) {
3096        self.as_path().hash(state)
3097    }
3098}
3099
3100impl PartialOrd for Utf8PathBuf {
3101    #[inline]
3102    fn partial_cmp(&self, other: &Utf8PathBuf) -> Option<Ordering> {
3103        Some(self.cmp(other))
3104    }
3105}
3106
3107impl Ord for Utf8PathBuf {
3108    fn cmp(&self, other: &Utf8PathBuf) -> Ordering {
3109        self.components().cmp(other.components())
3110    }
3111}
3112
3113impl PartialEq for Utf8Path {
3114    #[inline]
3115    fn eq(&self, other: &Utf8Path) -> bool {
3116        self.components().eq(other.components())
3117    }
3118}
3119
3120impl Eq for Utf8Path {}
3121
3122impl Hash for Utf8Path {
3123    fn hash<H: Hasher>(&self, state: &mut H) {
3124        for component in self.components() {
3125            component.hash(state)
3126        }
3127    }
3128}
3129
3130impl PartialOrd for Utf8Path {
3131    #[inline]
3132    fn partial_cmp(&self, other: &Utf8Path) -> Option<Ordering> {
3133        Some(self.cmp(other))
3134    }
3135}
3136
3137impl Ord for Utf8Path {
3138    fn cmp(&self, other: &Utf8Path) -> Ordering {
3139        self.components().cmp(other.components())
3140    }
3141}
3142
3143impl<'a> IntoIterator for &'a Utf8PathBuf {
3144    type Item = &'a str;
3145    type IntoIter = Iter<'a>;
3146    #[inline]
3147    fn into_iter(self) -> Iter<'a> {
3148        self.iter()
3149    }
3150}
3151
3152impl<'a> IntoIterator for &'a Utf8Path {
3153    type Item = &'a str;
3154    type IntoIter = Iter<'a>;
3155    #[inline]
3156    fn into_iter(self) -> Iter<'a> {
3157        self.iter()
3158    }
3159}
3160
3161macro_rules! impl_cmp {
3162    ($lhs:ty, $rhs: ty) => {
3163        #[allow(clippy::extra_unused_lifetimes)]
3164        impl<'a, 'b> PartialEq<$rhs> for $lhs {
3165            #[inline]
3166            fn eq(&self, other: &$rhs) -> bool {
3167                <Utf8Path as PartialEq>::eq(self, other)
3168            }
3169        }
3170
3171        #[allow(clippy::extra_unused_lifetimes)]
3172        impl<'a, 'b> PartialEq<$lhs> for $rhs {
3173            #[inline]
3174            fn eq(&self, other: &$lhs) -> bool {
3175                <Utf8Path as PartialEq>::eq(self, other)
3176            }
3177        }
3178
3179        #[allow(clippy::extra_unused_lifetimes)]
3180        impl<'a, 'b> PartialOrd<$rhs> for $lhs {
3181            #[inline]
3182            fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> {
3183                <Utf8Path as PartialOrd>::partial_cmp(self, other)
3184            }
3185        }
3186
3187        #[allow(clippy::extra_unused_lifetimes)]
3188        impl<'a, 'b> PartialOrd<$lhs> for $rhs {
3189            #[inline]
3190            fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> {
3191                <Utf8Path as PartialOrd>::partial_cmp(self, other)
3192            }
3193        }
3194    };
3195}
3196
3197impl_cmp!(Utf8PathBuf, Utf8Path);
3198impl_cmp!(Utf8PathBuf, &'a Utf8Path);
3199impl_cmp!(Cow<'a, Utf8Path>, Utf8Path);
3200impl_cmp!(Cow<'a, Utf8Path>, &'b Utf8Path);
3201impl_cmp!(Cow<'a, Utf8Path>, Utf8PathBuf);
3202
3203macro_rules! impl_cmp_std_path {
3204    ($lhs:ty, $rhs: ty) => {
3205        #[allow(clippy::extra_unused_lifetimes)]
3206        impl<'a, 'b> PartialEq<$rhs> for $lhs {
3207            #[inline]
3208            fn eq(&self, other: &$rhs) -> bool {
3209                <Path as PartialEq>::eq(self.as_ref(), other)
3210            }
3211        }
3212
3213        #[allow(clippy::extra_unused_lifetimes)]
3214        impl<'a, 'b> PartialEq<$lhs> for $rhs {
3215            #[inline]
3216            fn eq(&self, other: &$lhs) -> bool {
3217                <Path as PartialEq>::eq(self, other.as_ref())
3218            }
3219        }
3220
3221        #[allow(clippy::extra_unused_lifetimes)]
3222        impl<'a, 'b> PartialOrd<$rhs> for $lhs {
3223            #[inline]
3224            fn partial_cmp(&self, other: &$rhs) -> Option<std::cmp::Ordering> {
3225                <Path as PartialOrd>::partial_cmp(self.as_ref(), other)
3226            }
3227        }
3228
3229        #[allow(clippy::extra_unused_lifetimes)]
3230        impl<'a, 'b> PartialOrd<$lhs> for $rhs {
3231            #[inline]
3232            fn partial_cmp(&self, other: &$lhs) -> Option<std::cmp::Ordering> {
3233                <Path as PartialOrd>::partial_cmp(self, other.as_ref())
3234            }
3235        }
3236    };
3237}
3238
3239impl_cmp_std_path!(Utf8PathBuf, Path);
3240impl_cmp_std_path!(Utf8PathBuf, &'a Path);
3241impl_cmp_std_path!(Utf8PathBuf, Cow<'a, Path>);
3242impl_cmp_std_path!(Utf8PathBuf, PathBuf);
3243impl_cmp_std_path!(Utf8Path, Path);
3244impl_cmp_std_path!(Utf8Path, &'a Path);
3245impl_cmp_std_path!(Utf8Path, Cow<'a, Path>);
3246impl_cmp_std_path!(Utf8Path, PathBuf);
3247impl_cmp_std_path!(&'a Utf8Path, Path);
3248impl_cmp_std_path!(&'a Utf8Path, Cow<'b, Path>);
3249impl_cmp_std_path!(&'a Utf8Path, PathBuf);
3250// NOTE: impls for Cow<'a, Utf8Path> cannot be defined because of the orphan rule (E0117)
3251
3252macro_rules! impl_cmp_str {
3253    ($lhs:ty, $rhs: ty) => {
3254        #[allow(clippy::extra_unused_lifetimes)]
3255        impl<'a, 'b> PartialEq<$rhs> for $lhs {
3256            #[inline]
3257            fn eq(&self, other: &$rhs) -> bool {
3258                <Utf8Path as PartialEq>::eq(self, Utf8Path::new(other))
3259            }
3260        }
3261
3262        #[allow(clippy::extra_unused_lifetimes)]
3263        impl<'a, 'b> PartialEq<$lhs> for $rhs {
3264            #[inline]
3265            fn eq(&self, other: &$lhs) -> bool {
3266                <Utf8Path as PartialEq>::eq(Utf8Path::new(self), other)
3267            }
3268        }
3269
3270        #[allow(clippy::extra_unused_lifetimes)]
3271        impl<'a, 'b> PartialOrd<$rhs> for $lhs {
3272            #[inline]
3273            fn partial_cmp(&self, other: &$rhs) -> Option<std::cmp::Ordering> {
3274                <Utf8Path as PartialOrd>::partial_cmp(self, Utf8Path::new(other))
3275            }
3276        }
3277
3278        #[allow(clippy::extra_unused_lifetimes)]
3279        impl<'a, 'b> PartialOrd<$lhs> for $rhs {
3280            #[inline]
3281            fn partial_cmp(&self, other: &$lhs) -> Option<std::cmp::Ordering> {
3282                <Utf8Path as PartialOrd>::partial_cmp(Utf8Path::new(self), other)
3283            }
3284        }
3285    };
3286}
3287
3288impl_cmp_str!(Utf8PathBuf, str);
3289impl_cmp_str!(Utf8PathBuf, &'a str);
3290impl_cmp_str!(Utf8PathBuf, Cow<'a, str>);
3291impl_cmp_str!(Utf8PathBuf, String);
3292impl_cmp_str!(Utf8Path, str);
3293impl_cmp_str!(Utf8Path, &'a str);
3294impl_cmp_str!(Utf8Path, Cow<'a, str>);
3295impl_cmp_str!(Utf8Path, String);
3296impl_cmp_str!(&'a Utf8Path, str);
3297impl_cmp_str!(&'a Utf8Path, Cow<'b, str>);
3298impl_cmp_str!(&'a Utf8Path, String);
3299// NOTE: impls for Cow<'a, Utf8Path> cannot be defined because of the orphan rule (E0117)
3300
3301macro_rules! impl_cmp_os_str {
3302    ($lhs:ty, $rhs: ty) => {
3303        #[allow(clippy::extra_unused_lifetimes)]
3304        impl<'a, 'b> PartialEq<$rhs> for $lhs {
3305            #[inline]
3306            fn eq(&self, other: &$rhs) -> bool {
3307                <Path as PartialEq>::eq(self.as_ref(), other.as_ref())
3308            }
3309        }
3310
3311        #[allow(clippy::extra_unused_lifetimes)]
3312        impl<'a, 'b> PartialEq<$lhs> for $rhs {
3313            #[inline]
3314            fn eq(&self, other: &$lhs) -> bool {
3315                <Path as PartialEq>::eq(self.as_ref(), other.as_ref())
3316            }
3317        }
3318
3319        #[allow(clippy::extra_unused_lifetimes)]
3320        impl<'a, 'b> PartialOrd<$rhs> for $lhs {
3321            #[inline]
3322            fn partial_cmp(&self, other: &$rhs) -> Option<std::cmp::Ordering> {
3323                <Path as PartialOrd>::partial_cmp(self.as_ref(), other.as_ref())
3324            }
3325        }
3326
3327        #[allow(clippy::extra_unused_lifetimes)]
3328        impl<'a, 'b> PartialOrd<$lhs> for $rhs {
3329            #[inline]
3330            fn partial_cmp(&self, other: &$lhs) -> Option<std::cmp::Ordering> {
3331                <Path as PartialOrd>::partial_cmp(self.as_ref(), other.as_ref())
3332            }
3333        }
3334    };
3335}
3336
3337impl_cmp_os_str!(Utf8PathBuf, OsStr);
3338impl_cmp_os_str!(Utf8PathBuf, &'a OsStr);
3339impl_cmp_os_str!(Utf8PathBuf, Cow<'a, OsStr>);
3340impl_cmp_os_str!(Utf8PathBuf, OsString);
3341impl_cmp_os_str!(Utf8Path, OsStr);
3342impl_cmp_os_str!(Utf8Path, &'a OsStr);
3343impl_cmp_os_str!(Utf8Path, Cow<'a, OsStr>);
3344impl_cmp_os_str!(Utf8Path, OsString);
3345impl_cmp_os_str!(&'a Utf8Path, OsStr);
3346impl_cmp_os_str!(&'a Utf8Path, Cow<'b, OsStr>);
3347impl_cmp_os_str!(&'a Utf8Path, OsString);
3348// NOTE: impls for Cow<'a, Utf8Path> cannot be defined because of the orphan rule (E0117)
3349
3350/// Makes the path absolute without accessing the filesystem, converting it to a [`Utf8PathBuf`].
3351///
3352/// If the path is relative, the current directory is used as the base directory. All intermediate
3353/// components will be resolved according to platform-specific rules, but unlike
3354/// [`canonicalize`][Utf8Path::canonicalize] or [`canonicalize_utf8`](Utf8Path::canonicalize_utf8),
3355/// this does not resolve symlinks and may succeed even if the path does not exist.
3356///
3357/// *Requires Rust 1.79 or newer.*
3358///
3359/// # Errors
3360///
3361/// Errors if:
3362///
3363/// * The path is empty.
3364/// * The [current directory][std::env::current_dir] cannot be determined.
3365/// * The path is not valid UTF-8.
3366///
3367/// # Examples
3368///
3369/// ## POSIX paths
3370///
3371/// ```
3372/// # #[cfg(unix)]
3373/// fn main() -> std::io::Result<()> {
3374///     use camino::Utf8Path;
3375///
3376///     // Relative to absolute
3377///     let absolute = camino::absolute_utf8("foo/./bar")?;
3378///     assert!(absolute.ends_with("foo/bar"));
3379///
3380///     // Absolute to absolute
3381///     let absolute = camino::absolute_utf8("/foo//test/.././bar.rs")?;
3382///     assert_eq!(absolute, Utf8Path::new("/foo/test/../bar.rs"));
3383///     Ok(())
3384/// }
3385/// # #[cfg(not(unix))]
3386/// # fn main() {}
3387/// ```
3388///
3389/// The path is resolved using [POSIX semantics][posix-semantics] except that it stops short of
3390/// resolving symlinks. This means it will keep `..` components and trailing slashes.
3391///
3392/// ## Windows paths
3393///
3394/// ```
3395/// # #[cfg(windows)]
3396/// fn main() -> std::io::Result<()> {
3397///     use camino::Utf8Path;
3398///
3399///     // Relative to absolute
3400///     let absolute = camino::absolute_utf8("foo/./bar")?;
3401///     assert!(absolute.ends_with(r"foo\bar"));
3402///
3403///     // Absolute to absolute
3404///     let absolute = camino::absolute_utf8(r"C:\foo//test\..\./bar.rs")?;
3405///
3406///     assert_eq!(absolute, Utf8Path::new(r"C:\foo\bar.rs"));
3407///     Ok(())
3408/// }
3409/// # #[cfg(not(windows))]
3410/// # fn main() {}
3411/// ```
3412///
3413/// For verbatim paths this will simply return the path as given. For other paths this is currently
3414/// equivalent to calling [`GetFullPathNameW`][windows-path].
3415///
3416/// Note that this [may change in the future][changes].
3417///
3418/// [changes]: io#platform-specific-behavior
3419/// [posix-semantics]:
3420///     https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13
3421/// [windows-path]:
3422///     https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfullpathnamew
3423#[cfg(absolute_path)]
3424pub fn absolute_utf8<P: AsRef<Path>>(path: P) -> io::Result<Utf8PathBuf> {
3425    // Note that even if the passed in path is valid UTF-8, it is not guaranteed
3426    // that the absolute path will be valid UTF-8. For example, the current
3427    // directory may not be valid UTF-8.
3428    //
3429    // That's why we take `AsRef<Path>` instead of `AsRef<Utf8Path>` here -- we
3430    // have to pay the cost of checking for valid UTF-8 anyway.
3431    let path = path.as_ref();
3432    #[allow(clippy::incompatible_msrv)]
3433    Utf8PathBuf::try_from(std::path::absolute(path)?).map_err(|error| error.into_io_error())
3434}
3435
3436// invariant: OsStr must be guaranteed to be utf8 data
3437#[inline]
3438unsafe fn str_assume_utf8(string: &OsStr) -> &str {
3439    #[cfg(os_str_bytes)]
3440    {
3441        // SAFETY: OsStr is guaranteed to be utf8 data from the invariant
3442        unsafe {
3443            std::str::from_utf8_unchecked(
3444                #[allow(clippy::incompatible_msrv)]
3445                string.as_encoded_bytes(),
3446            )
3447        }
3448    }
3449    #[cfg(not(os_str_bytes))]
3450    {
3451        // Adapted from the source code for Option::unwrap_unchecked.
3452        match string.to_str() {
3453            Some(val) => val,
3454            None => std::hint::unreachable_unchecked(),
3455        }
3456    }
3457}