1 // Copyright (c) The camino Contributors
2 // SPDX-License-Identifier: MIT OR Apache-2.0
3 
4 #![warn(missing_docs)]
5 
6 //! UTF-8 encoded paths.
7 //!
8 //! `camino` is an extension of the `std::path` module that adds new `Utf8PathBuf` and `Utf8Path`
9 //! types. These are like the standard library's [`PathBuf`] and [`Path`] types, except they are
10 //! guaranteed to only contain UTF-8 encoded data. Therefore, they expose the ability to get their
11 //! contents as strings, they implement `Display`, etc.
12 //!
13 //! The `std::path` types are not guaranteed to be valid UTF-8. This is the right decision for the standard library,
14 //! since it must be as general as possible. However, on all platforms, non-Unicode paths are vanishingly uncommon for a
15 //! number of reasons:
16 //! * Unicode won. There are still some legacy codebases that store paths in encodings like Shift-JIS, but most
17 //!   have been converted to Unicode at this point.
18 //! * Unicode is the common subset of supported paths across Windows and Unix platforms. (On Windows, Rust stores paths
19 //!   as [an extension to UTF-8](https://simonsapin.github.io/wtf-8/), and converts them to UTF-16 at Win32
20 //!   API boundaries.)
21 //! * There are already many systems, such as Cargo, that only support UTF-8 paths. If your own tool interacts with any such
22 //!   system, you can assume that paths are valid UTF-8 without creating any additional burdens on consumers.
23 //! * The ["makefile problem"](https://www.mercurial-scm.org/wiki/EncodingStrategy#The_.22makefile_problem.22)
24 //!   (which also applies to `Cargo.toml`, and any other metadata file that lists the names of other files) has *no general,
25 //!   cross-platform solution* in systems that support non-UTF-8 paths. However, restricting paths to UTF-8 eliminates
26 //!   this problem.
27 //!
28 //! Therefore, many programs that want to manipulate paths *do* assume they contain UTF-8 data, and convert them to `str`s
29 //! as  necessary. However, because this invariant is not encoded in the `Path` type, conversions such as
30 //! `path.to_str().unwrap()` need to be repeated again and again, creating a frustrating experience.
31 //!
32 //! Instead, `camino` allows you to check that your paths are UTF-8 *once*, and then manipulate them
33 //! as valid UTF-8 from there on, avoiding repeated lossy and confusing conversions.
34 
35 use std::{
36     borrow::{Borrow, Cow},
37     cmp::Ordering,
38     convert::{Infallible, TryFrom},
39     error,
40     ffi::{OsStr, OsString},
41     fmt, fs,
42     hash::{Hash, Hasher},
43     io,
44     iter::FusedIterator,
45     ops::Deref,
46     path::*,
47     rc::Rc,
48     str::FromStr,
49     sync::Arc,
50 };
51 
52 #[cfg(feature = "serde1")]
53 mod serde_impls;
54 #[cfg(test)]
55 mod tests;
56 
57 /// An owned, mutable UTF-8 path (akin to [`String`]).
58 ///
59 /// This type provides methods like [`push`] and [`set_extension`] that mutate
60 /// the path in place. It also implements [`Deref`] to [`Utf8Path`], meaning that
61 /// all methods on [`Utf8Path`] slices are available on `Utf8PathBuf` values as well.
62 ///
63 /// [`push`]: Utf8PathBuf::push
64 /// [`set_extension`]: Utf8PathBuf::set_extension
65 ///
66 /// # Examples
67 ///
68 /// You can use [`push`] to build up a `Utf8PathBuf` from
69 /// components:
70 ///
71 /// ```
72 /// use camino::Utf8PathBuf;
73 ///
74 /// let mut path = Utf8PathBuf::new();
75 ///
76 /// path.push(r"C:\");
77 /// path.push("windows");
78 /// path.push("system32");
79 ///
80 /// path.set_extension("dll");
81 /// ```
82 ///
83 /// However, [`push`] is best used for dynamic situations. This is a better way
84 /// to do this when you know all of the components ahead of time:
85 ///
86 /// ```
87 /// use camino::Utf8PathBuf;
88 ///
89 /// let path: Utf8PathBuf = [r"C:\", "windows", "system32.dll"].iter().collect();
90 /// ```
91 ///
92 /// We can still do better than this! Since these are all strings, we can use
93 /// `From::from`:
94 ///
95 /// ```
96 /// use camino::Utf8PathBuf;
97 ///
98 /// let path = Utf8PathBuf::from(r"C:\windows\system32.dll");
99 /// ```
100 ///
101 /// Which method works best depends on what kind of situation you're in.
102 // NB: Internal PathBuf must only contain utf8 data
103 #[derive(Clone, Default)]
104 #[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
105 #[cfg_attr(feature = "serde1", serde(transparent))]
106 #[repr(transparent)]
107 pub struct Utf8PathBuf(PathBuf);
108 
109 impl Utf8PathBuf {
110     /// Allocates an empty `Utf8PathBuf`.
111     ///
112     /// # Examples
113     ///
114     /// ```
115     /// use camino::Utf8PathBuf;
116     ///
117     /// let path = Utf8PathBuf::new();
118     /// ```
new() -> Utf8PathBuf119     pub fn new() -> Utf8PathBuf {
120         Utf8PathBuf(PathBuf::new())
121     }
122 
123     /// Creates a new `Utf8PathBuf` from a `PathBuf` containing valid UTF-8 characters.
124     ///
125     /// Errors with the original `PathBuf` if it is not valid UTF-8.
126     ///
127     /// For a version that returns a type that implements [`std::error::Error`], use the
128     /// `TryFrom<PathBuf>` impl.
129     ///
130     /// # Examples
131     ///
132     /// ```
133     /// use camino::Utf8PathBuf;
134     /// use std::ffi::OsStr;
135     /// # #[cfg(unix)]
136     /// use std::os::unix::ffi::OsStrExt;
137     /// use std::path::PathBuf;
138     ///
139     /// let unicode_path = PathBuf::from("/valid/unicode");
140     /// Utf8PathBuf::from_path_buf(unicode_path).expect("valid Unicode path succeeded");
141     ///
142     /// // Paths on Unix can be non-UTF-8.
143     /// # #[cfg(unix)]
144     /// let non_unicode_str = OsStr::from_bytes(b"\xFF\xFF\xFF");
145     /// # #[cfg(unix)]
146     /// let non_unicode_path = PathBuf::from(non_unicode_str);
147     /// # #[cfg(unix)]
148     /// Utf8PathBuf::from_path_buf(non_unicode_path).expect_err("non-Unicode path failed");
149     /// ```
from_path_buf(path: PathBuf) -> Result<Utf8PathBuf, PathBuf>150     pub fn from_path_buf(path: PathBuf) -> Result<Utf8PathBuf, PathBuf> {
151         match path.into_os_string().into_string() {
152             Ok(string) => Ok(Utf8PathBuf::from(string)),
153             Err(os_string) => Err(PathBuf::from(os_string)),
154         }
155     }
156 
157     /// Converts a `Utf8PathBuf` to a [`PathBuf`].
158     ///
159     /// This is equivalent to the `From<Utf8PathBuf> for PathBuf` impl, but may aid in type
160     /// inference.
161     ///
162     /// # Examples
163     ///
164     /// ```
165     /// use camino::Utf8PathBuf;
166     /// use std::path::PathBuf;
167     ///
168     /// let utf8_path_buf = Utf8PathBuf::from("foo.txt");
169     /// let std_path_buf = utf8_path_buf.into_std_path_buf();
170     /// assert_eq!(std_path_buf.to_str(), Some("foo.txt"));
171     ///
172     /// // Convert back to a Utf8PathBuf.
173     /// let new_utf8_path_buf = Utf8PathBuf::from_path_buf(std_path_buf).unwrap();
174     /// assert_eq!(new_utf8_path_buf, "foo.txt");
175     /// ```
into_std_path_buf(self) -> PathBuf176     pub fn into_std_path_buf(self) -> PathBuf {
177         self.into()
178     }
179 
180     /// Creates a new `Utf8PathBuf` with a given capacity used to create the internal [`PathBuf`].
181     /// See [`with_capacity`] defined on [`PathBuf`].
182     ///
183     /// *Requires Rust 1.44 or newer.*
184     ///
185     /// # Examples
186     ///
187     /// ```
188     /// use camino::Utf8PathBuf;
189     ///
190     /// let mut path = Utf8PathBuf::with_capacity(10);
191     /// let capacity = path.capacity();
192     ///
193     /// // This push is done without reallocating
194     /// path.push(r"C:\");
195     ///
196     /// assert_eq!(capacity, path.capacity());
197     /// ```
198     ///
199     /// [`with_capacity`]: PathBuf::with_capacity
200     #[cfg(path_buf_capacity)]
with_capacity(capacity: usize) -> Utf8PathBuf201     pub fn with_capacity(capacity: usize) -> Utf8PathBuf {
202         Utf8PathBuf(PathBuf::with_capacity(capacity))
203     }
204 
205     /// Coerces to a [`Utf8Path`] slice.
206     ///
207     /// # Examples
208     ///
209     /// ```
210     /// use camino::{Utf8Path, Utf8PathBuf};
211     ///
212     /// let p = Utf8PathBuf::from("/test");
213     /// assert_eq!(Utf8Path::new("/test"), p.as_path());
214     /// ```
as_path(&self) -> &Utf8Path215     pub fn as_path(&self) -> &Utf8Path {
216         // SAFETY: every Utf8PathBuf constructor ensures that self is valid UTF-8
217         unsafe { Utf8Path::assume_utf8(&*self.0) }
218     }
219 
220     /// Extends `self` with `path`.
221     ///
222     /// If `path` is absolute, it replaces the current path.
223     ///
224     /// On Windows:
225     ///
226     /// * if `path` has a root but no prefix (e.g., `\windows`), it
227     ///   replaces everything except for the prefix (if any) of `self`.
228     /// * if `path` has a prefix but no root, it replaces `self`.
229     ///
230     /// # Examples
231     ///
232     /// Pushing a relative path extends the existing path:
233     ///
234     /// ```
235     /// use camino::Utf8PathBuf;
236     ///
237     /// let mut path = Utf8PathBuf::from("/tmp");
238     /// path.push("file.bk");
239     /// assert_eq!(path, Utf8PathBuf::from("/tmp/file.bk"));
240     /// ```
241     ///
242     /// Pushing an absolute path replaces the existing path:
243     ///
244     /// ```
245     /// use camino::Utf8PathBuf;
246     ///
247     /// let mut path = Utf8PathBuf::from("/tmp");
248     /// path.push("/etc");
249     /// assert_eq!(path, Utf8PathBuf::from("/etc"));
250     /// ```
push(&mut self, path: impl AsRef<Utf8Path>)251     pub fn push(&mut self, path: impl AsRef<Utf8Path>) {
252         self.0.push(&path.as_ref().0)
253     }
254 
255     /// Truncates `self` to [`self.parent`].
256     ///
257     /// Returns `false` and does nothing if [`self.parent`] is [`None`].
258     /// Otherwise, returns `true`.
259     ///
260     /// [`self.parent`]: Utf8Path::parent
261     ///
262     /// # Examples
263     ///
264     /// ```
265     /// use camino::{Utf8Path, Utf8PathBuf};
266     ///
267     /// let mut p = Utf8PathBuf::from("/spirited/away.rs");
268     ///
269     /// p.pop();
270     /// assert_eq!(Utf8Path::new("/spirited"), p);
271     /// p.pop();
272     /// assert_eq!(Utf8Path::new("/"), p);
273     /// ```
pop(&mut self) -> bool274     pub fn pop(&mut self) -> bool {
275         self.0.pop()
276     }
277 
278     /// Updates [`self.file_name`] to `file_name`.
279     ///
280     /// If [`self.file_name`] was [`None`], this is equivalent to pushing
281     /// `file_name`.
282     ///
283     /// Otherwise it is equivalent to calling [`pop`] and then pushing
284     /// `file_name`. The new path will be a sibling of the original path.
285     /// (That is, it will have the same parent.)
286     ///
287     /// [`self.file_name`]: Utf8Path::file_name
288     /// [`pop`]: Utf8PathBuf::pop
289     ///
290     /// # Examples
291     ///
292     /// ```
293     /// use camino::Utf8PathBuf;
294     ///
295     /// let mut buf = Utf8PathBuf::from("/");
296     /// assert_eq!(buf.file_name(), None);
297     /// buf.set_file_name("bar");
298     /// assert_eq!(buf, Utf8PathBuf::from("/bar"));
299     /// assert!(buf.file_name().is_some());
300     /// buf.set_file_name("baz.txt");
301     /// assert_eq!(buf, Utf8PathBuf::from("/baz.txt"));
302     /// ```
set_file_name(&mut self, file_name: impl AsRef<str>)303     pub fn set_file_name(&mut self, file_name: impl AsRef<str>) {
304         self.0.set_file_name(file_name.as_ref())
305     }
306 
307     /// Updates [`self.extension`] to `extension`.
308     ///
309     /// Returns `false` and does nothing if [`self.file_name`] is [`None`],
310     /// returns `true` and updates the extension otherwise.
311     ///
312     /// If [`self.extension`] is [`None`], the extension is added; otherwise
313     /// it is replaced.
314     ///
315     /// [`self.file_name`]: Utf8Path::file_name
316     /// [`self.extension`]: Utf8Path::extension
317     ///
318     /// # Examples
319     ///
320     /// ```
321     /// use camino::{Utf8Path, Utf8PathBuf};
322     ///
323     /// let mut p = Utf8PathBuf::from("/feel/the");
324     ///
325     /// p.set_extension("force");
326     /// assert_eq!(Utf8Path::new("/feel/the.force"), p.as_path());
327     ///
328     /// p.set_extension("dark_side");
329     /// assert_eq!(Utf8Path::new("/feel/the.dark_side"), p.as_path());
330     /// ```
set_extension(&mut self, extension: impl AsRef<str>) -> bool331     pub fn set_extension(&mut self, extension: impl AsRef<str>) -> bool {
332         self.0.set_extension(extension.as_ref())
333     }
334 
335     /// Consumes the `Utf8PathBuf`, yielding its internal [`String`] storage.
336     ///
337     /// # Examples
338     ///
339     /// ```
340     /// use camino::Utf8PathBuf;
341     ///
342     /// let p = Utf8PathBuf::from("/the/head");
343     /// let s = p.into_string();
344     /// assert_eq!(s, "/the/head");
345     /// ```
into_string(self) -> String346     pub fn into_string(self) -> String {
347         self.into_os_string().into_string().unwrap()
348     }
349 
350     /// Consumes the `Utf8PathBuf`, yielding its internal [`OsString`] storage.
351     ///
352     /// # Examples
353     ///
354     /// ```
355     /// use camino::Utf8PathBuf;
356     /// use std::ffi::OsStr;
357     ///
358     /// let p = Utf8PathBuf::from("/the/head");
359     /// let s = p.into_os_string();
360     /// assert_eq!(s, OsStr::new("/the/head"));
361     /// ```
into_os_string(self) -> OsString362     pub fn into_os_string(self) -> OsString {
363         self.0.into_os_string()
364     }
365 
366     /// Converts this `Utf8PathBuf` into a [boxed](Box) [`Utf8Path`].
into_boxed_path(self) -> Box<Utf8Path>367     pub fn into_boxed_path(self) -> Box<Utf8Path> {
368         let ptr = Box::into_raw(self.0.into_boxed_path()) as *mut Utf8Path;
369         // SAFETY:
370         // * self is valid UTF-8
371         // * ptr was constructed by consuming self so it represents an owned path
372         // * Utf8Path is marked as #[repr(transparent)] so the conversion from *mut Path to
373         //   *mut Utf8Path is valid
374         unsafe { Box::from_raw(ptr) }
375     }
376 
377     /// Invokes [`capacity`] on the underlying instance of [`PathBuf`].
378     ///
379     /// *Requires Rust 1.44 or newer.*
380     ///
381     /// [`capacity`]: PathBuf::capacity
382     #[cfg(path_buf_capacity)]
capacity(&self) -> usize383     pub fn capacity(&self) -> usize {
384         self.0.capacity()
385     }
386 
387     /// Invokes [`clear`] on the underlying instance of [`PathBuf`].
388     ///
389     /// *Requires Rust 1.44 or newer.*
390     ///
391     /// [`clear`]: PathBuf::clear
392     #[cfg(path_buf_capacity)]
clear(&mut self)393     pub fn clear(&mut self) {
394         self.0.clear()
395     }
396 
397     /// Invokes [`reserve`] on the underlying instance of [`PathBuf`].
398     ///
399     /// *Requires Rust 1.44 or newer.*
400     ///
401     /// [`reserve`]: PathBuf::reserve
402     #[cfg(path_buf_capacity)]
reserve(&mut self, additional: usize)403     pub fn reserve(&mut self, additional: usize) {
404         self.0.reserve(additional)
405     }
406 
407     /// Invokes [`reserve_exact`] on the underlying instance of [`PathBuf`].
408     ///
409     /// *Requires Rust 1.44 or newer.*
410     ///
411     /// [`reserve_exact`]: PathBuf::reserve_exact
412     #[cfg(path_buf_capacity)]
reserve_exact(&mut self, additional: usize)413     pub fn reserve_exact(&mut self, additional: usize) {
414         self.0.reserve_exact(additional)
415     }
416 
417     /// Invokes [`shrink_to_fit`] on the underlying instance of [`PathBuf`].
418     ///
419     /// *Requires Rust 1.44 or newer.*
420     ///
421     /// [`shrink_to_fit`]: PathBuf::shrink_to_fit
422     #[cfg(path_buf_capacity)]
shrink_to_fit(&mut self)423     pub fn shrink_to_fit(&mut self) {
424         self.0.shrink_to_fit()
425     }
426 }
427 
428 impl Deref for Utf8PathBuf {
429     type Target = Utf8Path;
430 
deref(&self) -> &Utf8Path431     fn deref(&self) -> &Utf8Path {
432         self.as_path()
433     }
434 }
435 
436 impl fmt::Debug for Utf8PathBuf {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result437     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
438         fmt::Debug::fmt(&**self, f)
439     }
440 }
441 
442 impl fmt::Display for Utf8PathBuf {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result443     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
444         fmt::Display::fmt(self.as_str(), f)
445     }
446 }
447 
448 impl<P: AsRef<Utf8Path>> Extend<P> for Utf8PathBuf {
extend<I: IntoIterator<Item = P>>(&mut self, iter: I)449     fn extend<I: IntoIterator<Item = P>>(&mut self, iter: I) {
450         for path in iter {
451             self.push(path);
452         }
453     }
454 }
455 
456 /// A slice of a UTF-8 path (akin to [`str`]).
457 ///
458 /// This type supports a number of operations for inspecting a path, including
459 /// breaking the path into its components (separated by `/` on Unix and by either
460 /// `/` or `\` on Windows), extracting the file name, determining whether the path
461 /// is absolute, and so on.
462 ///
463 /// This is an *unsized* type, meaning that it must always be used behind a
464 /// pointer like `&` or [`Box`]. For an owned version of this type,
465 /// see [`Utf8PathBuf`].
466 ///
467 /// # Examples
468 ///
469 /// ```
470 /// use camino::Utf8Path;
471 ///
472 /// // Note: this example does work on Windows
473 /// let path = Utf8Path::new("./foo/bar.txt");
474 ///
475 /// let parent = path.parent();
476 /// assert_eq!(parent, Some(Utf8Path::new("./foo")));
477 ///
478 /// let file_stem = path.file_stem();
479 /// assert_eq!(file_stem, Some("bar"));
480 ///
481 /// let extension = path.extension();
482 /// assert_eq!(extension, Some("txt"));
483 /// ```
484 // NB: Internal Path must only contain utf8 data
485 #[repr(transparent)]
486 pub struct Utf8Path(Path);
487 
488 impl Utf8Path {
489     /// Directly wraps a string slice as a `Utf8Path` slice.
490     ///
491     /// This is a cost-free conversion.
492     ///
493     /// # Examples
494     ///
495     /// ```
496     /// use camino::Utf8Path;
497     ///
498     /// Utf8Path::new("foo.txt");
499     /// ```
500     ///
501     /// You can create `Utf8Path`s from `String`s, or even other `Utf8Path`s:
502     ///
503     /// ```
504     /// use camino::Utf8Path;
505     ///
506     /// let string = String::from("foo.txt");
507     /// let from_string = Utf8Path::new(&string);
508     /// let from_path = Utf8Path::new(&from_string);
509     /// assert_eq!(from_string, from_path);
510     /// ```
new(s: &(impl AsRef<str> + ?Sized)) -> &Utf8Path511     pub fn new(s: &(impl AsRef<str> + ?Sized)) -> &Utf8Path {
512         let path = Path::new(s.as_ref());
513         // SAFETY: s is a str which means it is always valid UTF-8
514         unsafe { Utf8Path::assume_utf8(path) }
515     }
516 
517     /// Converts a [`Path`] to a `Utf8Path`.
518     ///
519     /// Returns `None` if the path is not valid UTF-8.
520     ///
521     /// For a version that returns a type that implements [`std::error::Error`], use the
522     /// `TryFrom<&Path>` impl.
523     ///
524     /// # Examples
525     ///
526     /// ```
527     /// use camino::Utf8Path;
528     /// use std::ffi::OsStr;
529     /// # #[cfg(unix)]
530     /// use std::os::unix::ffi::OsStrExt;
531     /// use std::path::Path;
532     ///
533     /// let unicode_path = Path::new("/valid/unicode");
534     /// Utf8Path::from_path(unicode_path).expect("valid Unicode path succeeded");
535     ///
536     /// // Paths on Unix can be non-UTF-8.
537     /// # #[cfg(unix)]
538     /// let non_unicode_str = OsStr::from_bytes(b"\xFF\xFF\xFF");
539     /// # #[cfg(unix)]
540     /// let non_unicode_path = Path::new(non_unicode_str);
541     /// # #[cfg(unix)]
542     /// assert!(Utf8Path::from_path(non_unicode_path).is_none(), "non-Unicode path failed");
543     /// ```
from_path(path: &Path) -> Option<&Utf8Path>544     pub fn from_path(path: &Path) -> Option<&Utf8Path> {
545         path.as_os_str().to_str().map(|s| Utf8Path::new(s))
546     }
547 
548     /// Converts a `Utf8Path` to a [`Path`].
549     ///
550     /// This is equivalent to the `AsRef<&Path> for &Utf8Path` impl, but may aid in type inference.
551     ///
552     /// # Examples
553     ///
554     /// ```
555     /// use camino::Utf8Path;
556     /// use std::path::Path;
557     ///
558     /// let utf8_path = Utf8Path::new("foo.txt");
559     /// let std_path: &Path = utf8_path.as_std_path();
560     /// assert_eq!(std_path.to_str(), Some("foo.txt"));
561     ///
562     /// // Convert back to a Utf8Path.
563     /// let new_utf8_path = Utf8Path::from_path(std_path).unwrap();
564     /// assert_eq!(new_utf8_path, "foo.txt");
565     /// ```
as_std_path(&self) -> &Path566     pub fn as_std_path(&self) -> &Path {
567         self.as_ref()
568     }
569 
570     /// Yields the underlying [`str`] slice.
571     ///
572     /// Unlike [`Path::to_str`], this always returns a slice because the contents of a `Utf8Path`
573     /// are guaranteed to be valid UTF-8.
574     ///
575     /// # Examples
576     ///
577     /// ```
578     /// use camino::Utf8Path;
579     ///
580     /// let s = Utf8Path::new("foo.txt").as_str();
581     /// assert_eq!(s, "foo.txt");
582     /// ```
583     ///
584     /// [`str`]: str
as_str(&self) -> &str585     pub fn as_str(&self) -> &str {
586         // SAFETY: every Utf8Path constructor ensures that self is valid UTF-8
587         unsafe { assume_utf8(self.as_os_str()) }
588     }
589 
590     /// Yields the underlying [`OsStr`] slice.
591     ///
592     /// # Examples
593     ///
594     /// ```
595     /// use camino::Utf8Path;
596     ///
597     /// let os_str = Utf8Path::new("foo.txt").as_os_str();
598     /// assert_eq!(os_str, std::ffi::OsStr::new("foo.txt"));
599     /// ```
as_os_str(&self) -> &OsStr600     pub fn as_os_str(&self) -> &OsStr {
601         self.0.as_os_str()
602     }
603 
604     /// Converts a `Utf8Path` to an owned [`Utf8PathBuf`].
605     ///
606     /// # Examples
607     ///
608     /// ```
609     /// use camino::{Utf8Path, Utf8PathBuf};
610     ///
611     /// let path_buf = Utf8Path::new("foo.txt").to_path_buf();
612     /// assert_eq!(path_buf, Utf8PathBuf::from("foo.txt"));
613     /// ```
to_path_buf(&self) -> Utf8PathBuf614     pub fn to_path_buf(&self) -> Utf8PathBuf {
615         Utf8PathBuf(self.0.to_path_buf())
616     }
617 
618     /// Returns `true` if the `Utf8Path` is absolute, i.e., if it is independent of
619     /// the current directory.
620     ///
621     /// * On Unix, a path is absolute if it starts with the root, so
622     /// `is_absolute` and [`has_root`] are equivalent.
623     ///
624     /// * On Windows, a path is absolute if it has a prefix and starts with the
625     /// root: `c:\windows` is absolute, while `c:temp` and `\temp` are not.
626     ///
627     /// # Examples
628     ///
629     /// ```
630     /// use camino::Utf8Path;
631     ///
632     /// assert!(!Utf8Path::new("foo.txt").is_absolute());
633     /// ```
634     ///
635     /// [`has_root`]: Utf8Path::has_root
is_absolute(&self) -> bool636     pub fn is_absolute(&self) -> bool {
637         self.0.is_absolute()
638     }
639 
640     /// Returns `true` if the `Utf8Path` is relative, i.e., not absolute.
641     ///
642     /// See [`is_absolute`]'s documentation for more details.
643     ///
644     /// # Examples
645     ///
646     /// ```
647     /// use camino::Utf8Path;
648     ///
649     /// assert!(Utf8Path::new("foo.txt").is_relative());
650     /// ```
651     ///
652     /// [`is_absolute`]: Utf8Path::is_absolute
is_relative(&self) -> bool653     pub fn is_relative(&self) -> bool {
654         self.0.is_relative()
655     }
656 
657     /// Returns `true` if the `Utf8Path` has a root.
658     ///
659     /// * On Unix, a path has a root if it begins with `/`.
660     ///
661     /// * On Windows, a path has a root if it:
662     ///     * has no prefix and begins with a separator, e.g., `\windows`
663     ///     * has a prefix followed by a separator, e.g., `c:\windows` but not `c:windows`
664     ///     * has any non-disk prefix, e.g., `\\server\share`
665     ///
666     /// # Examples
667     ///
668     /// ```
669     /// use camino::Utf8Path;
670     ///
671     /// assert!(Utf8Path::new("/etc/passwd").has_root());
672     /// ```
has_root(&self) -> bool673     pub fn has_root(&self) -> bool {
674         self.0.has_root()
675     }
676 
677     /// Returns the `Path` without its final component, if there is one.
678     ///
679     /// Returns [`None`] if the path terminates in a root or prefix.
680     ///
681     /// # Examples
682     ///
683     /// ```
684     /// use camino::Utf8Path;
685     ///
686     /// let path = Utf8Path::new("/foo/bar");
687     /// let parent = path.parent().unwrap();
688     /// assert_eq!(parent, Utf8Path::new("/foo"));
689     ///
690     /// let grand_parent = parent.parent().unwrap();
691     /// assert_eq!(grand_parent, Utf8Path::new("/"));
692     /// assert_eq!(grand_parent.parent(), None);
693     /// ```
parent(&self) -> Option<&Utf8Path>694     pub fn parent(&self) -> Option<&Utf8Path> {
695         self.0.parent().map(|path| {
696             // SAFETY: self is valid UTF-8, so parent is valid UTF-8 as well
697             unsafe { Utf8Path::assume_utf8(path) }
698         })
699     }
700 
701     /// Produces an iterator over `Utf8Path` and its ancestors.
702     ///
703     /// The iterator will yield the `Utf8Path` that is returned if the [`parent`] method is used zero
704     /// or more times. That means, the iterator will yield `&self`, `&self.parent().unwrap()`,
705     /// `&self.parent().unwrap().parent().unwrap()` and so on. If the [`parent`] method returns
706     /// [`None`], the iterator will do likewise. The iterator will always yield at least one value,
707     /// namely `&self`.
708     ///
709     /// # Examples
710     ///
711     /// ```
712     /// use camino::Utf8Path;
713     ///
714     /// let mut ancestors = Utf8Path::new("/foo/bar").ancestors();
715     /// assert_eq!(ancestors.next(), Some(Utf8Path::new("/foo/bar")));
716     /// assert_eq!(ancestors.next(), Some(Utf8Path::new("/foo")));
717     /// assert_eq!(ancestors.next(), Some(Utf8Path::new("/")));
718     /// assert_eq!(ancestors.next(), None);
719     ///
720     /// let mut ancestors = Utf8Path::new("../foo/bar").ancestors();
721     /// assert_eq!(ancestors.next(), Some(Utf8Path::new("../foo/bar")));
722     /// assert_eq!(ancestors.next(), Some(Utf8Path::new("../foo")));
723     /// assert_eq!(ancestors.next(), Some(Utf8Path::new("..")));
724     /// assert_eq!(ancestors.next(), Some(Utf8Path::new("")));
725     /// assert_eq!(ancestors.next(), None);
726     /// ```
727     ///
728     /// [`parent`]: Utf8Path::parent
ancestors(&self) -> Utf8Ancestors<'_>729     pub fn ancestors(&self) -> Utf8Ancestors<'_> {
730         Utf8Ancestors(self.0.ancestors())
731     }
732 
733     /// Returns the final component of the `Utf8Path`, if there is one.
734     ///
735     /// If the path is a normal file, this is the file name. If it's the path of a directory, this
736     /// is the directory name.
737     ///
738     /// Returns [`None`] if the path terminates in `..`.
739     ///
740     /// # Examples
741     ///
742     /// ```
743     /// use camino::Utf8Path;
744     ///
745     /// assert_eq!(Some("bin"), Utf8Path::new("/usr/bin/").file_name());
746     /// assert_eq!(Some("foo.txt"), Utf8Path::new("tmp/foo.txt").file_name());
747     /// assert_eq!(Some("foo.txt"), Utf8Path::new("foo.txt/.").file_name());
748     /// assert_eq!(Some("foo.txt"), Utf8Path::new("foo.txt/.//").file_name());
749     /// assert_eq!(None, Utf8Path::new("foo.txt/..").file_name());
750     /// assert_eq!(None, Utf8Path::new("/").file_name());
751     /// ```
file_name(&self) -> Option<&str>752     pub fn file_name(&self) -> Option<&str> {
753         self.0.file_name().map(|s| {
754             // SAFETY: self is valid UTF-8, so file_name is valid UTF-8 as well
755             unsafe { assume_utf8(s) }
756         })
757     }
758 
759     /// Returns a path that, when joined onto `base`, yields `self`.
760     ///
761     /// # Errors
762     ///
763     /// If `base` is not a prefix of `self` (i.e., [`starts_with`]
764     /// returns `false`), returns [`Err`].
765     ///
766     /// [`starts_with`]: Utf8Path::starts_with
767     ///
768     /// # Examples
769     ///
770     /// ```
771     /// use camino::{Utf8Path, Utf8PathBuf};
772     ///
773     /// let path = Utf8Path::new("/test/haha/foo.txt");
774     ///
775     /// assert_eq!(path.strip_prefix("/"), Ok(Utf8Path::new("test/haha/foo.txt")));
776     /// assert_eq!(path.strip_prefix("/test"), Ok(Utf8Path::new("haha/foo.txt")));
777     /// assert_eq!(path.strip_prefix("/test/"), Ok(Utf8Path::new("haha/foo.txt")));
778     /// assert_eq!(path.strip_prefix("/test/haha/foo.txt"), Ok(Utf8Path::new("")));
779     /// assert_eq!(path.strip_prefix("/test/haha/foo.txt/"), Ok(Utf8Path::new("")));
780     ///
781     /// assert!(path.strip_prefix("test").is_err());
782     /// assert!(path.strip_prefix("/haha").is_err());
783     ///
784     /// let prefix = Utf8PathBuf::from("/test/");
785     /// assert_eq!(path.strip_prefix(prefix), Ok(Utf8Path::new("haha/foo.txt")));
786     /// ```
strip_prefix(&self, base: impl AsRef<Path>) -> Result<&Utf8Path, StripPrefixError>787     pub fn strip_prefix(&self, base: impl AsRef<Path>) -> Result<&Utf8Path, StripPrefixError> {
788         self.0.strip_prefix(base).map(|path| {
789             // SAFETY: self is valid UTF-8, and strip_prefix returns a part of self (or an empty
790             // string), so it is valid UTF-8 as well.
791             unsafe { Utf8Path::assume_utf8(path) }
792         })
793     }
794 
795     /// Determines whether `base` is a prefix of `self`.
796     ///
797     /// Only considers whole path components to match.
798     ///
799     /// # Examples
800     ///
801     /// ```
802     /// use camino::Utf8Path;
803     ///
804     /// let path = Utf8Path::new("/etc/passwd");
805     ///
806     /// assert!(path.starts_with("/etc"));
807     /// assert!(path.starts_with("/etc/"));
808     /// assert!(path.starts_with("/etc/passwd"));
809     /// assert!(path.starts_with("/etc/passwd/")); // extra slash is okay
810     /// assert!(path.starts_with("/etc/passwd///")); // multiple extra slashes are okay
811     ///
812     /// assert!(!path.starts_with("/e"));
813     /// assert!(!path.starts_with("/etc/passwd.txt"));
814     ///
815     /// assert!(!Utf8Path::new("/etc/foo.rs").starts_with("/etc/foo"));
816     /// ```
starts_with(&self, base: impl AsRef<Path>) -> bool817     pub fn starts_with(&self, base: impl AsRef<Path>) -> bool {
818         self.0.starts_with(base)
819     }
820 
821     /// Determines whether `child` is a suffix of `self`.
822     ///
823     /// Only considers whole path components to match.
824     ///
825     /// # Examples
826     ///
827     /// ```
828     /// use camino::Utf8Path;
829     ///
830     /// let path = Utf8Path::new("/etc/resolv.conf");
831     ///
832     /// assert!(path.ends_with("resolv.conf"));
833     /// assert!(path.ends_with("etc/resolv.conf"));
834     /// assert!(path.ends_with("/etc/resolv.conf"));
835     ///
836     /// assert!(!path.ends_with("/resolv.conf"));
837     /// assert!(!path.ends_with("conf")); // use .extension() instead
838     /// ```
ends_with(&self, base: impl AsRef<Path>) -> bool839     pub fn ends_with(&self, base: impl AsRef<Path>) -> bool {
840         self.0.ends_with(base)
841     }
842 
843     /// Extracts the stem (non-extension) portion of [`self.file_name`].
844     ///
845     /// [`self.file_name`]: Utf8Path::file_name
846     ///
847     /// The stem is:
848     ///
849     /// * [`None`], if there is no file name;
850     /// * The entire file name if there is no embedded `.`;
851     /// * The entire file name if the file name begins with `.` and has no other `.`s within;
852     /// * Otherwise, the portion of the file name before the final `.`
853     ///
854     /// # Examples
855     ///
856     /// ```
857     /// use camino::Utf8Path;
858     ///
859     /// assert_eq!("foo", Utf8Path::new("foo.rs").file_stem().unwrap());
860     /// assert_eq!("foo.tar", Utf8Path::new("foo.tar.gz").file_stem().unwrap());
861     /// ```
file_stem(&self) -> Option<&str>862     pub fn file_stem(&self) -> Option<&str> {
863         self.0.file_stem().map(|s| {
864             // SAFETY: self is valid UTF-8, so file_stem is valid UTF-8 as well
865             unsafe { assume_utf8(s) }
866         })
867     }
868 
869     /// Extracts the extension of [`self.file_name`], if possible.
870     ///
871     /// The extension is:
872     ///
873     /// * [`None`], if there is no file name;
874     /// * [`None`], if there is no embedded `.`;
875     /// * [`None`], if the file name begins with `.` and has no other `.`s within;
876     /// * Otherwise, the portion of the file name after the final `.`
877     ///
878     /// [`self.file_name`]: Utf8Path::file_name
879     ///
880     /// # Examples
881     ///
882     /// ```
883     /// use camino::Utf8Path;
884     ///
885     /// assert_eq!("rs", Utf8Path::new("foo.rs").extension().unwrap());
886     /// assert_eq!("gz", Utf8Path::new("foo.tar.gz").extension().unwrap());
887     /// ```
extension(&self) -> Option<&str>888     pub fn extension(&self) -> Option<&str> {
889         self.0.extension().map(|s| {
890             // SAFETY: self is valid UTF-8, so extension is valid UTF-8 as well
891             unsafe { assume_utf8(s) }
892         })
893     }
894 
895     /// Creates an owned [`Utf8PathBuf`] with `path` adjoined to `self`.
896     ///
897     /// See [`Utf8PathBuf::push`] for more details on what it means to adjoin a path.
898     ///
899     /// # Examples
900     ///
901     /// ```
902     /// use camino::{Utf8Path, Utf8PathBuf};
903     ///
904     /// assert_eq!(Utf8Path::new("/etc").join("passwd"), Utf8PathBuf::from("/etc/passwd"));
905     /// ```
join(&self, path: impl AsRef<Utf8Path>) -> Utf8PathBuf906     pub fn join(&self, path: impl AsRef<Utf8Path>) -> Utf8PathBuf {
907         Utf8PathBuf(self.0.join(&path.as_ref().0))
908     }
909 
910     /// Creates an owned [`PathBuf`] with `path` adjoined to `self`.
911     ///
912     /// See [`PathBuf::push`] for more details on what it means to adjoin a path.
913     ///
914     /// # Examples
915     ///
916     /// ```
917     /// use camino::Utf8Path;
918     /// use std::path::PathBuf;
919     ///
920     /// assert_eq!(Utf8Path::new("/etc").join_os("passwd"), PathBuf::from("/etc/passwd"));
921     /// ```
join_os(&self, path: impl AsRef<Path>) -> PathBuf922     pub fn join_os(&self, path: impl AsRef<Path>) -> PathBuf {
923         self.0.join(path)
924     }
925 
926     /// Creates an owned [`Utf8PathBuf`] like `self` but with the given file name.
927     ///
928     /// See [`Utf8PathBuf::set_file_name`] for more details.
929     ///
930     /// # Examples
931     ///
932     /// ```
933     /// use camino::{Utf8Path, Utf8PathBuf};
934     ///
935     /// let path = Utf8Path::new("/tmp/foo.txt");
936     /// assert_eq!(path.with_file_name("bar.txt"), Utf8PathBuf::from("/tmp/bar.txt"));
937     ///
938     /// let path = Utf8Path::new("/tmp");
939     /// assert_eq!(path.with_file_name("var"), Utf8PathBuf::from("/var"));
940     /// ```
with_file_name(&self, file_name: impl AsRef<str>) -> Utf8PathBuf941     pub fn with_file_name(&self, file_name: impl AsRef<str>) -> Utf8PathBuf {
942         Utf8PathBuf(self.0.with_file_name(file_name.as_ref()))
943     }
944 
945     /// Creates an owned [`Utf8PathBuf`] like `self` but with the given extension.
946     ///
947     /// See [`Utf8PathBuf::set_extension`] for more details.
948     ///
949     /// # Examples
950     ///
951     /// ```
952     /// use camino::{Utf8Path, Utf8PathBuf};
953     ///
954     /// let path = Utf8Path::new("foo.rs");
955     /// assert_eq!(path.with_extension("txt"), Utf8PathBuf::from("foo.txt"));
956     ///
957     /// let path = Utf8Path::new("foo.tar.gz");
958     /// assert_eq!(path.with_extension(""), Utf8PathBuf::from("foo.tar"));
959     /// assert_eq!(path.with_extension("xz"), Utf8PathBuf::from("foo.tar.xz"));
960     /// assert_eq!(path.with_extension("").with_extension("txt"), Utf8PathBuf::from("foo.txt"));
961     /// ```
with_extension(&self, extension: impl AsRef<str>) -> Utf8PathBuf962     pub fn with_extension(&self, extension: impl AsRef<str>) -> Utf8PathBuf {
963         Utf8PathBuf(self.0.with_extension(extension.as_ref()))
964     }
965 
966     /// Produces an iterator over the [`Utf8Component`]s of the path.
967     ///
968     /// When parsing the path, there is a small amount of normalization:
969     ///
970     /// * Repeated separators are ignored, so `a/b` and `a//b` both have
971     ///   `a` and `b` as components.
972     ///
973     /// * Occurrences of `.` are normalized away, except if they are at the
974     ///   beginning of the path. For example, `a/./b`, `a/b/`, `a/b/.` and
975     ///   `a/b` all have `a` and `b` as components, but `./a/b` starts with
976     ///   an additional [`CurDir`] component.
977     ///
978     /// * A trailing slash is normalized away, `/a/b` and `/a/b/` are equivalent.
979     ///
980     /// Note that no other normalization takes place; in particular, `a/c`
981     /// and `a/b/../c` are distinct, to account for the possibility that `b`
982     /// is a symbolic link (so its parent isn't `a`).
983     ///
984     /// # Examples
985     ///
986     /// ```
987     /// use camino::{Utf8Component, Utf8Path};
988     ///
989     /// let mut components = Utf8Path::new("/tmp/foo.txt").components();
990     ///
991     /// assert_eq!(components.next(), Some(Utf8Component::RootDir));
992     /// assert_eq!(components.next(), Some(Utf8Component::Normal("tmp")));
993     /// assert_eq!(components.next(), Some(Utf8Component::Normal("foo.txt")));
994     /// assert_eq!(components.next(), None)
995     /// ```
996     ///
997     /// [`CurDir`]: Utf8Component::CurDir
components(&self) -> Utf8Components998     pub fn components(&self) -> Utf8Components {
999         Utf8Components(self.0.components())
1000     }
1001 
1002     /// Produces an iterator over the path's components viewed as [`str`]
1003     /// slices.
1004     ///
1005     /// For more information about the particulars of how the path is separated
1006     /// into components, see [`components`].
1007     ///
1008     /// [`components`]: Utf8Path::components
1009     ///
1010     /// # Examples
1011     ///
1012     /// ```
1013     /// use camino::Utf8Path;
1014     ///
1015     /// let mut it = Utf8Path::new("/tmp/foo.txt").iter();
1016     /// assert_eq!(it.next(), Some(std::path::MAIN_SEPARATOR.to_string().as_str()));
1017     /// assert_eq!(it.next(), Some("tmp"));
1018     /// assert_eq!(it.next(), Some("foo.txt"));
1019     /// assert_eq!(it.next(), None)
1020     /// ```
iter(&self) -> Iter<'_>1021     pub fn iter(&self) -> Iter<'_> {
1022         Iter {
1023             inner: self.components(),
1024         }
1025     }
1026 
1027     /// Queries the file system to get information about a file, directory, etc.
1028     ///
1029     /// This function will traverse symbolic links to query information about the
1030     /// destination file.
1031     ///
1032     /// This is an alias to [`fs::metadata`].
1033     ///
1034     /// # Examples
1035     ///
1036     /// ```no_run
1037     /// use camino::Utf8Path;
1038     ///
1039     /// let path = Utf8Path::new("/Minas/tirith");
1040     /// let metadata = path.metadata().expect("metadata call failed");
1041     /// println!("{:?}", metadata.file_type());
1042     /// ```
metadata(&self) -> io::Result<fs::Metadata>1043     pub fn metadata(&self) -> io::Result<fs::Metadata> {
1044         self.0.metadata()
1045     }
1046 
1047     /// Queries the metadata about a file without following symlinks.
1048     ///
1049     /// This is an alias to [`fs::symlink_metadata`].
1050     ///
1051     /// # Examples
1052     ///
1053     /// ```no_run
1054     /// use camino::Utf8Path;
1055     ///
1056     /// let path = Utf8Path::new("/Minas/tirith");
1057     /// let metadata = path.symlink_metadata().expect("symlink_metadata call failed");
1058     /// println!("{:?}", metadata.file_type());
1059     /// ```
symlink_metadata(&self) -> io::Result<fs::Metadata>1060     pub fn symlink_metadata(&self) -> io::Result<fs::Metadata> {
1061         self.0.symlink_metadata()
1062     }
1063 
1064     /// Returns the canonical, absolute form of the path with all intermediate
1065     /// components normalized and symbolic links resolved.
1066     ///
1067     /// This returns a [`PathBuf`] because even if a symlink is valid Unicode, its target may not
1068     /// be.
1069     ///
1070     /// This is an alias to [`fs::canonicalize`].
1071     ///
1072     /// # Examples
1073     ///
1074     /// ```no_run
1075     /// use camino::Utf8Path;
1076     /// use std::path::PathBuf;
1077     ///
1078     /// let path = Utf8Path::new("/foo/test/../test/bar.rs");
1079     /// assert_eq!(path.canonicalize().unwrap(), PathBuf::from("/foo/test/bar.rs"));
1080     /// ```
canonicalize(&self) -> io::Result<PathBuf>1081     pub fn canonicalize(&self) -> io::Result<PathBuf> {
1082         self.0.canonicalize()
1083     }
1084 
1085     /// Reads a symbolic link, returning the file that the link points to.
1086     ///
1087     /// This returns a [`PathBuf`] because even if a symlink is valid Unicode, its target may not
1088     /// be.
1089     ///
1090     /// This is an alias to [`fs::read_link`].
1091     ///
1092     /// # Examples
1093     ///
1094     /// ```no_run
1095     /// use camino::Utf8Path;
1096     ///
1097     /// let path = Utf8Path::new("/laputa/sky_castle.rs");
1098     /// let path_link = path.read_link().expect("read_link call failed");
1099     /// ```
read_link(&self) -> io::Result<PathBuf>1100     pub fn read_link(&self) -> io::Result<PathBuf> {
1101         self.0.read_link()
1102     }
1103 
1104     /// Returns an iterator over the entries within a directory.
1105     ///
1106     /// The iterator will yield instances of [`io::Result`]`<`[`fs::DirEntry`]`>`. New
1107     /// errors may be encountered after an iterator is initially constructed.
1108     ///
1109     /// This is an alias to [`fs::read_dir`].
1110     ///
1111     /// # Examples
1112     ///
1113     /// ```no_run
1114     /// use camino::Utf8Path;
1115     ///
1116     /// let path = Utf8Path::new("/laputa");
1117     /// for entry in path.read_dir().expect("read_dir call failed") {
1118     ///     if let Ok(entry) = entry {
1119     ///         println!("{:?}", entry.path());
1120     ///     }
1121     /// }
1122     /// ```
read_dir(&self) -> io::Result<fs::ReadDir>1123     pub fn read_dir(&self) -> io::Result<fs::ReadDir> {
1124         self.0.read_dir()
1125     }
1126 
1127     /// Returns `true` if the path points at an existing entity.
1128     ///
1129     /// This function will traverse symbolic links to query information about the
1130     /// destination file. In case of broken symbolic links this will return `false`.
1131     ///
1132     /// If you cannot access the directory containing the file, e.g., because of a
1133     /// permission error, this will return `false`.
1134     ///
1135     /// # Examples
1136     ///
1137     /// ```no_run
1138     /// use camino::Utf8Path;
1139     /// assert!(!Utf8Path::new("does_not_exist.txt").exists());
1140     /// ```
1141     ///
1142     /// # See Also
1143     ///
1144     /// This is a convenience function that coerces errors to false. If you want to
1145     /// check errors, call [`fs::metadata`].
exists(&self) -> bool1146     pub fn exists(&self) -> bool {
1147         self.0.exists()
1148     }
1149 
1150     /// Returns `true` if the path exists on disk and is pointing at a regular file.
1151     ///
1152     /// This function will traverse symbolic links to query information about the
1153     /// destination file. In case of broken symbolic links this will return `false`.
1154     ///
1155     /// If you cannot access the directory containing the file, e.g., because of a
1156     /// permission error, this will return `false`.
1157     ///
1158     /// # Examples
1159     ///
1160     /// ```no_run
1161     /// use camino::Utf8Path;
1162     /// assert_eq!(Utf8Path::new("./is_a_directory/").is_file(), false);
1163     /// assert_eq!(Utf8Path::new("a_file.txt").is_file(), true);
1164     /// ```
1165     ///
1166     /// # See Also
1167     ///
1168     /// This is a convenience function that coerces errors to false. If you want to
1169     /// check errors, call [`fs::metadata`] and handle its [`Result`]. Then call
1170     /// [`fs::Metadata::is_file`] if it was [`Ok`].
1171     ///
1172     /// When the goal is simply to read from (or write to) the source, the most
1173     /// reliable way to test the source can be read (or written to) is to open
1174     /// it. Only using `is_file` can break workflows like `diff <( prog_a )` on
1175     /// a Unix-like system for example. See [`fs::File::open`] or
1176     /// [`fs::OpenOptions::open`] for more information.
is_file(&self) -> bool1177     pub fn is_file(&self) -> bool {
1178         self.0.is_file()
1179     }
1180 
1181     /// Returns `true` if the path exists on disk and is pointing at a directory.
1182     ///
1183     /// This function will traverse symbolic links to query information about the
1184     /// destination file. In case of broken symbolic links this will return `false`.
1185     ///
1186     /// If you cannot access the directory containing the file, e.g., because of a
1187     /// permission error, this will return `false`.
1188     ///
1189     /// # Examples
1190     ///
1191     /// ```no_run
1192     /// use camino::Utf8Path;
1193     /// assert_eq!(Utf8Path::new("./is_a_directory/").is_dir(), true);
1194     /// assert_eq!(Utf8Path::new("a_file.txt").is_dir(), false);
1195     /// ```
1196     ///
1197     /// # See Also
1198     ///
1199     /// This is a convenience function that coerces errors to false. If you want to
1200     /// check errors, call [`fs::metadata`] and handle its [`Result`]. Then call
1201     /// [`fs::Metadata::is_dir`] if it was [`Ok`].
is_dir(&self) -> bool1202     pub fn is_dir(&self) -> bool {
1203         self.0.is_dir()
1204     }
1205 
1206     /// Converts a `Box<Utf8Path>` into a [`Utf8PathBuf`] without copying or allocating.
into_path_buf(self: Box<Utf8Path>) -> Utf8PathBuf1207     pub fn into_path_buf(self: Box<Utf8Path>) -> Utf8PathBuf {
1208         let ptr = Box::into_raw(self) as *mut Path;
1209         // SAFETY:
1210         // * self is valid UTF-8
1211         // * ptr was constructed by consuming self so it represents an owned path.
1212         // * Utf8Path is marked as #[repr(transparent)] so the conversion from a *mut Utf8Path to a
1213         //   *mut Path is valid.
1214         let boxed_path = unsafe { Box::from_raw(ptr) };
1215         Utf8PathBuf(boxed_path.into_path_buf())
1216     }
1217 
1218     // invariant: Path must be guaranteed to be utf-8 data
assume_utf8(path: &Path) -> &Utf8Path1219     unsafe fn assume_utf8(path: &Path) -> &Utf8Path {
1220         // SAFETY: Utf8Path is marked as #[repr(transparent)] so the conversion from a
1221         // *const Path to a *const Utf8Path is valid.
1222         &*(path as *const Path as *const Utf8Path)
1223     }
1224 }
1225 
1226 impl Clone for Box<Utf8Path> {
clone(&self) -> Self1227     fn clone(&self) -> Self {
1228         let boxed: Box<Path> = self.0.into();
1229         let ptr = Box::into_raw(boxed) as *mut Utf8Path;
1230         // SAFETY:
1231         // * self is valid UTF-8
1232         // * ptr was created by consuming a Box<Path> so it represents an rced pointer
1233         // * Utf8Path is marked as #[repr(transparent)] so the conversion from *mut Path to
1234         //   *mut Utf8Path is valid
1235         unsafe { Box::from_raw(ptr) }
1236     }
1237 }
1238 
1239 impl fmt::Display for Utf8Path {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1240     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1241         fmt::Display::fmt(self.as_str(), f)
1242     }
1243 }
1244 
1245 impl fmt::Debug for Utf8Path {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1246     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1247         fmt::Debug::fmt(self.as_str(), f)
1248     }
1249 }
1250 
1251 /// An iterator over [`Utf8Path`] and its ancestors.
1252 ///
1253 /// This `struct` is created by the [`ancestors`] method on [`Utf8Path`].
1254 /// See its documentation for more.
1255 ///
1256 /// # Examples
1257 ///
1258 /// ```
1259 /// use camino::Utf8Path;
1260 ///
1261 /// let path = Utf8Path::new("/foo/bar");
1262 ///
1263 /// for ancestor in path.ancestors() {
1264 ///     println!("{}", ancestor);
1265 /// }
1266 /// ```
1267 ///
1268 /// [`ancestors`]: Utf8Path::ancestors
1269 #[derive(Copy, Clone)]
1270 #[repr(transparent)]
1271 pub struct Utf8Ancestors<'a>(Ancestors<'a>);
1272 
1273 impl<'a> fmt::Debug for Utf8Ancestors<'a> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1274     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1275         fmt::Debug::fmt(&self.0, f)
1276     }
1277 }
1278 
1279 impl<'a> Iterator for Utf8Ancestors<'a> {
1280     type Item = &'a Utf8Path;
1281 
next(&mut self) -> Option<Self::Item>1282     fn next(&mut self) -> Option<Self::Item> {
1283         self.0.next().map(|path| {
1284             // SAFETY: Utf8Ancestors was constructed from a Utf8Path, so it is guaranteed to
1285             // be valid UTF-8
1286             unsafe { Utf8Path::assume_utf8(path) }
1287         })
1288     }
1289 }
1290 
1291 impl<'a> FusedIterator for Utf8Ancestors<'a> {}
1292 
1293 /// An iterator over the [`Utf8Component`]s of a [`Utf8Path`].
1294 ///
1295 /// This `struct` is created by the [`components`] method on [`Utf8Path`].
1296 /// See its documentation for more.
1297 ///
1298 /// # Examples
1299 ///
1300 /// ```
1301 /// use camino::Utf8Path;
1302 ///
1303 /// let path = Utf8Path::new("/tmp/foo/bar.txt");
1304 ///
1305 /// for component in path.components() {
1306 ///     println!("{:?}", component);
1307 /// }
1308 /// ```
1309 ///
1310 /// [`components`]: Utf8Path::components
1311 #[derive(Clone, Eq, Ord, PartialEq, PartialOrd)]
1312 pub struct Utf8Components<'a>(Components<'a>);
1313 
1314 impl<'a> Utf8Components<'a> {
1315     /// Extracts a slice corresponding to the portion of the path remaining for iteration.
1316     ///
1317     /// # Examples
1318     ///
1319     /// ```
1320     /// use camino::Utf8Path;
1321     ///
1322     /// let mut components = Utf8Path::new("/tmp/foo/bar.txt").components();
1323     /// components.next();
1324     /// components.next();
1325     ///
1326     /// assert_eq!(Utf8Path::new("foo/bar.txt"), components.as_path());
1327     /// ```
as_path(&self) -> &'a Utf8Path1328     pub fn as_path(&self) -> &'a Utf8Path {
1329         // SAFETY: Utf8Components was constructed from a Utf8Path, so it is guaranteed to be valid
1330         // UTF-8
1331         unsafe { Utf8Path::assume_utf8(self.0.as_path()) }
1332     }
1333 }
1334 
1335 impl<'a> Iterator for Utf8Components<'a> {
1336     type Item = Utf8Component<'a>;
1337 
next(&mut self) -> Option<Self::Item>1338     fn next(&mut self) -> Option<Self::Item> {
1339         self.0.next().map(|component| {
1340             // SAFETY: Utf8Component was constructed from a Utf8Path, so it is guaranteed to be
1341             // valid UTF-8
1342             unsafe { Utf8Component::new(component) }
1343         })
1344     }
1345 }
1346 
1347 impl<'a> FusedIterator for Utf8Components<'a> {}
1348 
1349 impl<'a> DoubleEndedIterator for Utf8Components<'a> {
next_back(&mut self) -> Option<Self::Item>1350     fn next_back(&mut self) -> Option<Self::Item> {
1351         self.0.next_back().map(|component| {
1352             // SAFETY: Utf8Component was constructed from a Utf8Path, so it is guaranteed to be
1353             // valid UTF-8
1354             unsafe { Utf8Component::new(component) }
1355         })
1356     }
1357 }
1358 
1359 impl<'a> fmt::Debug for Utf8Components<'a> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1360     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1361         fmt::Debug::fmt(&self.0, f)
1362     }
1363 }
1364 
1365 impl AsRef<Utf8Path> for Utf8Components<'_> {
as_ref(&self) -> &Utf8Path1366     fn as_ref(&self) -> &Utf8Path {
1367         self.as_path()
1368     }
1369 }
1370 
1371 impl AsRef<Path> for Utf8Components<'_> {
as_ref(&self) -> &Path1372     fn as_ref(&self) -> &Path {
1373         self.as_path().as_ref()
1374     }
1375 }
1376 
1377 impl AsRef<str> for Utf8Components<'_> {
as_ref(&self) -> &str1378     fn as_ref(&self) -> &str {
1379         self.as_path().as_ref()
1380     }
1381 }
1382 
1383 impl AsRef<OsStr> for Utf8Components<'_> {
as_ref(&self) -> &OsStr1384     fn as_ref(&self) -> &OsStr {
1385         self.as_path().as_os_str()
1386     }
1387 }
1388 
1389 /// An iterator over the [`Utf8Component`]s of a [`Utf8Path`], as [`str`] slices.
1390 ///
1391 /// This `struct` is created by the [`iter`] method on [`Utf8Path`].
1392 /// See its documentation for more.
1393 ///
1394 /// [`iter`]: Utf8Path::iter
1395 #[derive(Clone)]
1396 pub struct Iter<'a> {
1397     inner: Utf8Components<'a>,
1398 }
1399 
1400 impl fmt::Debug for Iter<'_> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1401     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1402         struct DebugHelper<'a>(&'a Utf8Path);
1403 
1404         impl fmt::Debug for DebugHelper<'_> {
1405             fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1406                 f.debug_list().entries(self.0.iter()).finish()
1407             }
1408         }
1409 
1410         f.debug_tuple("Iter")
1411             .field(&DebugHelper(self.as_path()))
1412             .finish()
1413     }
1414 }
1415 
1416 impl<'a> Iter<'a> {
1417     /// Extracts a slice corresponding to the portion of the path remaining for iteration.
1418     ///
1419     /// # Examples
1420     ///
1421     /// ```
1422     /// use camino::Utf8Path;
1423     ///
1424     /// let mut iter = Utf8Path::new("/tmp/foo/bar.txt").iter();
1425     /// iter.next();
1426     /// iter.next();
1427     ///
1428     /// assert_eq!(Utf8Path::new("foo/bar.txt"), iter.as_path());
1429     /// ```
as_path(&self) -> &'a Utf8Path1430     pub fn as_path(&self) -> &'a Utf8Path {
1431         self.inner.as_path()
1432     }
1433 }
1434 
1435 impl AsRef<Utf8Path> for Iter<'_> {
as_ref(&self) -> &Utf8Path1436     fn as_ref(&self) -> &Utf8Path {
1437         self.as_path()
1438     }
1439 }
1440 
1441 impl AsRef<Path> for Iter<'_> {
as_ref(&self) -> &Path1442     fn as_ref(&self) -> &Path {
1443         self.as_path().as_ref()
1444     }
1445 }
1446 
1447 impl AsRef<str> for Iter<'_> {
as_ref(&self) -> &str1448     fn as_ref(&self) -> &str {
1449         self.as_path().as_ref()
1450     }
1451 }
1452 
1453 impl AsRef<OsStr> for Iter<'_> {
as_ref(&self) -> &OsStr1454     fn as_ref(&self) -> &OsStr {
1455         self.as_path().as_os_str()
1456     }
1457 }
1458 
1459 impl<'a> Iterator for Iter<'a> {
1460     type Item = &'a str;
1461 
next(&mut self) -> Option<&'a str>1462     fn next(&mut self) -> Option<&'a str> {
1463         self.inner.next().map(|component| component.as_str())
1464     }
1465 }
1466 
1467 impl<'a> DoubleEndedIterator for Iter<'a> {
next_back(&mut self) -> Option<&'a str>1468     fn next_back(&mut self) -> Option<&'a str> {
1469         self.inner.next_back().map(|component| component.as_str())
1470     }
1471 }
1472 
1473 impl FusedIterator for Iter<'_> {}
1474 
1475 /// A single component of a path.
1476 ///
1477 /// A `Utf8Component` roughly corresponds to a substring between path separators
1478 /// (`/` or `\`).
1479 ///
1480 /// This `enum` is created by iterating over [`Utf8Components`], which in turn is
1481 /// created by the [`components`](Utf8Path::components) method on [`Utf8Path`].
1482 ///
1483 /// # Examples
1484 ///
1485 /// ```rust
1486 /// use camino::{Utf8Component, Utf8Path};
1487 ///
1488 /// let path = Utf8Path::new("/tmp/foo/bar.txt");
1489 /// let components = path.components().collect::<Vec<_>>();
1490 /// assert_eq!(&components, &[
1491 ///     Utf8Component::RootDir,
1492 ///     Utf8Component::Normal("tmp"),
1493 ///     Utf8Component::Normal("foo"),
1494 ///     Utf8Component::Normal("bar.txt"),
1495 /// ]);
1496 /// ```
1497 #[derive(Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
1498 pub enum Utf8Component<'a> {
1499     /// A Windows path prefix, e.g., `C:` or `\\server\share`.
1500     ///
1501     /// There is a large variety of prefix types, see [`Utf8Prefix`]'s documentation
1502     /// for more.
1503     ///
1504     /// Does not occur on Unix.
1505     Prefix(Utf8PrefixComponent<'a>),
1506 
1507     /// The root directory component, appears after any prefix and before anything else.
1508     ///
1509     /// It represents a separator that designates that a path starts from root.
1510     RootDir,
1511 
1512     /// A reference to the current directory, i.e., `.`.
1513     CurDir,
1514 
1515     /// A reference to the parent directory, i.e., `..`.
1516     ParentDir,
1517 
1518     /// A normal component, e.g., `a` and `b` in `a/b`.
1519     ///
1520     /// This variant is the most common one, it represents references to files
1521     /// or directories.
1522     Normal(&'a str),
1523 }
1524 
1525 impl<'a> Utf8Component<'a> {
new(component: Component<'a>) -> Utf8Component<'a>1526     unsafe fn new(component: Component<'a>) -> Utf8Component<'a> {
1527         match component {
1528             Component::Prefix(prefix) => Utf8Component::Prefix(Utf8PrefixComponent(prefix)),
1529             Component::RootDir => Utf8Component::RootDir,
1530             Component::CurDir => Utf8Component::CurDir,
1531             Component::ParentDir => Utf8Component::ParentDir,
1532             Component::Normal(s) => Utf8Component::Normal(assume_utf8(s)),
1533         }
1534     }
1535 
1536     /// Extracts the underlying [`str`] slice.
1537     ///
1538     /// # Examples
1539     ///
1540     /// ```
1541     /// use camino::Utf8Path;
1542     ///
1543     /// let path = Utf8Path::new("./tmp/foo/bar.txt");
1544     /// let components: Vec<_> = path.components().map(|comp| comp.as_str()).collect();
1545     /// assert_eq!(&components, &[".", "tmp", "foo", "bar.txt"]);
1546     /// ```
as_str(&self) -> &'a str1547     pub fn as_str(&self) -> &'a str {
1548         // SAFETY: Utf8Component was constructed from a Utf8Path, so it is guaranteed to be
1549         // valid UTF-8
1550         unsafe { assume_utf8(self.as_os_str()) }
1551     }
1552 
1553     /// Extracts the underlying [`OsStr`] slice.
1554     ///
1555     /// # Examples
1556     ///
1557     /// ```
1558     /// use camino::Utf8Path;
1559     ///
1560     /// let path = Utf8Path::new("./tmp/foo/bar.txt");
1561     /// let components: Vec<_> = path.components().map(|comp| comp.as_os_str()).collect();
1562     /// assert_eq!(&components, &[".", "tmp", "foo", "bar.txt"]);
1563     /// ```
as_os_str(&self) -> &'a OsStr1564     pub fn as_os_str(&self) -> &'a OsStr {
1565         match *self {
1566             Utf8Component::Prefix(prefix) => prefix.as_os_str(),
1567             Utf8Component::RootDir => Component::RootDir.as_os_str(),
1568             Utf8Component::CurDir => Component::CurDir.as_os_str(),
1569             Utf8Component::ParentDir => Component::ParentDir.as_os_str(),
1570             Utf8Component::Normal(s) => OsStr::new(s),
1571         }
1572     }
1573 }
1574 
1575 impl<'a> fmt::Debug for Utf8Component<'a> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1576     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1577         fmt::Debug::fmt(self.as_os_str(), f)
1578     }
1579 }
1580 
1581 impl<'a> fmt::Display for Utf8Component<'a> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1582     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1583         fmt::Display::fmt(self.as_str(), f)
1584     }
1585 }
1586 
1587 impl AsRef<Utf8Path> for Utf8Component<'_> {
as_ref(&self) -> &Utf8Path1588     fn as_ref(&self) -> &Utf8Path {
1589         self.as_str().as_ref()
1590     }
1591 }
1592 
1593 impl AsRef<Path> for Utf8Component<'_> {
as_ref(&self) -> &Path1594     fn as_ref(&self) -> &Path {
1595         self.as_os_str().as_ref()
1596     }
1597 }
1598 
1599 impl AsRef<str> for Utf8Component<'_> {
as_ref(&self) -> &str1600     fn as_ref(&self) -> &str {
1601         self.as_str()
1602     }
1603 }
1604 
1605 impl AsRef<OsStr> for Utf8Component<'_> {
as_ref(&self) -> &OsStr1606     fn as_ref(&self) -> &OsStr {
1607         self.as_os_str()
1608     }
1609 }
1610 
1611 /// Windows path prefixes, e.g., `C:` or `\\server\share`.
1612 ///
1613 /// Windows uses a variety of path prefix styles, including references to drive
1614 /// volumes (like `C:`), network shared folders (like `\\server\share`), and
1615 /// others. In addition, some path prefixes are "verbatim" (i.e., prefixed with
1616 /// `\\?\`), in which case `/` is *not* treated as a separator and essentially
1617 /// no normalization is performed.
1618 ///
1619 /// # Examples
1620 ///
1621 /// ```
1622 /// use camino::{Utf8Component, Utf8Path, Utf8Prefix};
1623 /// use camino::Utf8Prefix::*;
1624 ///
1625 /// fn get_path_prefix(s: &str) -> Utf8Prefix {
1626 ///     let path = Utf8Path::new(s);
1627 ///     match path.components().next().unwrap() {
1628 ///         Utf8Component::Prefix(prefix_component) => prefix_component.kind(),
1629 ///         _ => panic!(),
1630 ///     }
1631 /// }
1632 ///
1633 /// # if cfg!(windows) {
1634 /// assert_eq!(Verbatim("pictures"), get_path_prefix(r"\\?\pictures\kittens"));
1635 /// assert_eq!(VerbatimUNC("server", "share"), get_path_prefix(r"\\?\UNC\server\share"));
1636 /// assert_eq!(VerbatimDisk(b'C'), get_path_prefix(r"\\?\c:\"));
1637 /// assert_eq!(DeviceNS("BrainInterface"), get_path_prefix(r"\\.\BrainInterface"));
1638 /// assert_eq!(UNC("server", "share"), get_path_prefix(r"\\server\share"));
1639 /// assert_eq!(Disk(b'C'), get_path_prefix(r"C:\Users\Rust\Pictures\Ferris"));
1640 /// # }
1641 /// ```
1642 #[derive(Copy, Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
1643 pub enum Utf8Prefix<'a> {
1644     /// Verbatim prefix, e.g., `\\?\cat_pics`.
1645     ///
1646     /// Verbatim prefixes consist of `\\?\` immediately followed by the given
1647     /// component.
1648     Verbatim(&'a str),
1649 
1650     /// Verbatim prefix using Windows' _**U**niform **N**aming **C**onvention_,
1651     /// e.g., `\\?\UNC\server\share`.
1652     ///
1653     /// Verbatim UNC prefixes consist of `\\?\UNC\` immediately followed by the
1654     /// server's hostname and a share name.
1655     VerbatimUNC(&'a str, &'a str),
1656 
1657     /// Verbatim disk prefix, e.g., `\\?\C:`.
1658     ///
1659     /// Verbatim disk prefixes consist of `\\?\` immediately followed by the
1660     /// drive letter and `:`.
1661     VerbatimDisk(u8),
1662 
1663     /// Device namespace prefix, e.g., `\\.\COM42`.
1664     ///
1665     /// Device namespace prefixes consist of `\\.\` immediately followed by the
1666     /// device name.
1667     DeviceNS(&'a str),
1668 
1669     /// Prefix using Windows' _**U**niform **N**aming **C**onvention_, e.g.
1670     /// `\\server\share`.
1671     ///
1672     /// UNC prefixes consist of the server's hostname and a share name.
1673     UNC(&'a str, &'a str),
1674 
1675     /// Prefix `C:` for the given disk drive.
1676     Disk(u8),
1677 }
1678 
1679 impl<'a> Utf8Prefix<'a> {
1680     /// Determines if the prefix is verbatim, i.e., begins with `\\?\`.
1681     ///
1682     /// # Examples
1683     ///
1684     /// ```
1685     /// use camino::Utf8Prefix::*;
1686     ///
1687     /// assert!(Verbatim("pictures").is_verbatim());
1688     /// assert!(VerbatimUNC("server", "share").is_verbatim());
1689     /// assert!(VerbatimDisk(b'C').is_verbatim());
1690     /// assert!(!DeviceNS("BrainInterface").is_verbatim());
1691     /// assert!(!UNC("server", "share").is_verbatim());
1692     /// assert!(!Disk(b'C').is_verbatim());
1693     /// ```
is_verbatim(&self) -> bool1694     pub fn is_verbatim(&self) -> bool {
1695         use Utf8Prefix::*;
1696         match self {
1697             Verbatim(_) | VerbatimDisk(_) | VerbatimUNC(..) => true,
1698             _ => false,
1699         }
1700     }
1701 }
1702 
1703 /// A structure wrapping a Windows path prefix as well as its unparsed string
1704 /// representation.
1705 ///
1706 /// In addition to the parsed [`Utf8Prefix`] information returned by [`kind`],
1707 /// `Utf8PrefixComponent` also holds the raw and unparsed [`str`] slice,
1708 /// returned by [`as_str`].
1709 ///
1710 /// Instances of this `struct` can be obtained by matching against the
1711 /// [`Prefix` variant] on [`Utf8Component`].
1712 ///
1713 /// Does not occur on Unix.
1714 ///
1715 /// # Examples
1716 ///
1717 /// ```
1718 /// # if cfg!(windows) {
1719 /// use camino::{Utf8Component, Utf8Path, Utf8Prefix};
1720 /// use std::ffi::OsStr;
1721 ///
1722 /// let path = Utf8Path::new(r"c:\you\later\");
1723 /// match path.components().next().unwrap() {
1724 ///     Utf8Component::Prefix(prefix_component) => {
1725 ///         assert_eq!(Utf8Prefix::Disk(b'C'), prefix_component.kind());
1726 ///         assert_eq!("c:", prefix_component.as_str());
1727 ///     }
1728 ///     _ => unreachable!(),
1729 /// }
1730 /// # }
1731 /// ```
1732 ///
1733 /// [`as_str`]: Utf8PrefixComponent::as_str
1734 /// [`kind`]: Utf8PrefixComponent::kind
1735 /// [`Prefix` variant]: Utf8Component::Prefix
1736 #[repr(transparent)]
1737 #[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd)]
1738 pub struct Utf8PrefixComponent<'a>(PrefixComponent<'a>);
1739 
1740 impl<'a> Utf8PrefixComponent<'a> {
1741     /// Returns the parsed prefix data.
1742     ///
1743     /// See [`Utf8Prefix`]'s documentation for more information on the different
1744     /// kinds of prefixes.
kind(&self) -> Utf8Prefix<'a>1745     pub fn kind(&self) -> Utf8Prefix<'a> {
1746         // SAFETY for all the below unsafe blocks: the path self was originally constructed from was
1747         // UTF-8 so any parts of it are valid UTF-8
1748         match self.0.kind() {
1749             Prefix::Verbatim(prefix) => Utf8Prefix::Verbatim(unsafe { assume_utf8(prefix) }),
1750             Prefix::VerbatimUNC(server, share) => {
1751                 let server = unsafe { assume_utf8(server) };
1752                 let share = unsafe { assume_utf8(share) };
1753                 Utf8Prefix::VerbatimUNC(server, share)
1754             }
1755             Prefix::VerbatimDisk(drive) => Utf8Prefix::VerbatimDisk(drive),
1756             Prefix::DeviceNS(prefix) => Utf8Prefix::DeviceNS(unsafe { assume_utf8(prefix) }),
1757             Prefix::UNC(server, share) => {
1758                 let server = unsafe { assume_utf8(server) };
1759                 let share = unsafe { assume_utf8(share) };
1760                 Utf8Prefix::UNC(server, share)
1761             }
1762             Prefix::Disk(drive) => Utf8Prefix::Disk(drive),
1763         }
1764     }
1765 
1766     /// Returns the [`str`] slice for this prefix.
as_str(&self) -> &'a str1767     pub fn as_str(&self) -> &'a str {
1768         // SAFETY: Utf8PrefixComponent was constructed from a Utf8Path, so it is guaranteed to be
1769         // valid UTF-8
1770         unsafe { assume_utf8(self.as_os_str()) }
1771     }
1772 
1773     /// Returns the raw [`OsStr`] slice for this prefix.
as_os_str(&self) -> &'a OsStr1774     pub fn as_os_str(&self) -> &'a OsStr {
1775         self.0.as_os_str()
1776     }
1777 }
1778 
1779 impl<'a> fmt::Debug for Utf8PrefixComponent<'a> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1780     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1781         fmt::Debug::fmt(&self.0, f)
1782     }
1783 }
1784 
1785 impl<'a> fmt::Display for Utf8PrefixComponent<'a> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1786     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1787         fmt::Display::fmt(self.as_str(), f)
1788     }
1789 }
1790 
1791 // ---
1792 
1793 impl From<String> for Utf8PathBuf {
from(string: String) -> Utf8PathBuf1794     fn from(string: String) -> Utf8PathBuf {
1795         Utf8PathBuf(string.into())
1796     }
1797 }
1798 
1799 impl FromStr for Utf8PathBuf {
1800     type Err = Infallible;
1801 
from_str(s: &str) -> Result<Self, Self::Err>1802     fn from_str(s: &str) -> Result<Self, Self::Err> {
1803         Ok(Utf8PathBuf(s.into()))
1804     }
1805 }
1806 
1807 // ---
1808 // From impls: borrowed -> borrowed
1809 // ---
1810 
1811 impl<'a> From<&'a str> for &'a Utf8Path {
from(s: &'a str) -> &'a Utf8Path1812     fn from(s: &'a str) -> &'a Utf8Path {
1813         Utf8Path::new(s)
1814     }
1815 }
1816 
1817 // ---
1818 // From impls: borrowed -> owned
1819 // ---
1820 
1821 impl<T: ?Sized + AsRef<str>> From<&T> for Utf8PathBuf {
from(s: &T) -> Utf8PathBuf1822     fn from(s: &T) -> Utf8PathBuf {
1823         Utf8PathBuf::from(s.as_ref().to_owned())
1824     }
1825 }
1826 
1827 impl<T: ?Sized + AsRef<str>> From<&T> for Box<Utf8Path> {
from(s: &T) -> Box<Utf8Path>1828     fn from(s: &T) -> Box<Utf8Path> {
1829         Utf8PathBuf::from(s).into_boxed_path()
1830     }
1831 }
1832 
1833 impl From<&'_ Utf8Path> for Arc<Utf8Path> {
from(path: &Utf8Path) -> Arc<Utf8Path>1834     fn from(path: &Utf8Path) -> Arc<Utf8Path> {
1835         let arc: Arc<Path> = Arc::from(AsRef::<Path>::as_ref(path));
1836         let ptr = Arc::into_raw(arc) as *const Utf8Path;
1837         // SAFETY:
1838         // * path is valid UTF-8
1839         // * ptr was created by consuming an Arc<Path> so it represents an arced pointer
1840         // * Utf8Path is marked as #[repr(transparent)] so the conversion from *const Path to
1841         //   *const Utf8Path is valid
1842         unsafe { Arc::from_raw(ptr) }
1843     }
1844 }
1845 
1846 impl From<&'_ Utf8Path> for Rc<Utf8Path> {
from(path: &Utf8Path) -> Rc<Utf8Path>1847     fn from(path: &Utf8Path) -> Rc<Utf8Path> {
1848         let rc: Rc<Path> = Rc::from(AsRef::<Path>::as_ref(path));
1849         let ptr = Rc::into_raw(rc) as *const Utf8Path;
1850         // SAFETY:
1851         // * path is valid UTF-8
1852         // * ptr was created by consuming an Rc<Path> so it represents an rced pointer
1853         // * Utf8Path is marked as #[repr(transparent)] so the conversion from *const Path to
1854         //   *const Utf8Path is valid
1855         unsafe { Rc::from_raw(ptr) }
1856     }
1857 }
1858 
1859 impl<'a> From<&'a Utf8Path> for Cow<'a, Utf8Path> {
from(path: &'a Utf8Path) -> Cow<'a, Utf8Path>1860     fn from(path: &'a Utf8Path) -> Cow<'a, Utf8Path> {
1861         Cow::Borrowed(path)
1862     }
1863 }
1864 
1865 impl From<&'_ Utf8Path> for Box<Path> {
from(path: &Utf8Path) -> Box<Path>1866     fn from(path: &Utf8Path) -> Box<Path> {
1867         AsRef::<Path>::as_ref(path).into()
1868     }
1869 }
1870 
1871 impl From<&'_ Utf8Path> for Arc<Path> {
from(path: &Utf8Path) -> Arc<Path>1872     fn from(path: &Utf8Path) -> Arc<Path> {
1873         AsRef::<Path>::as_ref(path).into()
1874     }
1875 }
1876 
1877 impl From<&'_ Utf8Path> for Rc<Path> {
from(path: &Utf8Path) -> Rc<Path>1878     fn from(path: &Utf8Path) -> Rc<Path> {
1879         AsRef::<Path>::as_ref(path).into()
1880     }
1881 }
1882 
1883 impl<'a> From<&'a Utf8Path> for Cow<'a, Path> {
from(path: &'a Utf8Path) -> Cow<'a, Path>1884     fn from(path: &'a Utf8Path) -> Cow<'a, Path> {
1885         Cow::Borrowed(path.as_ref())
1886     }
1887 }
1888 
1889 // ---
1890 // From impls: owned -> owned
1891 // ---
1892 
1893 impl From<Box<Utf8Path>> for Utf8PathBuf {
from(path: Box<Utf8Path>) -> Utf8PathBuf1894     fn from(path: Box<Utf8Path>) -> Utf8PathBuf {
1895         path.into_path_buf()
1896     }
1897 }
1898 
1899 impl From<Utf8PathBuf> for Box<Utf8Path> {
from(path: Utf8PathBuf) -> Box<Utf8Path>1900     fn from(path: Utf8PathBuf) -> Box<Utf8Path> {
1901         path.into_boxed_path()
1902     }
1903 }
1904 
1905 impl<'a> From<Cow<'a, Utf8Path>> for Utf8PathBuf {
from(path: Cow<'a, Utf8Path>) -> Utf8PathBuf1906     fn from(path: Cow<'a, Utf8Path>) -> Utf8PathBuf {
1907         path.into_owned()
1908     }
1909 }
1910 
1911 impl From<Utf8PathBuf> for String {
from(path: Utf8PathBuf) -> String1912     fn from(path: Utf8PathBuf) -> String {
1913         path.into_string()
1914     }
1915 }
1916 
1917 impl From<Utf8PathBuf> for OsString {
from(path: Utf8PathBuf) -> OsString1918     fn from(path: Utf8PathBuf) -> OsString {
1919         path.into_os_string()
1920     }
1921 }
1922 
1923 impl<'a> From<Utf8PathBuf> for Cow<'a, Utf8Path> {
from(path: Utf8PathBuf) -> Cow<'a, Utf8Path>1924     fn from(path: Utf8PathBuf) -> Cow<'a, Utf8Path> {
1925         Cow::Owned(path)
1926     }
1927 }
1928 
1929 impl From<Utf8PathBuf> for Arc<Utf8Path> {
from(path: Utf8PathBuf) -> Arc<Utf8Path>1930     fn from(path: Utf8PathBuf) -> Arc<Utf8Path> {
1931         let arc: Arc<Path> = Arc::from(path.0);
1932         let ptr = Arc::into_raw(arc) as *const Utf8Path;
1933         // SAFETY:
1934         // * path is valid UTF-8
1935         // * ptr was created by consuming an Arc<Path> so it represents an arced pointer
1936         // * Utf8Path is marked as #[repr(transparent)] so the conversion from *const Path to
1937         //   *const Utf8Path is valid
1938         unsafe { Arc::from_raw(ptr) }
1939     }
1940 }
1941 
1942 impl From<Utf8PathBuf> for Rc<Utf8Path> {
from(path: Utf8PathBuf) -> Rc<Utf8Path>1943     fn from(path: Utf8PathBuf) -> Rc<Utf8Path> {
1944         let rc: Rc<Path> = Rc::from(path.0);
1945         let ptr = Rc::into_raw(rc) as *const Utf8Path;
1946         // SAFETY:
1947         // * path is valid UTF-8
1948         // * ptr was created by consuming an Rc<Path> so it represents an rced pointer
1949         // * Utf8Path is marked as #[repr(transparent)] so the conversion from *const Path to
1950         //   *const Utf8Path is valid
1951         unsafe { Rc::from_raw(ptr) }
1952     }
1953 }
1954 
1955 impl From<Utf8PathBuf> for PathBuf {
from(path: Utf8PathBuf) -> PathBuf1956     fn from(path: Utf8PathBuf) -> PathBuf {
1957         path.0
1958     }
1959 }
1960 
1961 impl From<Utf8PathBuf> for Box<Path> {
from(path: Utf8PathBuf) -> Box<Path>1962     fn from(path: Utf8PathBuf) -> Box<Path> {
1963         PathBuf::from(path).into_boxed_path()
1964     }
1965 }
1966 
1967 impl From<Utf8PathBuf> for Arc<Path> {
from(path: Utf8PathBuf) -> Arc<Path>1968     fn from(path: Utf8PathBuf) -> Arc<Path> {
1969         PathBuf::from(path).into()
1970     }
1971 }
1972 
1973 impl From<Utf8PathBuf> for Rc<Path> {
from(path: Utf8PathBuf) -> Rc<Path>1974     fn from(path: Utf8PathBuf) -> Rc<Path> {
1975         PathBuf::from(path).into()
1976     }
1977 }
1978 
1979 impl<'a> From<Utf8PathBuf> for Cow<'a, Path> {
from(path: Utf8PathBuf) -> Cow<'a, Path>1980     fn from(path: Utf8PathBuf) -> Cow<'a, Path> {
1981         PathBuf::from(path).into()
1982     }
1983 }
1984 
1985 // ---
1986 // TryFrom impls
1987 // ---
1988 
1989 impl TryFrom<PathBuf> for Utf8PathBuf {
1990     type Error = FromPathBufError;
1991 
try_from(path: PathBuf) -> Result<Utf8PathBuf, Self::Error>1992     fn try_from(path: PathBuf) -> Result<Utf8PathBuf, Self::Error> {
1993         Utf8PathBuf::from_path_buf(path).map_err(|path| FromPathBufError {
1994             path,
1995             error: FromPathError(()),
1996         })
1997     }
1998 }
1999 
2000 impl<'a> TryFrom<&'a Path> for &'a Utf8Path {
2001     type Error = FromPathError;
2002 
try_from(path: &'a Path) -> Result<&'a Utf8Path, Self::Error>2003     fn try_from(path: &'a Path) -> Result<&'a Utf8Path, Self::Error> {
2004         Utf8Path::from_path(path).ok_or(FromPathError(()))
2005     }
2006 }
2007 
2008 /// A possible error value while converting a [`PathBuf`] to a [`Utf8PathBuf`].
2009 ///
2010 /// Produced by the `TryFrom<PathBuf>` implementation for [`Utf8PathBuf`].
2011 ///
2012 /// # Examples
2013 ///
2014 /// ```
2015 /// use camino::{Utf8PathBuf, FromPathBufError};
2016 /// use std::convert::{TryFrom, TryInto};
2017 /// use std::ffi::OsStr;
2018 /// # #[cfg(unix)]
2019 /// use std::os::unix::ffi::OsStrExt;
2020 /// use std::path::PathBuf;
2021 ///
2022 /// let unicode_path = PathBuf::from("/valid/unicode");
2023 /// let utf8_path_buf: Utf8PathBuf = unicode_path.try_into().expect("valid Unicode path succeeded");
2024 ///
2025 /// // Paths on Unix can be non-UTF-8.
2026 /// # #[cfg(unix)]
2027 /// let non_unicode_str = OsStr::from_bytes(b"\xFF\xFF\xFF");
2028 /// # #[cfg(unix)]
2029 /// let non_unicode_path = PathBuf::from(non_unicode_str);
2030 /// # #[cfg(unix)]
2031 /// let err: FromPathBufError = Utf8PathBuf::try_from(non_unicode_path.clone())
2032 ///     .expect_err("non-Unicode path failed");
2033 /// # #[cfg(unix)]
2034 /// assert_eq!(err.as_path(), &non_unicode_path);
2035 /// # #[cfg(unix)]
2036 /// assert_eq!(err.into_path_buf(), non_unicode_path);
2037 /// ```
2038 #[derive(Clone, Debug, Eq, PartialEq)]
2039 pub struct FromPathBufError {
2040     path: PathBuf,
2041     error: FromPathError,
2042 }
2043 
2044 impl FromPathBufError {
2045     /// Returns the [`Path`] slice that was attempted to be converted to [`Utf8PathBuf`].
as_path(&self) -> &Path2046     pub fn as_path(&self) -> &Path {
2047         &self.path
2048     }
2049 
2050     /// Returns the [`PathBuf`] that was attempted to be converted to [`Utf8PathBuf`].
into_path_buf(self) -> PathBuf2051     pub fn into_path_buf(self) -> PathBuf {
2052         self.path
2053     }
2054 
2055     /// Fetch a [`FromPathError`] for more about the conversion failure.
2056     ///
2057     /// At the moment this struct does not contain any additional information, but is provided for
2058     /// completeness.
from_path_error(&self) -> FromPathError2059     pub fn from_path_error(&self) -> FromPathError {
2060         self.error
2061     }
2062 }
2063 
2064 impl fmt::Display for FromPathBufError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result2065     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2066         write!(f, "PathBuf contains invalid UTF-8: {}", self.path.display())
2067     }
2068 }
2069 
2070 impl error::Error for FromPathBufError {
source(&self) -> Option<&(dyn error::Error + 'static)>2071     fn source(&self) -> Option<&(dyn error::Error + 'static)> {
2072         Some(&self.error)
2073     }
2074 }
2075 
2076 /// A possible error value while converting a [`Path`] to a [`Utf8Path`].
2077 ///
2078 /// Produced by the `TryFrom<&Path>` implementation for [`&Utf8Path`](Utf8Path).
2079 ///
2080 ///
2081 /// # Examples
2082 ///
2083 /// ```
2084 /// use camino::{Utf8Path, FromPathError};
2085 /// use std::convert::{TryFrom, TryInto};
2086 /// use std::ffi::OsStr;
2087 /// # #[cfg(unix)]
2088 /// use std::os::unix::ffi::OsStrExt;
2089 /// use std::path::Path;
2090 ///
2091 /// let unicode_path = Path::new("/valid/unicode");
2092 /// let utf8_path: &Utf8Path = unicode_path.try_into().expect("valid Unicode path succeeded");
2093 ///
2094 /// // Paths on Unix can be non-UTF-8.
2095 /// # #[cfg(unix)]
2096 /// let non_unicode_str = OsStr::from_bytes(b"\xFF\xFF\xFF");
2097 /// # #[cfg(unix)]
2098 /// let non_unicode_path = Path::new(non_unicode_str);
2099 /// # #[cfg(unix)]
2100 /// let err: FromPathError = <&Utf8Path>::try_from(non_unicode_path)
2101 ///     .expect_err("non-Unicode path failed");
2102 /// ```
2103 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
2104 pub struct FromPathError(());
2105 
2106 impl fmt::Display for FromPathError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result2107     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2108         write!(f, "Path contains invalid UTF-8")
2109     }
2110 }
2111 
2112 impl error::Error for FromPathError {
source(&self) -> Option<&(dyn error::Error + 'static)>2113     fn source(&self) -> Option<&(dyn error::Error + 'static)> {
2114         None
2115     }
2116 }
2117 
2118 // ---
2119 // AsRef impls
2120 // ---
2121 
2122 impl AsRef<Utf8Path> for Utf8Path {
as_ref(&self) -> &Utf8Path2123     fn as_ref(&self) -> &Utf8Path {
2124         self
2125     }
2126 }
2127 
2128 impl AsRef<Utf8Path> for Utf8PathBuf {
as_ref(&self) -> &Utf8Path2129     fn as_ref(&self) -> &Utf8Path {
2130         self.as_path()
2131     }
2132 }
2133 
2134 impl AsRef<Utf8Path> for str {
as_ref(&self) -> &Utf8Path2135     fn as_ref(&self) -> &Utf8Path {
2136         Utf8Path::new(self)
2137     }
2138 }
2139 
2140 impl AsRef<Utf8Path> for String {
as_ref(&self) -> &Utf8Path2141     fn as_ref(&self) -> &Utf8Path {
2142         Utf8Path::new(self)
2143     }
2144 }
2145 
2146 impl AsRef<Path> for Utf8Path {
as_ref(&self) -> &Path2147     fn as_ref(&self) -> &Path {
2148         &self.0
2149     }
2150 }
2151 
2152 impl AsRef<Path> for Utf8PathBuf {
as_ref(&self) -> &Path2153     fn as_ref(&self) -> &Path {
2154         &*self.0
2155     }
2156 }
2157 
2158 impl AsRef<str> for Utf8Path {
as_ref(&self) -> &str2159     fn as_ref(&self) -> &str {
2160         self.as_str()
2161     }
2162 }
2163 
2164 impl AsRef<str> for Utf8PathBuf {
as_ref(&self) -> &str2165     fn as_ref(&self) -> &str {
2166         self.as_str()
2167     }
2168 }
2169 
2170 impl AsRef<OsStr> for Utf8Path {
as_ref(&self) -> &OsStr2171     fn as_ref(&self) -> &OsStr {
2172         self.as_os_str()
2173     }
2174 }
2175 
2176 impl AsRef<OsStr> for Utf8PathBuf {
as_ref(&self) -> &OsStr2177     fn as_ref(&self) -> &OsStr {
2178         self.as_os_str()
2179     }
2180 }
2181 
2182 // ---
2183 // Borrow and ToOwned
2184 // ---
2185 
2186 impl Borrow<Utf8Path> for Utf8PathBuf {
borrow(&self) -> &Utf8Path2187     fn borrow(&self) -> &Utf8Path {
2188         self.as_path()
2189     }
2190 }
2191 
2192 impl ToOwned for Utf8Path {
2193     type Owned = Utf8PathBuf;
2194 
to_owned(&self) -> Utf8PathBuf2195     fn to_owned(&self) -> Utf8PathBuf {
2196         self.to_path_buf()
2197     }
2198 }
2199 
2200 impl<P: AsRef<Utf8Path>> std::iter::FromIterator<P> for Utf8PathBuf {
from_iter<I: IntoIterator<Item = P>>(iter: I) -> Utf8PathBuf2201     fn from_iter<I: IntoIterator<Item = P>>(iter: I) -> Utf8PathBuf {
2202         let mut buf = Utf8PathBuf::new();
2203         buf.extend(iter);
2204         buf
2205     }
2206 }
2207 
2208 // ---
2209 // [Partial]Eq, [Partial]Ord, Hash
2210 // ---
2211 
2212 impl PartialEq for Utf8PathBuf {
eq(&self, other: &Utf8PathBuf) -> bool2213     fn eq(&self, other: &Utf8PathBuf) -> bool {
2214         self.components() == other.components()
2215     }
2216 }
2217 
2218 impl Eq for Utf8PathBuf {}
2219 
2220 impl Hash for Utf8PathBuf {
hash<H: Hasher>(&self, state: &mut H)2221     fn hash<H: Hasher>(&self, state: &mut H) {
2222         self.as_path().hash(state)
2223     }
2224 }
2225 
2226 impl PartialOrd for Utf8PathBuf {
partial_cmp(&self, other: &Utf8PathBuf) -> Option<Ordering>2227     fn partial_cmp(&self, other: &Utf8PathBuf) -> Option<Ordering> {
2228         self.components().partial_cmp(other.components())
2229     }
2230 }
2231 
2232 impl Ord for Utf8PathBuf {
cmp(&self, other: &Utf8PathBuf) -> Ordering2233     fn cmp(&self, other: &Utf8PathBuf) -> Ordering {
2234         self.components().cmp(other.components())
2235     }
2236 }
2237 
2238 impl PartialEq for Utf8Path {
eq(&self, other: &Utf8Path) -> bool2239     fn eq(&self, other: &Utf8Path) -> bool {
2240         self.components().eq(other.components())
2241     }
2242 }
2243 
2244 impl Eq for Utf8Path {}
2245 
2246 impl Hash for Utf8Path {
hash<H: Hasher>(&self, state: &mut H)2247     fn hash<H: Hasher>(&self, state: &mut H) {
2248         for component in self.components() {
2249             component.hash(state)
2250         }
2251     }
2252 }
2253 
2254 impl PartialOrd for Utf8Path {
partial_cmp(&self, other: &Utf8Path) -> Option<Ordering>2255     fn partial_cmp(&self, other: &Utf8Path) -> Option<Ordering> {
2256         self.components().partial_cmp(other.components())
2257     }
2258 }
2259 
2260 impl Ord for Utf8Path {
cmp(&self, other: &Utf8Path) -> Ordering2261     fn cmp(&self, other: &Utf8Path) -> Ordering {
2262         self.components().cmp(other.components())
2263     }
2264 }
2265 
2266 impl<'a> IntoIterator for &'a Utf8PathBuf {
2267     type Item = &'a str;
2268     type IntoIter = Iter<'a>;
into_iter(self) -> Iter<'a>2269     fn into_iter(self) -> Iter<'a> {
2270         self.iter()
2271     }
2272 }
2273 
2274 impl<'a> IntoIterator for &'a Utf8Path {
2275     type Item = &'a str;
2276     type IntoIter = Iter<'a>;
into_iter(self) -> Iter<'a>2277     fn into_iter(self) -> Iter<'a> {
2278         self.iter()
2279     }
2280 }
2281 
2282 macro_rules! impl_cmp {
2283     ($lhs:ty, $rhs: ty) => {
2284         impl<'a, 'b> PartialEq<$rhs> for $lhs {
2285             #[inline]
2286             fn eq(&self, other: &$rhs) -> bool {
2287                 <Utf8Path as PartialEq>::eq(self, other)
2288             }
2289         }
2290 
2291         impl<'a, 'b> PartialEq<$lhs> for $rhs {
2292             #[inline]
2293             fn eq(&self, other: &$lhs) -> bool {
2294                 <Utf8Path as PartialEq>::eq(self, other)
2295             }
2296         }
2297 
2298         impl<'a, 'b> PartialOrd<$rhs> for $lhs {
2299             #[inline]
2300             fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> {
2301                 <Utf8Path as PartialOrd>::partial_cmp(self, other)
2302             }
2303         }
2304 
2305         impl<'a, 'b> PartialOrd<$lhs> for $rhs {
2306             #[inline]
2307             fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> {
2308                 <Utf8Path as PartialOrd>::partial_cmp(self, other)
2309             }
2310         }
2311     };
2312 }
2313 
2314 impl_cmp!(Utf8PathBuf, Utf8Path);
2315 impl_cmp!(Utf8PathBuf, &'a Utf8Path);
2316 impl_cmp!(Cow<'a, Utf8Path>, Utf8Path);
2317 impl_cmp!(Cow<'a, Utf8Path>, &'b Utf8Path);
2318 impl_cmp!(Cow<'a, Utf8Path>, Utf8PathBuf);
2319 
2320 macro_rules! impl_cmp_std_path {
2321     ($lhs:ty, $rhs: ty) => {
2322         impl<'a, 'b> PartialEq<$rhs> for $lhs {
2323             #[inline]
2324             fn eq(&self, other: &$rhs) -> bool {
2325                 <Path as PartialEq>::eq(self.as_ref(), other)
2326             }
2327         }
2328 
2329         impl<'a, 'b> PartialEq<$lhs> for $rhs {
2330             #[inline]
2331             fn eq(&self, other: &$lhs) -> bool {
2332                 <Path as PartialEq>::eq(self, other.as_ref())
2333             }
2334         }
2335 
2336         impl<'a, 'b> PartialOrd<$rhs> for $lhs {
2337             #[inline]
2338             fn partial_cmp(&self, other: &$rhs) -> Option<std::cmp::Ordering> {
2339                 <Path as PartialOrd>::partial_cmp(self.as_ref(), other)
2340             }
2341         }
2342 
2343         impl<'a, 'b> PartialOrd<$lhs> for $rhs {
2344             #[inline]
2345             fn partial_cmp(&self, other: &$lhs) -> Option<std::cmp::Ordering> {
2346                 <Path as PartialOrd>::partial_cmp(self, other.as_ref())
2347             }
2348         }
2349     };
2350 }
2351 
2352 impl_cmp_std_path!(Utf8PathBuf, Path);
2353 impl_cmp_std_path!(Utf8PathBuf, &'a Path);
2354 impl_cmp_std_path!(Utf8PathBuf, Cow<'a, Path>);
2355 impl_cmp_std_path!(Utf8PathBuf, PathBuf);
2356 impl_cmp_std_path!(Utf8Path, Path);
2357 impl_cmp_std_path!(Utf8Path, &'a Path);
2358 impl_cmp_std_path!(Utf8Path, Cow<'a, Path>);
2359 impl_cmp_std_path!(Utf8Path, PathBuf);
2360 impl_cmp_std_path!(&'a Utf8Path, Path);
2361 impl_cmp_std_path!(&'a Utf8Path, Cow<'b, Path>);
2362 impl_cmp_std_path!(&'a Utf8Path, PathBuf);
2363 // NOTE: impls for Cow<'a, Utf8Path> cannot be defined because of the orphan rule (E0117)
2364 
2365 macro_rules! impl_cmp_str {
2366     ($lhs:ty, $rhs: ty) => {
2367         impl<'a, 'b> PartialEq<$rhs> for $lhs {
2368             #[inline]
2369             fn eq(&self, other: &$rhs) -> bool {
2370                 <Utf8Path as PartialEq>::eq(self, Utf8Path::new(other))
2371             }
2372         }
2373 
2374         impl<'a, 'b> PartialEq<$lhs> for $rhs {
2375             #[inline]
2376             fn eq(&self, other: &$lhs) -> bool {
2377                 <Utf8Path as PartialEq>::eq(Utf8Path::new(self), other)
2378             }
2379         }
2380 
2381         impl<'a, 'b> PartialOrd<$rhs> for $lhs {
2382             #[inline]
2383             fn partial_cmp(&self, other: &$rhs) -> Option<std::cmp::Ordering> {
2384                 <Utf8Path as PartialOrd>::partial_cmp(self, Utf8Path::new(other))
2385             }
2386         }
2387 
2388         impl<'a, 'b> PartialOrd<$lhs> for $rhs {
2389             #[inline]
2390             fn partial_cmp(&self, other: &$lhs) -> Option<std::cmp::Ordering> {
2391                 <Utf8Path as PartialOrd>::partial_cmp(Utf8Path::new(self), other)
2392             }
2393         }
2394     };
2395 }
2396 
2397 impl_cmp_str!(Utf8PathBuf, str);
2398 impl_cmp_str!(Utf8PathBuf, &'a str);
2399 impl_cmp_str!(Utf8PathBuf, Cow<'a, str>);
2400 impl_cmp_str!(Utf8PathBuf, String);
2401 impl_cmp_str!(Utf8Path, str);
2402 impl_cmp_str!(Utf8Path, &'a str);
2403 impl_cmp_str!(Utf8Path, Cow<'a, str>);
2404 impl_cmp_str!(Utf8Path, String);
2405 impl_cmp_str!(&'a Utf8Path, str);
2406 impl_cmp_str!(&'a Utf8Path, Cow<'b, str>);
2407 impl_cmp_str!(&'a Utf8Path, String);
2408 // NOTE: impls for Cow<'a, Utf8Path> cannot be defined because of the orphan rule (E0117)
2409 
2410 macro_rules! impl_cmp_os_str {
2411     ($lhs:ty, $rhs: ty) => {
2412         impl<'a, 'b> PartialEq<$rhs> for $lhs {
2413             #[inline]
2414             fn eq(&self, other: &$rhs) -> bool {
2415                 <Path as PartialEq>::eq(self.as_ref(), other.as_ref())
2416             }
2417         }
2418 
2419         impl<'a, 'b> PartialEq<$lhs> for $rhs {
2420             #[inline]
2421             fn eq(&self, other: &$lhs) -> bool {
2422                 <Path as PartialEq>::eq(self.as_ref(), other.as_ref())
2423             }
2424         }
2425 
2426         impl<'a, 'b> PartialOrd<$rhs> for $lhs {
2427             #[inline]
2428             fn partial_cmp(&self, other: &$rhs) -> Option<std::cmp::Ordering> {
2429                 <Path as PartialOrd>::partial_cmp(self.as_ref(), other.as_ref())
2430             }
2431         }
2432 
2433         impl<'a, 'b> PartialOrd<$lhs> for $rhs {
2434             #[inline]
2435             fn partial_cmp(&self, other: &$lhs) -> Option<std::cmp::Ordering> {
2436                 <Path as PartialOrd>::partial_cmp(self.as_ref(), other.as_ref())
2437             }
2438         }
2439     };
2440 }
2441 
2442 impl_cmp_os_str!(Utf8PathBuf, OsStr);
2443 impl_cmp_os_str!(Utf8PathBuf, &'a OsStr);
2444 impl_cmp_os_str!(Utf8PathBuf, Cow<'a, OsStr>);
2445 impl_cmp_os_str!(Utf8PathBuf, OsString);
2446 impl_cmp_os_str!(Utf8Path, OsStr);
2447 impl_cmp_os_str!(Utf8Path, &'a OsStr);
2448 impl_cmp_os_str!(Utf8Path, Cow<'a, OsStr>);
2449 impl_cmp_os_str!(Utf8Path, OsString);
2450 impl_cmp_os_str!(&'a Utf8Path, OsStr);
2451 impl_cmp_os_str!(&'a Utf8Path, Cow<'b, OsStr>);
2452 impl_cmp_os_str!(&'a Utf8Path, OsString);
2453 // NOTE: impls for Cow<'a, Utf8Path> cannot be defined because of the orphan rule (E0117)
2454 
2455 // invariant: OsStr must be guaranteed to be utf8 data
assume_utf8(string: &OsStr) -> &str2456 unsafe fn assume_utf8(string: &OsStr) -> &str {
2457     &*(string as *const OsStr as *const str)
2458 }
2459