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