Skip to main content

relative_path/
lib.rs

1//! [<img alt="github" src="https://img.shields.io/badge/github-udoprog/relative--path-8da0cb?style=for-the-badge&logo=github" height="20">](https://github.com/udoprog/relative-path)
2//! [<img alt="crates.io" src="https://img.shields.io/crates/v/relative-path.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/relative-path)
3//! [<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-relative--path-66c2a5?style=for-the-badge&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K" height="20">](https://docs.rs/relative-path)
4//!
5//! Portable relative UTF-8 paths for Rust.
6//!
7//! This crate provides a module analogous to [`std::path`], with the following
8//! characteristics:
9//!
10//! * The path separator is set to a fixed character (`/`), regardless of
11//!   platform.
12//! * Relative paths cannot represent a path in the filesystem without first
13//!   specifying *what they are relative to* using functions such as [`to_path`]
14//!   and [`to_logical_path`].
15//! * Relative paths are always guaranteed to be valid UTF-8 strings.
16//!
17//! On top of this we support many operations that guarantee the same behavior
18//! across platforms.
19//!
20//! For more utilities to manipulate relative paths, see the
21//! [`relative-path-utils` crate].
22//!
23//! <br>
24//!
25//! ## Usage
26//!
27//! Add `relative-path` to your `Cargo.toml`:
28//!
29//! ```toml
30//! relative-path = "2.0.3"
31//! ```
32//!
33//! Start using relative paths:
34//!
35//! ```
36//! use serde::{Serialize, Deserialize};
37//! use relative_path::RelativePath;
38//!
39//! #[derive(Serialize, Deserialize)]
40//! struct Manifest<'a> {
41//!     #[serde(borrow)]
42//!     source: &'a RelativePath,
43//! }
44//!
45//! # Ok::<_, Box<dyn std::error::Error>>(())
46//! ```
47//!
48//! <br>
49//!
50//! ## Serde Support
51//!
52//! This library includes serde support that can be enabled with the `serde`
53//! feature.
54//!
55//! <br>
56//!
57//! ## Musli Support
58//!
59//! This library includes [Müsli] 0.2 support that can be enabled with the
60//! `musli02` feature. Paths are encoded as strings, the same representation the
61//! serde support uses.
62//!
63//! Encoding a `Box<RelativePath>` uses musli's implementation for `Box`, which
64//! requires musli's `alloc` feature.
65//!
66//! <br>
67//!
68//! ## Why is `std::path` a portability hazard?
69//!
70//! Path representations differ across platforms.
71//!
72//! * Windows permits using drive volumes (multiple roots) as a prefix (e.g.
73//!   `"c:\"`) and backslash (`\`) as a separator.
74//! * Unix references absolute paths from a single root and uses forward slash
75//!   (`/`) as a separator.
76//!
77//! If we use `PathBuf`, Storing paths in a manifest would allow our application
78//! to build and run on one platform but potentially not others.
79//!
80//! Consider the following data model and corresponding toml for a manifest:
81//!
82//! ```rust
83//! use std::path::PathBuf;
84//!
85//! use serde::{Serialize, Deserialize};
86//!
87//! #[derive(Serialize, Deserialize)]
88//! struct Manifest {
89//!     source: PathBuf,
90//! }
91//! ```
92//!
93//! ```toml
94//! source = "C:\\Users\\udoprog\\repo\\data\\source"
95//! ```
96//!
97//! This will run for you (assuming `source` exists). So you go ahead and check
98//! the manifest into git. The next day your Linux colleague calls you and
99//! wonders what they have ever done to wrong you?
100//!
101//! So what went wrong? Well two things. You forgot to make the `source`
102//! relative, so anyone at the company which has a different username than you
103//! won't be able to use it. So you go ahead and fix that:
104//!
105//! ```toml
106//! source = "data\\source"
107//! ```
108//!
109//! But there is still one problem! A backslash (`\`) is only a legal path
110//! separator on Windows. Luckily you learn that forward slashes are supported
111//! both on Windows *and* Linux. So you opt for:
112//!
113//! ```toml
114//! source = "data/source"
115//! ```
116//!
117//! Things are working now. So all is well... Right? Sure, but we can do better.
118//!
119//! This crate provides types that work with *portable relative paths* (hence
120//! the name). So by using [`RelativePath`] we can systematically help avoid
121//! portability issues like the one above. Avoiding issues at the source is
122//! preferably over spending 5 minutes of onboarding time on a theoretical
123//! problem, hoping that your new hires will remember what to do if they ever
124//! encounter it.
125//!
126//! Using [`RelativePathBuf`] we can fix our data model like this:
127//!
128//! ```rust
129//! use relative_path::RelativePathBuf;
130//! use serde::{Serialize, Deserialize};
131//!
132//! #[derive(Serialize, Deserialize)]
133//! pub struct Manifest {
134//!     source: RelativePathBuf,
135//! }
136//! ```
137//!
138//! And where it's used:
139//!
140//! ```rust,no_run
141//! # use relative_path::RelativePathBuf;
142//! # use serde::{Serialize, Deserialize};
143//! # #[derive(Serialize, Deserialize)] pub struct Manifest { source: RelativePathBuf }
144//! use std::fs;
145//! use std::env::current_dir;
146//!
147//! let manifest: Manifest = todo!();
148//!
149//! let root = current_dir()?;
150//! let source = manifest.source.to_path(&root);
151//! let content = fs::read(&source)?;
152//! # Ok::<_, Box<dyn std::error::Error>>(())
153//! ```
154//!
155//! <br>
156//!
157//! ## Overview
158//!
159//! Conversion to a platform-specific [`Path`] happens through the [`to_path`]
160//! and [`to_logical_path`] functions. Where you are required to specify the
161//! path that prefixes the relative path. This can come from a function such as
162//! [`std::env::current_dir`].
163//!
164//! ```rust
165//! use std::env::current_dir;
166//! use std::path::Path;
167//!
168//! use relative_path::RelativePath;
169//!
170//! let root = current_dir()?;
171//!
172//! # if cfg!(windows) {
173//! // to_path unconditionally concatenates a relative path with its base:
174//! let relative_path = RelativePath::new("../foo/./bar");
175//! let full_path = relative_path.to_path(&root);
176//! assert_eq!(full_path, root.join("..\\foo\\.\\bar"));
177//!
178//! // to_logical_path tries to apply the logical operations that the relative
179//! // path corresponds to:
180//! let relative_path = RelativePath::new("../foo/./bar");
181//! let full_path = relative_path.to_logical_path(&root);
182//!
183//! // Replicate the operation performed by `to_logical_path`.
184//! let mut parent = root.clone();
185//! parent.pop();
186//! assert_eq!(full_path, parent.join("foo\\bar"));
187//! # }
188//! # Ok::<_, std::io::Error>(())
189//! ```
190//!
191//! When two relative paths are compared to each other, their exact component
192//! makeup determines equality.
193//!
194//! ```rust
195//! use relative_path::RelativePath;
196//!
197//! assert_ne!(
198//!     RelativePath::new("foo/bar/../baz"),
199//!     RelativePath::new("foo/baz")
200//! );
201//! ```
202//!
203//! Using platform-specific path separators to construct relative paths is not
204//! supported.
205//!
206//! Path separators from other platforms are simply treated as part of a
207//! component:
208//!
209//! ```rust
210//! use relative_path::RelativePath;
211//!
212//! assert_ne!(
213//!     RelativePath::new("foo/bar"),
214//!     RelativePath::new("foo\\bar")
215//! );
216//!
217//! assert_eq!(1, RelativePath::new("foo\\bar").components().count());
218//! assert_eq!(2, RelativePath::new("foo/bar").components().count());
219//! ```
220//!
221//! To see if two relative paths are equivalent you can use [`normalize`]:
222//!
223//! ```rust
224//! use relative_path::RelativePath;
225//!
226//! assert_eq!(
227//!     RelativePath::new("foo/bar/../baz").normalize(),
228//!     RelativePath::new("foo/baz").normalize(),
229//! );
230//! ```
231//!
232//! <br>
233//!
234//! ## Additional portability notes
235//!
236//! While relative paths avoid the most egregious portability issue, that
237//! absolute paths will work equally unwell on all platforms. We cannot avoid
238//! all. This section tries to document additional portability hazards that we
239//! are aware of.
240//!
241//! [`RelativePath`], similarly to [`Path`], makes no guarantees that its
242//! constituent components make up legal file names. While components are
243//! strictly separated by slashes, we can still store things in them which may
244//! not be used as legal paths on all platforms.
245//!
246//! * A `NUL` character is not permitted on unix platforms - this is a
247//!   terminator in C-based filesystem APIs. Slash (`/`) is also used as a path
248//!   separator.
249//! * Windows has a number of [reserved characters and names][windows-reserved]
250//!   (like `CON`, `PRN`, and `AUX`) which cannot legally be part of a
251//!   filesystem component.
252//! * Windows paths are [case-insensitive by default][windows-case]. So,
253//!   `Foo.txt` and `foo.txt` are the same files on windows. But they are
254//!   considered different paths on most unix systems.
255//!
256//! A relative path that *accidentally* contains a platform-specific components
257//! will largely result in a nonsensical paths being generated in the hope that
258//! they will fail fast during development and testing.
259//!
260//! ```rust
261//! use relative_path::{RelativePath, PathExt};
262//! use std::path::Path;
263//!
264//! if cfg!(windows) {
265//!     assert_eq!(
266//!         Path::new("foo\\c:\\bar\\baz"),
267//!         RelativePath::new("c:\\bar\\baz").to_path("foo")
268//!     );
269//! }
270//!
271//! if cfg!(unix) {
272//!     assert_eq!(
273//!         Path::new("foo/bar/baz"),
274//!         RelativePath::new("/bar/baz").to_path("foo")
275//!     );
276//! }
277//!
278//! assert_eq!(
279//!     Path::new("foo").relative_to("bar")?,
280//!     RelativePath::new("../foo"),
281//! );
282//! # Ok::<_, Box<dyn std::error::Error>>(())
283//! ```
284//!
285//! [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html
286//! [`normalize`]: https://docs.rs/relative-path/1/relative_path/struct.RelativePath.html#method.normalize
287//! [`Path`]: https://doc.rust-lang.org/std/path/struct.Path.html
288//! [`RelativePath`]: https://docs.rs/relative-path/1/relative_path/struct.RelativePath.html
289//! [`RelativePathBuf`]: https://docs.rs/relative-path/1/relative_path/struct.RelativePathBuf.html
290//! [`std::env::current_dir`]: https://doc.rust-lang.org/std/env/fn.current_dir.html
291//! [`std::path`]: https://doc.rust-lang.org/std/path/index.html
292//! [`to_logical_path`]: https://docs.rs/relative-path/1/relative_path/struct.RelativePath.html#method.to_logical_path
293//! [`to_path`]: https://docs.rs/relative-path/1/relative_path/struct.RelativePath.html#method.to_path
294//! [windows-reserved]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
295//! [windows-case]: https://learn.microsoft.com/en-us/windows/wsl/case-sensitivity
296//! [`relative-path-utils` crate]: https://docs.rs/relative-path-utils
297//! [Müsli]: https://docs.rs/musli/0.2
298
299// This file contains parts that are Copyright 2015 The Rust Project Developers, copied from:
300// https://github.com/rust-lang/rust
301// cb2a656cdfb6400ac0200c661267f91fabf237e2 src/libstd/path.rs
302
303#![deny(missing_docs)]
304#![no_std]
305#![cfg_attr(relative_path_docsrs, feature(doc_cfg))]
306
307#[cfg(feature = "alloc")]
308extern crate alloc;
309
310#[cfg(feature = "std")]
311extern crate std;
312
313#[cfg(all(feature = "alloc", feature = "std"))]
314mod path_ext;
315
316#[cfg(test)]
317mod tests;
318
319#[cfg(feature = "musli02")]
320mod musli02;
321
322#[cfg(all(feature = "alloc", feature = "std"))]
323#[cfg_attr(
324    relative_path_docsrs,
325    doc(cfg(all(feature = "alloc", feature = "std")))
326)]
327pub use path_ext::{PathExt, RelativeToError};
328
329#[cfg(feature = "alloc")]
330#[cfg_attr(relative_path_docsrs, doc(cfg(feature = "alloc")))]
331mod relative_path_buf;
332#[cfg(feature = "alloc")]
333#[doc(inline)]
334pub use self::relative_path_buf::RelativePathBuf;
335
336use core::cmp;
337use core::fmt;
338use core::hash::{Hash, Hasher};
339use core::mem;
340use core::str;
341
342#[cfg(feature = "alloc")]
343use alloc::borrow::{Cow, ToOwned};
344#[cfg(feature = "alloc")]
345use alloc::boxed::Box;
346#[cfg(feature = "alloc")]
347use alloc::rc::Rc;
348#[cfg(feature = "alloc")]
349use alloc::string::String;
350#[cfg(feature = "alloc")]
351use alloc::sync::Arc;
352
353#[cfg(feature = "std")]
354use std::error;
355#[cfg(feature = "std")]
356use std::path;
357
358const STEM_SEP: char = '.';
359const CURRENT_STR: &str = ".";
360const PARENT_STR: &str = "..";
361
362const SEP: char = '/';
363
364#[inline(always)]
365fn split_file_at_dot(input: &str) -> (Option<&str>, Option<&str>) {
366    if input == PARENT_STR {
367        return (Some(input), None);
368    }
369
370    let mut iter = input.rsplitn(2, STEM_SEP);
371
372    let after = iter.next();
373    let before = iter.next();
374
375    if before == Some("") {
376        (Some(input), None)
377    } else {
378        (before, after)
379    }
380}
381
382// Iterate through `iter` while it matches `prefix`; return `None` if `prefix`
383// is not a prefix of `iter`, otherwise return `Some(iter_after_prefix)` giving
384// `iter` after having exhausted `prefix`.
385#[inline(always)]
386fn iter_after<'a, 'b, I, J>(mut iter: I, mut prefix: J) -> Option<I>
387where
388    I: Iterator<Item = Component<'a>> + Clone,
389    J: Iterator<Item = Component<'b>>,
390{
391    loop {
392        let mut iter_next = iter.clone();
393        match (iter_next.next(), prefix.next()) {
394            (Some(x), Some(y)) if x == y => (),
395            (Some(_) | None, Some(_)) => return None,
396            (Some(_) | None, None) => return Some(iter),
397        }
398        iter = iter_next;
399    }
400}
401
402/// A single path component.
403///
404/// Accessed using the [`RelativePath::components`] iterator.
405///
406/// # Examples
407///
408/// ```
409/// use relative_path::{Component, RelativePath};
410///
411/// let path = RelativePath::new("foo/../bar/./baz");
412/// let mut it = path.components();
413///
414/// assert_eq!(Some(Component::Normal("foo")), it.next());
415/// assert_eq!(Some(Component::ParentDir), it.next());
416/// assert_eq!(Some(Component::Normal("bar")), it.next());
417/// assert_eq!(Some(Component::CurDir), it.next());
418/// assert_eq!(Some(Component::Normal("baz")), it.next());
419/// assert_eq!(None, it.next());
420/// ```
421#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
422pub enum Component<'a> {
423    /// The current directory `.`.
424    CurDir,
425    /// The parent directory `..`.
426    ParentDir,
427    /// A normal path component as a string.
428    Normal(&'a str),
429}
430
431impl<'a> Component<'a> {
432    /// Extracts the underlying [`str`] slice.
433    ///
434    /// [`str`]: prim@str
435    ///
436    /// # Examples
437    ///
438    /// ```
439    /// use relative_path::{RelativePath, Component};
440    ///
441    /// let path = RelativePath::new("./tmp/../foo/bar.txt");
442    /// let components: Vec<_> = path.components().map(Component::as_str).collect();
443    /// assert_eq!(&components, &[".", "tmp", "..", "foo", "bar.txt"]);
444    /// ```
445    #[must_use]
446    #[inline]
447    pub fn as_str(self) -> &'a str {
448        use self::Component::{CurDir, Normal, ParentDir};
449
450        match self {
451            CurDir => CURRENT_STR,
452            ParentDir => PARENT_STR,
453            Normal(name) => name,
454        }
455    }
456}
457
458/// [`AsRef<RelativePath>`] implementation for [`Component`].
459///
460/// # Examples
461///
462/// ```
463/// use relative_path::RelativePath;
464///
465/// let mut it = RelativePath::new("../foo/bar").components();
466///
467/// let a = it.next().ok_or("a")?;
468/// let b = it.next().ok_or("b")?;
469/// let c = it.next().ok_or("c")?;
470///
471/// let a: &RelativePath = a.as_ref();
472/// let b: &RelativePath = b.as_ref();
473/// let c: &RelativePath = c.as_ref();
474///
475/// assert_eq!(a, "..");
476/// assert_eq!(b, "foo");
477/// assert_eq!(c, "bar");
478///
479/// # Ok::<_, Box<dyn std::error::Error>>(())
480/// ```
481impl AsRef<RelativePath> for Component<'_> {
482    #[inline]
483    fn as_ref(&self) -> &RelativePath {
484        self.as_str().as_ref()
485    }
486}
487
488/// Iterator over all the components in a relative path.
489#[derive(Clone)]
490pub struct Components<'a> {
491    source: &'a str,
492}
493
494impl<'a> Iterator for Components<'a> {
495    type Item = Component<'a>;
496
497    fn next(&mut self) -> Option<Self::Item> {
498        self.source = self.source.trim_start_matches(SEP);
499
500        let slice = match self.source.find(SEP) {
501            Some(i) => {
502                let (slice, rest) = self.source.split_at(i);
503                self.source = rest.trim_start_matches(SEP);
504                slice
505            }
506            None => mem::take(&mut self.source),
507        };
508
509        match slice {
510            "" => None,
511            CURRENT_STR => Some(Component::CurDir),
512            PARENT_STR => Some(Component::ParentDir),
513            slice => Some(Component::Normal(slice)),
514        }
515    }
516}
517
518impl DoubleEndedIterator for Components<'_> {
519    fn next_back(&mut self) -> Option<Self::Item> {
520        self.source = self.source.trim_end_matches(SEP);
521
522        let slice = match self.source.rfind(SEP) {
523            Some(i) => {
524                let (rest, slice) = self.source.split_at(i + 1);
525                self.source = rest.trim_end_matches(SEP);
526                slice
527            }
528            None => mem::take(&mut self.source),
529        };
530
531        match slice {
532            "" => None,
533            CURRENT_STR => Some(Component::CurDir),
534            PARENT_STR => Some(Component::ParentDir),
535            slice => Some(Component::Normal(slice)),
536        }
537    }
538}
539
540impl<'a> Components<'a> {
541    /// Construct a new component from the given string.
542    #[inline]
543    fn new(source: &'a str) -> Components<'a> {
544        Self { source }
545    }
546
547    /// Extracts a slice corresponding to the portion of the path remaining for iteration.
548    ///
549    /// # Examples
550    ///
551    /// ```
552    /// use relative_path::RelativePath;
553    ///
554    /// let mut components = RelativePath::new("tmp/foo/bar.txt").components();
555    /// components.next();
556    /// components.next();
557    ///
558    /// assert_eq!("bar.txt", components.as_relative_path());
559    /// ```
560    #[must_use]
561    #[inline]
562    pub fn as_relative_path(&self) -> &'a RelativePath {
563        RelativePath::new(self.source)
564    }
565}
566
567impl<'a> cmp::PartialEq for Components<'a> {
568    #[inline]
569    fn eq(&self, other: &Components<'a>) -> bool {
570        Iterator::eq(self.clone(), other.clone())
571    }
572}
573
574/// An iterator over the [`Component`]s of a [`RelativePath`], as [`str`]
575/// slices.
576///
577/// This `struct` is created by the [`iter`][RelativePath::iter] method.
578///
579/// [`str`]: prim@str
580#[derive(Clone)]
581pub struct Iter<'a> {
582    inner: Components<'a>,
583}
584
585impl<'a> Iterator for Iter<'a> {
586    type Item = &'a str;
587
588    #[inline]
589    fn next(&mut self) -> Option<&'a str> {
590        self.inner.next().map(Component::as_str)
591    }
592}
593
594impl<'a> DoubleEndedIterator for Iter<'a> {
595    #[inline]
596    fn next_back(&mut self) -> Option<&'a str> {
597        self.inner.next_back().map(Component::as_str)
598    }
599}
600
601/// Error kind for [`FromPathError`].
602#[cfg(feature = "std")]
603#[cfg_attr(relative_path_docsrs, doc(cfg(feature = "std")))]
604#[derive(Debug, Clone, Copy, PartialEq, Eq)]
605#[non_exhaustive]
606pub enum FromPathErrorKind {
607    /// Non-relative component in path.
608    NonRelative,
609    /// Non-utf8 component in path.
610    NonUtf8,
611    /// Trying to convert a platform-specific path which uses a platform-specific separator.
612    BadSeparator,
613}
614
615/// An error raised when attempting to convert a path using
616/// [`RelativePathBuf::from_path`].
617#[cfg(feature = "std")]
618#[cfg_attr(relative_path_docsrs, doc(cfg(feature = "std")))]
619#[derive(Debug, Clone, PartialEq, Eq)]
620pub struct FromPathError {
621    kind: FromPathErrorKind,
622}
623
624#[cfg(feature = "std")]
625#[cfg_attr(relative_path_docsrs, doc(cfg(feature = "std")))]
626impl FromPathError {
627    /// Gets the underlying [`FromPathErrorKind`] that provides more details on
628    /// what went wrong.
629    ///
630    /// # Examples
631    ///
632    /// ```
633    /// use std::path::Path;
634    /// use relative_path::{FromPathErrorKind, RelativePathBuf};
635    ///
636    /// let result = RelativePathBuf::from_path(Path::new("/hello/world"));
637    /// let e = result.unwrap_err();
638    ///
639    /// assert_eq!(FromPathErrorKind::NonRelative, e.kind());
640    /// ```
641    #[must_use]
642    #[inline]
643    pub fn kind(&self) -> FromPathErrorKind {
644        self.kind
645    }
646}
647
648#[cfg(feature = "std")]
649#[cfg_attr(relative_path_docsrs, doc(cfg(feature = "std")))]
650impl From<FromPathErrorKind> for FromPathError {
651    #[inline]
652    fn from(value: FromPathErrorKind) -> Self {
653        Self { kind: value }
654    }
655}
656
657#[cfg(feature = "std")]
658#[cfg_attr(relative_path_docsrs, doc(cfg(feature = "std")))]
659impl fmt::Display for FromPathError {
660    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
661        match self.kind {
662            FromPathErrorKind::NonRelative => "path contains non-relative component".fmt(fmt),
663            FromPathErrorKind::NonUtf8 => "path contains non-utf8 component".fmt(fmt),
664            FromPathErrorKind::BadSeparator => {
665                "path contains platform-specific path separator".fmt(fmt)
666            }
667        }
668    }
669}
670
671#[cfg(feature = "std")]
672#[cfg_attr(relative_path_docsrs, doc(cfg(feature = "std")))]
673impl error::Error for FromPathError {}
674
675/// A borrowed, immutable relative path.
676#[repr(transparent)]
677pub struct RelativePath {
678    inner: str,
679}
680
681/// An error returned from [`strip_prefix`] if the prefix was not found.
682///
683/// [`strip_prefix`]: RelativePath::strip_prefix
684#[derive(Debug, Clone, PartialEq, Eq)]
685pub struct StripPrefixError(());
686
687impl RelativePath {
688    /// Directly wraps a string slice as a `RelativePath` slice.
689    #[inline]
690    pub fn new<S>(s: &S) -> &RelativePath
691    where
692        S: AsRef<str> + ?Sized,
693    {
694        unsafe { &*(s.as_ref() as *const str as *const RelativePath) }
695    }
696
697    /// Try to convert a [`Path`] to a [`RelativePath`] without allocating a buffer.
698    ///
699    /// [`Path`]: std::path::Path
700    ///
701    /// # Errors
702    ///
703    /// This requires the path to be a legal, platform-neutral relative path.
704    /// Otherwise various forms of [`FromPathError`] will be returned as an
705    /// [`Err`].
706    ///
707    /// # Examples
708    ///
709    /// ```
710    /// use relative_path::{RelativePath, FromPathErrorKind};
711    ///
712    /// assert_eq!(
713    ///     Ok(RelativePath::new("foo/bar")),
714    ///     RelativePath::from_path("foo/bar")
715    /// );
716    ///
717    /// // Note: absolute paths are different depending on platform.
718    /// if cfg!(windows) {
719    ///     let e = RelativePath::from_path("c:\\foo\\bar").unwrap_err();
720    ///     assert_eq!(FromPathErrorKind::NonRelative, e.kind());
721    /// }
722    ///
723    /// if cfg!(unix) {
724    ///     let e = RelativePath::from_path("/foo/bar").unwrap_err();
725    ///     assert_eq!(FromPathErrorKind::NonRelative, e.kind());
726    /// }
727    /// ```
728    #[cfg(feature = "std")]
729    #[cfg_attr(relative_path_docsrs, doc(cfg(feature = "std")))]
730    pub fn from_path<P>(path: &P) -> Result<&RelativePath, FromPathError>
731    where
732        P: ?Sized + AsRef<path::Path>,
733    {
734        use std::path::Component::{CurDir, Normal, ParentDir, Prefix, RootDir};
735
736        let other = path.as_ref();
737
738        let s = match other.to_str() {
739            Some(s) => s,
740            None => return Err(FromPathErrorKind::NonUtf8.into()),
741        };
742
743        let rel = RelativePath::new(s);
744
745        // check that the component compositions are equal.
746        for (a, b) in other.components().zip(rel.components()) {
747            match (a, b) {
748                (Prefix(_) | RootDir, _) => return Err(FromPathErrorKind::NonRelative.into()),
749                (CurDir, Component::CurDir) | (ParentDir, Component::ParentDir) => continue,
750                (Normal(a), Component::Normal(b)) if a == b => continue,
751                _ => return Err(FromPathErrorKind::BadSeparator.into()),
752            }
753        }
754
755        Ok(rel)
756    }
757
758    /// Yields the underlying [`str`] slice.
759    ///
760    /// [`str`]: prim@str
761    ///
762    /// # Examples
763    ///
764    /// ```
765    /// use relative_path::RelativePath;
766    ///
767    /// assert_eq!(RelativePath::new("foo.txt").as_str(), "foo.txt");
768    /// ```
769    #[must_use]
770    #[inline]
771    pub fn as_str(&self) -> &str {
772        &self.inner
773    }
774
775    /// Returns an object that implements [`Display`][core::fmt::Display].
776    ///
777    /// # Examples
778    ///
779    /// ```
780    /// use relative_path::RelativePath;
781    ///
782    /// let path = RelativePath::new("tmp/foo.rs");
783    ///
784    /// println!("{}", path.display());
785    /// ```
786    #[deprecated(note = "RelativePath implements std::fmt::Display directly")]
787    #[must_use]
788    #[inline]
789    #[allow(deprecated)]
790    pub fn display(&self) -> Display<'_> {
791        Display { path: self }
792    }
793
794    /// Creates an owned [`RelativePathBuf`] with path adjoined to self.
795    ///
796    /// # Examples
797    ///
798    /// ```
799    /// use relative_path::RelativePath;
800    ///
801    /// let path = RelativePath::new("foo/bar");
802    /// assert_eq!("foo/bar/baz", path.join("baz"));
803    /// ```
804    #[cfg(feature = "alloc")]
805    #[cfg_attr(relative_path_docsrs, doc(cfg(feature = "alloc")))]
806    #[inline]
807    pub fn join<P>(&self, path: P) -> RelativePathBuf
808    where
809        P: AsRef<RelativePath>,
810    {
811        let mut out = self.to_relative_path_buf();
812        out.push(path);
813        out
814    }
815
816    /// Iterate over all components in this relative path.
817    ///
818    /// # Examples
819    ///
820    /// ```
821    /// use relative_path::{Component, RelativePath};
822    ///
823    /// let path = RelativePath::new("foo/bar/baz");
824    /// let mut it = path.components();
825    ///
826    /// assert_eq!(Some(Component::Normal("foo")), it.next());
827    /// assert_eq!(Some(Component::Normal("bar")), it.next());
828    /// assert_eq!(Some(Component::Normal("baz")), it.next());
829    /// assert_eq!(None, it.next());
830    /// ```
831    #[must_use]
832    #[inline]
833    pub fn components(&self) -> Components<'_> {
834        Components::new(&self.inner)
835    }
836
837    /// Produces an iterator over the path's components viewed as [`str`]
838    /// slices.
839    ///
840    /// For more information about the particulars of how the path is separated
841    /// into components, see [`components`][Self::components].
842    ///
843    /// [`str`]: prim@str
844    ///
845    /// # Examples
846    ///
847    /// ```
848    /// use relative_path::RelativePath;
849    ///
850    /// let mut it = RelativePath::new("/tmp/foo.txt").iter();
851    /// assert_eq!(it.next(), Some("tmp"));
852    /// assert_eq!(it.next(), Some("foo.txt"));
853    /// assert_eq!(it.next(), None)
854    /// ```
855    #[must_use]
856    #[inline]
857    pub fn iter(&self) -> Iter<'_> {
858        Iter {
859            inner: self.components(),
860        }
861    }
862
863    /// Convert to an owned [`RelativePathBuf`].
864    #[cfg(feature = "alloc")]
865    #[must_use]
866    #[inline]
867    pub fn to_relative_path_buf(&self) -> RelativePathBuf {
868        RelativePathBuf::from(self.inner.to_owned())
869    }
870
871    /// Build an owned [`PathBuf`] relative to `base` for the current relative
872    /// path.
873    ///
874    /// # Examples
875    ///
876    /// ```
877    /// use relative_path::RelativePath;
878    /// use std::path::Path;
879    ///
880    /// let path = RelativePath::new("foo/bar").to_path(".");
881    /// assert_eq!(Path::new("./foo/bar"), path);
882    ///
883    /// let path = RelativePath::new("foo/bar").to_path("");
884    /// assert_eq!(Path::new("foo/bar"), path);
885    /// ```
886    ///
887    /// # Encoding an absolute path
888    ///
889    /// Absolute paths are, in contrast to when using [`PathBuf::push`] *ignored*
890    /// and will be added unchanged to the buffer.
891    ///
892    /// This is to preserve the probability of a path conversion failing if the
893    /// relative path contains platform-specific absolute path components.
894    ///
895    /// ```
896    /// use relative_path::RelativePath;
897    /// use std::path::Path;
898    ///
899    /// if cfg!(windows) {
900    ///     let path = RelativePath::new("/bar/baz").to_path("foo");
901    ///     assert_eq!(Path::new("foo\\bar\\baz"), path);
902    ///
903    ///     let path = RelativePath::new("c:\\bar\\baz").to_path("foo");
904    ///     assert_eq!(Path::new("foo\\c:\\bar\\baz"), path);
905    /// }
906    ///
907    /// if cfg!(unix) {
908    ///     let path = RelativePath::new("/bar/baz").to_path("foo");
909    ///     assert_eq!(Path::new("foo/bar/baz"), path);
910    ///
911    ///     let path = RelativePath::new("c:\\bar\\baz").to_path("foo");
912    ///     assert_eq!(Path::new("foo/c:\\bar\\baz"), path);
913    /// }
914    /// ```
915    ///
916    /// [`PathBuf`]: std::path::PathBuf
917    /// [`PathBuf::push`]: std::path::PathBuf::push
918    #[cfg(feature = "std")]
919    #[cfg_attr(relative_path_docsrs, doc(cfg(feature = "std")))]
920    #[must_use]
921    pub fn to_path<P>(&self, base: P) -> path::PathBuf
922    where
923        P: AsRef<path::Path>,
924    {
925        let mut p = base.as_ref().to_path_buf().into_os_string();
926
927        for c in self.components() {
928            if !p.is_empty() {
929                p.push(path::MAIN_SEPARATOR.encode_utf8(&mut [0u8, 0u8, 0u8, 0u8]));
930            }
931
932            p.push(c.as_str());
933        }
934
935        path::PathBuf::from(p)
936    }
937
938    /// Build an owned [`PathBuf`] relative to `base` for the current relative
939    /// path.
940    ///
941    /// This is similar to [`to_path`] except that it doesn't just
942    /// unconditionally append one path to the other, instead it performs the
943    /// following operations depending on its own components:
944    ///
945    /// * [`Component::CurDir`] leaves the `base` unmodified.
946    /// * [`Component::ParentDir`] removes a component from `base` using
947    ///   [`path::PathBuf::pop`].
948    /// * [`Component::Normal`] pushes the given path component onto `base`
949    ///   using the same mechanism as [`to_path`].
950    ///
951    /// [`to_path`]: RelativePath::to_path
952    ///
953    /// Note that the exact semantics of the path operation is determined by the
954    /// corresponding [`PathBuf`] operation. E.g. popping a component off a path
955    /// like `.` will result in an empty path.
956    ///
957    /// ```
958    /// use relative_path::RelativePath;
959    /// use std::path::Path;
960    ///
961    /// let path = RelativePath::new("..").to_logical_path(".");
962    /// assert_eq!(path, Path::new(""));
963    /// ```
964    ///
965    /// # Examples
966    ///
967    /// ```
968    /// use relative_path::RelativePath;
969    /// use std::path::Path;
970    ///
971    /// let path = RelativePath::new("..").to_logical_path("foo/bar");
972    /// assert_eq!(path, Path::new("foo"));
973    /// ```
974    ///
975    /// # Encoding an absolute path
976    ///
977    /// Behaves the same as [`to_path`][RelativePath::to_path] when encoding
978    /// absolute paths.
979    ///
980    /// Absolute paths are, in contrast to when using [`PathBuf::push`] *ignored*
981    /// and will be added unchanged to the buffer.
982    ///
983    /// This is to preserve the probability of a path conversion failing if the
984    /// relative path contains platform-specific absolute path components.
985    ///
986    /// ```
987    /// use relative_path::RelativePath;
988    /// use std::path::Path;
989    ///
990    /// if cfg!(windows) {
991    ///     let path = RelativePath::new("/bar/baz").to_logical_path("foo");
992    ///     assert_eq!(Path::new("foo\\bar\\baz"), path);
993    ///
994    ///     let path = RelativePath::new("c:\\bar\\baz").to_logical_path("foo");
995    ///     assert_eq!(Path::new("foo\\c:\\bar\\baz"), path);
996    ///
997    ///     let path = RelativePath::new("foo/bar").to_logical_path("");
998    ///     assert_eq!(Path::new("foo\\bar"), path);
999    /// }
1000    ///
1001    /// if cfg!(unix) {
1002    ///     let path = RelativePath::new("/bar/baz").to_logical_path("foo");
1003    ///     assert_eq!(Path::new("foo/bar/baz"), path);
1004    ///
1005    ///     let path = RelativePath::new("c:\\bar\\baz").to_logical_path("foo");
1006    ///     assert_eq!(Path::new("foo/c:\\bar\\baz"), path);
1007    ///
1008    ///     let path = RelativePath::new("foo/bar").to_logical_path("");
1009    ///     assert_eq!(Path::new("foo/bar"), path);
1010    /// }
1011    /// ```
1012    ///
1013    /// [`PathBuf`]: std::path::PathBuf
1014    /// [`PathBuf::push`]: std::path::PathBuf::push
1015    #[cfg(feature = "std")]
1016    #[cfg_attr(relative_path_docsrs, doc(cfg(feature = "std")))]
1017    #[must_use]
1018    pub fn to_logical_path<P>(&self, base: P) -> path::PathBuf
1019    where
1020        P: AsRef<path::Path>,
1021    {
1022        use self::Component::{CurDir, Normal, ParentDir};
1023
1024        let mut p = base.as_ref().to_path_buf().into_os_string();
1025
1026        for c in self.components() {
1027            match c {
1028                CurDir => continue,
1029                ParentDir => {
1030                    let mut temp = path::PathBuf::from(std::mem::take(&mut p));
1031                    temp.pop();
1032                    p = temp.into_os_string();
1033                }
1034                Normal(c) => {
1035                    if !p.is_empty() {
1036                        p.push(path::MAIN_SEPARATOR.encode_utf8(&mut [0u8, 0u8, 0u8, 0u8]));
1037                    }
1038
1039                    p.push(c);
1040                }
1041            }
1042        }
1043
1044        path::PathBuf::from(p)
1045    }
1046
1047    /// Returns a relative path, without its final [`Component`] if there is one.
1048    ///
1049    /// # Examples
1050    ///
1051    /// ```
1052    /// use relative_path::RelativePath;
1053    ///
1054    /// assert_eq!(Some(RelativePath::new("foo")), RelativePath::new("foo/bar").parent());
1055    /// assert_eq!(Some(RelativePath::new("")), RelativePath::new("foo").parent());
1056    /// assert_eq!(None, RelativePath::new("").parent());
1057    /// ```
1058    #[must_use]
1059    pub fn parent(&self) -> Option<&RelativePath> {
1060        use self::Component::CurDir;
1061
1062        if self.inner.is_empty() {
1063            return None;
1064        }
1065
1066        let mut it = self.components();
1067        while let Some(CurDir) = it.next_back() {}
1068        Some(it.as_relative_path())
1069    }
1070
1071    /// Returns the final component of the `RelativePath`, if there is one.
1072    ///
1073    /// If the path is a normal file, this is the file name. If it's the path of
1074    /// a directory, this is the directory name.
1075    ///
1076    /// Returns [`None`] If the path terminates in `..`.
1077    ///
1078    /// # Examples
1079    ///
1080    /// ```
1081    /// use relative_path::RelativePath;
1082    ///
1083    /// assert_eq!(Some("bin"), RelativePath::new("usr/bin/").file_name());
1084    /// assert_eq!(Some("foo.txt"), RelativePath::new("tmp/foo.txt").file_name());
1085    /// assert_eq!(Some("foo.txt"), RelativePath::new("tmp/foo.txt/").file_name());
1086    /// assert_eq!(Some("foo.txt"), RelativePath::new("foo.txt/.").file_name());
1087    /// assert_eq!(Some("foo.txt"), RelativePath::new("foo.txt/.//").file_name());
1088    /// assert_eq!(None, RelativePath::new("foo.txt/..").file_name());
1089    /// assert_eq!(None, RelativePath::new("/").file_name());
1090    /// ```
1091    #[must_use]
1092    pub fn file_name(&self) -> Option<&str> {
1093        use self::Component::{CurDir, Normal, ParentDir};
1094
1095        let mut it = self.components();
1096
1097        while let Some(c) = it.next_back() {
1098            return match c {
1099                CurDir => continue,
1100                Normal(name) => Some(name),
1101                ParentDir => None,
1102            };
1103        }
1104
1105        None
1106    }
1107
1108    /// Returns a relative path that, when joined onto `base`, yields `self`.
1109    ///
1110    /// # Errors
1111    ///
1112    /// If `base` is not a prefix of `self` (i.e. [`starts_with`] returns
1113    /// `false`), returns [`Err`].
1114    ///
1115    /// [`starts_with`]: Self::starts_with
1116    ///
1117    /// # Examples
1118    ///
1119    /// ```
1120    /// use relative_path::RelativePath;
1121    ///
1122    /// let path = RelativePath::new("test/haha/foo.txt");
1123    ///
1124    /// assert_eq!(path.strip_prefix("test"), Ok(RelativePath::new("haha/foo.txt")));
1125    /// assert_eq!(path.strip_prefix("test").is_ok(), true);
1126    /// assert_eq!(path.strip_prefix("haha").is_ok(), false);
1127    /// ```
1128    pub fn strip_prefix<P>(&self, base: P) -> Result<&RelativePath, StripPrefixError>
1129    where
1130        P: AsRef<RelativePath>,
1131    {
1132        iter_after(self.components(), base.as_ref().components())
1133            .map(|c| c.as_relative_path())
1134            .ok_or(StripPrefixError(()))
1135    }
1136
1137    /// Determines whether `base` is a prefix of `self`.
1138    ///
1139    /// Only considers whole path components to match.
1140    ///
1141    /// # Examples
1142    ///
1143    /// ```
1144    /// use relative_path::RelativePath;
1145    ///
1146    /// let path = RelativePath::new("etc/passwd");
1147    ///
1148    /// assert!(path.starts_with("etc"));
1149    ///
1150    /// assert!(!path.starts_with("e"));
1151    /// ```
1152    #[must_use]
1153    pub fn starts_with<P>(&self, base: P) -> bool
1154    where
1155        P: AsRef<RelativePath>,
1156    {
1157        iter_after(self.components(), base.as_ref().components()).is_some()
1158    }
1159
1160    /// Determines whether `child` is a suffix of `self`.
1161    ///
1162    /// Only considers whole path components to match.
1163    ///
1164    /// # Examples
1165    ///
1166    /// ```
1167    /// use relative_path::RelativePath;
1168    ///
1169    /// let path = RelativePath::new("etc/passwd");
1170    ///
1171    /// assert!(path.ends_with("passwd"));
1172    /// ```
1173    #[must_use]
1174    pub fn ends_with<P>(&self, child: P) -> bool
1175    where
1176        P: AsRef<RelativePath>,
1177    {
1178        iter_after(self.components().rev(), child.as_ref().components().rev()).is_some()
1179    }
1180
1181    /// Determines whether `self` is normalized.
1182    ///
1183    /// # Examples
1184    ///
1185    /// ```
1186    /// use relative_path::RelativePath;
1187    ///
1188    /// // These are normalized.
1189    /// assert!(RelativePath::new("").is_normalized());
1190    /// assert!(RelativePath::new("baz.txt").is_normalized());
1191    /// assert!(RelativePath::new("foo/bar/baz.txt").is_normalized());
1192    /// assert!(RelativePath::new("..").is_normalized());
1193    /// assert!(RelativePath::new("../..").is_normalized());
1194    /// assert!(RelativePath::new("../../foo/bar/baz.txt").is_normalized());
1195    ///
1196    /// // These are not normalized.
1197    /// assert!(!RelativePath::new(".").is_normalized());
1198    /// assert!(!RelativePath::new("./baz.txt").is_normalized());
1199    /// assert!(!RelativePath::new("foo/..").is_normalized());
1200    /// assert!(!RelativePath::new("foo/../baz.txt").is_normalized());
1201    /// assert!(!RelativePath::new("foo/.").is_normalized());
1202    /// assert!(!RelativePath::new("foo/./baz.txt").is_normalized());
1203    /// assert!(!RelativePath::new("../foo/./bar/../baz.txt").is_normalized());
1204    /// ```
1205    #[must_use]
1206    pub fn is_normalized(&self) -> bool {
1207        self.components()
1208            .skip_while(|c| matches!(c, Component::ParentDir))
1209            .all(|c| matches!(c, Component::Normal(_)))
1210    }
1211
1212    /// Creates an owned [`RelativePathBuf`] like `self` but with the given file
1213    /// name.
1214    ///
1215    /// See [`set_file_name`] for more details.
1216    ///
1217    /// [`set_file_name`]: RelativePathBuf::set_file_name
1218    ///
1219    /// # Examples
1220    ///
1221    /// ```
1222    /// use relative_path::{RelativePath, RelativePathBuf};
1223    ///
1224    /// let path = RelativePath::new("tmp/foo.txt");
1225    /// assert_eq!(path.with_file_name("bar.txt"), RelativePathBuf::from("tmp/bar.txt"));
1226    ///
1227    /// let path = RelativePath::new("tmp");
1228    /// assert_eq!(path.with_file_name("var"), RelativePathBuf::from("var"));
1229    /// ```
1230    #[cfg(feature = "alloc")]
1231    #[cfg_attr(relative_path_docsrs, doc(cfg(feature = "alloc")))]
1232    #[must_use]
1233    pub fn with_file_name<S>(&self, file_name: S) -> RelativePathBuf
1234    where
1235        S: AsRef<str>,
1236    {
1237        let mut buf = self.to_relative_path_buf();
1238        buf.set_file_name(file_name);
1239        buf
1240    }
1241
1242    /// Extracts the stem (non-extension) portion of [`file_name`][Self::file_name].
1243    ///
1244    /// The stem is:
1245    ///
1246    /// * [`None`], if there is no file name;
1247    /// * The entire file name if there is no embedded `.`;
1248    /// * The entire file name if the file name begins with `.` and has no other `.`s within;
1249    /// * Otherwise, the portion of the file name before the final `.`
1250    ///
1251    /// # Examples
1252    ///
1253    /// ```
1254    /// use relative_path::RelativePath;
1255    ///
1256    /// let path = RelativePath::new("foo.rs");
1257    ///
1258    /// assert_eq!("foo", path.file_stem().unwrap());
1259    /// ```
1260    #[must_use]
1261    pub fn file_stem(&self) -> Option<&str> {
1262        self.file_name()
1263            .map(split_file_at_dot)
1264            .and_then(|(before, after)| before.or(after))
1265    }
1266
1267    /// Extracts the extension of [`file_name`][Self::file_name], if possible.
1268    ///
1269    /// The extension is:
1270    ///
1271    /// * [`None`], if there is no file name;
1272    /// * [`None`], if there is no embedded `.`;
1273    /// * [`None`], if the file name begins with `.` and has no other `.`s within;
1274    /// * Otherwise, the portion of the file name after the final `.`
1275    ///
1276    /// # Examples
1277    ///
1278    /// ```
1279    /// use relative_path::RelativePath;
1280    ///
1281    /// assert_eq!(Some("rs"), RelativePath::new("foo.rs").extension());
1282    /// assert_eq!(None, RelativePath::new(".rs").extension());
1283    /// assert_eq!(Some("rs"), RelativePath::new("foo.rs/.").extension());
1284    /// ```
1285    #[must_use]
1286    pub fn extension(&self) -> Option<&str> {
1287        self.file_name()
1288            .map(split_file_at_dot)
1289            .and_then(|(before, after)| before.and(after))
1290    }
1291
1292    /// Creates an owned [`RelativePathBuf`] like `self` but with the given
1293    /// extension.
1294    ///
1295    /// See [`set_extension`] for more details.
1296    ///
1297    /// [`set_extension`]: RelativePathBuf::set_extension
1298    ///
1299    /// # Examples
1300    ///
1301    /// ```
1302    /// use relative_path::{RelativePath, RelativePathBuf};
1303    ///
1304    /// let path = RelativePath::new("foo.rs");
1305    /// assert_eq!(path.with_extension("txt"), RelativePathBuf::from("foo.txt"));
1306    /// ```
1307    #[cfg(feature = "alloc")]
1308    #[cfg_attr(relative_path_docsrs, doc(cfg(feature = "alloc")))]
1309    #[must_use]
1310    pub fn with_extension<S>(&self, extension: S) -> RelativePathBuf
1311    where
1312        S: AsRef<str>,
1313    {
1314        let mut buf = self.to_relative_path_buf();
1315        buf.set_extension(extension);
1316        buf
1317    }
1318
1319    /// Build an owned [`RelativePathBuf`], joined with the given path and
1320    /// normalized.
1321    ///
1322    /// # Examples
1323    ///
1324    /// ```
1325    /// use relative_path::RelativePath;
1326    ///
1327    /// assert_eq!(
1328    ///     RelativePath::new("foo/baz.txt"),
1329    ///     RelativePath::new("foo/bar").join_normalized("../baz.txt").as_relative_path()
1330    /// );
1331    ///
1332    /// assert_eq!(
1333    ///     RelativePath::new("../foo/baz.txt"),
1334    ///     RelativePath::new("../foo/bar").join_normalized("../baz.txt").as_relative_path()
1335    /// );
1336    /// ```
1337    #[cfg(feature = "alloc")]
1338    #[cfg_attr(relative_path_docsrs, doc(cfg(feature = "alloc")))]
1339    #[must_use]
1340    pub fn join_normalized<P>(&self, path: P) -> RelativePathBuf
1341    where
1342        P: AsRef<RelativePath>,
1343    {
1344        let mut buf = RelativePathBuf::new();
1345        self::relative_path_buf::relative_traversal(&mut buf, self.components());
1346        self::relative_path_buf::relative_traversal(&mut buf, path.as_ref().components());
1347        buf
1348    }
1349
1350    /// Return an owned [`RelativePathBuf`], with all non-normal components
1351    /// moved to the beginning of the path.
1352    ///
1353    /// This permits for a normalized representation of different relative
1354    /// components.
1355    ///
1356    /// Normalization is a _destructive_ operation if the path references an
1357    /// actual filesystem path. An example of this is symlinks under unix, a
1358    /// path like `foo/../bar` might reference a different location other than
1359    /// `./bar`.
1360    ///
1361    /// Normalization is a logical operation and does not guarantee that the
1362    /// constructed path corresponds to what the filesystem would do. On Linux
1363    /// for example symbolic links could mean that the logical path doesn't
1364    /// correspond to the filesystem path.
1365    ///
1366    /// # Examples
1367    ///
1368    /// ```
1369    /// use relative_path::RelativePath;
1370    ///
1371    /// assert_eq!(
1372    ///     "../foo/baz.txt",
1373    ///     RelativePath::new("../foo/./bar/../baz.txt").normalize()
1374    /// );
1375    ///
1376    /// assert_eq!(
1377    ///     "",
1378    ///     RelativePath::new(".").normalize()
1379    /// );
1380    /// ```
1381    #[cfg(feature = "alloc")]
1382    #[cfg_attr(relative_path_docsrs, doc(cfg(feature = "alloc")))]
1383    #[must_use]
1384    pub fn normalize(&self) -> RelativePathBuf {
1385        let mut buf = RelativePathBuf::with_capacity(self.inner.len());
1386        self::relative_path_buf::relative_traversal(&mut buf, self.components());
1387        buf
1388    }
1389
1390    /// Constructs a relative path from the current path, to `path`.
1391    ///
1392    /// This function will return the empty [`RelativePath`] `""` if this source
1393    /// contains unnamed components like `..` that would have to be traversed to
1394    /// reach the destination `path`. This is necessary since we have no way of
1395    /// knowing what the names of those components are when we're building the
1396    /// new relative path.
1397    ///
1398    /// ```
1399    /// use relative_path::RelativePath;
1400    ///
1401    /// // Here we don't know what directories `../..` refers to, so there's no
1402    /// // way to construct a path back to `bar` in the current directory from
1403    /// // `../..`.
1404    /// let from = RelativePath::new("../../foo/relative-path");
1405    /// let to = RelativePath::new("bar");
1406    /// assert_eq!("", from.relative(to));
1407    /// ```
1408    ///
1409    /// One exception to this is when two paths contains a common prefix at
1410    /// which point there's no need to know what the names of those unnamed
1411    /// components are.
1412    ///
1413    /// ```
1414    /// use relative_path::RelativePath;
1415    ///
1416    /// let from = RelativePath::new("../../foo/bar");
1417    /// let to = RelativePath::new("../../foo/baz");
1418    ///
1419    /// assert_eq!("../baz", from.relative(to));
1420    ///
1421    /// let from = RelativePath::new("../a/../../foo/bar");
1422    /// let to = RelativePath::new("../../foo/baz");
1423    ///
1424    /// assert_eq!("../baz", from.relative(to));
1425    /// ```
1426    ///
1427    /// # Examples
1428    ///
1429    /// ```
1430    /// use relative_path::RelativePath;
1431    ///
1432    /// assert_eq!(
1433    ///     "../../e/f",
1434    ///     RelativePath::new("a/b/c/d").relative(RelativePath::new("a/b/e/f"))
1435    /// );
1436    ///
1437    /// assert_eq!(
1438    ///     "../bbb",
1439    ///     RelativePath::new("a/../aaa").relative(RelativePath::new("b/../bbb"))
1440    /// );
1441    ///
1442    /// let a = RelativePath::new("git/relative-path");
1443    /// let b = RelativePath::new("git");
1444    /// assert_eq!("relative-path", b.relative(a));
1445    /// assert_eq!("..", a.relative(b));
1446    ///
1447    /// let a = RelativePath::new("foo/bar/bap/foo.h");
1448    /// let b = RelativePath::new("../arch/foo.h");
1449    /// assert_eq!("../../../../../arch/foo.h", a.relative(b));
1450    /// assert_eq!("", b.relative(a));
1451    /// ```
1452    #[cfg(feature = "alloc")]
1453    #[cfg_attr(relative_path_docsrs, doc(cfg(feature = "alloc")))]
1454    #[must_use]
1455    pub fn relative<P>(&self, path: P) -> RelativePathBuf
1456    where
1457        P: AsRef<RelativePath>,
1458    {
1459        let mut from = RelativePathBuf::with_capacity(self.inner.len());
1460        let mut to = RelativePathBuf::with_capacity(path.as_ref().inner.len());
1461
1462        self::relative_path_buf::relative_traversal(&mut from, self.components());
1463        self::relative_path_buf::relative_traversal(&mut to, path.as_ref().components());
1464
1465        let mut it_from = from.components();
1466        let mut it_to = to.components();
1467
1468        // Strip a common prefixes - if any.
1469        let (lead_from, lead_to) = loop {
1470            match (it_from.next(), it_to.next()) {
1471                (Some(f), Some(t)) if f == t => continue,
1472                (f, t) => {
1473                    break (f, t);
1474                }
1475            }
1476        };
1477
1478        // Special case: The path we are traversing from can't contain unnamed
1479        // components. A relative path might be any path, like `/`, or
1480        // `/foo/bar/baz`, and these components cannot be named in the relative
1481        // traversal.
1482        //
1483        // Also note that `relative_traversal` guarantees that all ParentDir
1484        // components are at the head of the path being built.
1485        if lead_from == Some(Component::ParentDir) {
1486            return RelativePathBuf::new();
1487        }
1488
1489        let head = lead_from.into_iter().chain(it_from);
1490        let tail = lead_to.into_iter().chain(it_to);
1491
1492        let mut buf = RelativePathBuf::with_capacity(usize::max(from.len(), to.len()));
1493
1494        for c in head.map(|_| Component::ParentDir).chain(tail) {
1495            buf.push(c.as_str());
1496        }
1497
1498        buf
1499    }
1500
1501    /// Check if path starts with a path separator.
1502    #[inline]
1503    #[cfg(feature = "alloc")]
1504    fn starts_with_sep(&self) -> bool {
1505        self.inner.starts_with(SEP)
1506    }
1507
1508    /// Check if path ends with a path separator.
1509    #[inline]
1510    #[cfg(feature = "alloc")]
1511    fn ends_with_sep(&self) -> bool {
1512        self.inner.ends_with(SEP)
1513    }
1514}
1515
1516impl<'a> IntoIterator for &'a RelativePath {
1517    type IntoIter = Iter<'a>;
1518    type Item = &'a str;
1519
1520    #[inline]
1521    fn into_iter(self) -> Self::IntoIter {
1522        self.iter()
1523    }
1524}
1525
1526/// Conversion from a [`Box<str>`] reference to a [`Box<RelativePath>`].
1527///
1528/// # Examples
1529///
1530/// ```
1531/// use relative_path::RelativePath;
1532///
1533/// let path: Box<RelativePath> = Box::<str>::from("foo/bar").into();
1534/// assert_eq!(&*path, "foo/bar");
1535/// ```
1536#[cfg(feature = "alloc")]
1537impl From<Box<str>> for Box<RelativePath> {
1538    #[inline]
1539    fn from(boxed: Box<str>) -> Box<RelativePath> {
1540        let rw = Box::into_raw(boxed) as *mut RelativePath;
1541        unsafe { Box::from_raw(rw) }
1542    }
1543}
1544
1545/// Conversion from a [`str`] reference to a [`Box<RelativePath>`].
1546///
1547/// [`str`]: prim@str
1548///
1549/// # Examples
1550///
1551/// ```
1552/// use relative_path::RelativePath;
1553///
1554/// let path: Box<RelativePath> = "foo/bar".into();
1555/// assert_eq!(&*path, "foo/bar");
1556///
1557/// let path: Box<RelativePath> = RelativePath::new("foo/bar").into();
1558/// assert_eq!(&*path, "foo/bar");
1559/// ```
1560#[cfg(feature = "alloc")]
1561impl<T> From<&T> for Box<RelativePath>
1562where
1563    T: ?Sized + AsRef<str>,
1564{
1565    #[inline]
1566    fn from(path: &T) -> Box<RelativePath> {
1567        Box::<RelativePath>::from(Box::<str>::from(path.as_ref()))
1568    }
1569}
1570
1571/// Conversion from [`RelativePathBuf`] to [`Box<RelativePath>`].
1572///
1573/// # Examples
1574///
1575/// ```
1576/// use std::sync::Arc;
1577/// use relative_path::{RelativePath, RelativePathBuf};
1578///
1579/// let path = RelativePathBuf::from("foo/bar");
1580/// let path: Box<RelativePath> = path.into();
1581/// assert_eq!(&*path, "foo/bar");
1582/// ```
1583#[cfg(feature = "alloc")]
1584impl From<RelativePathBuf> for Box<RelativePath> {
1585    #[inline]
1586    fn from(path: RelativePathBuf) -> Box<RelativePath> {
1587        let boxed = Box::<str>::from(path.into_string());
1588        let rw = Box::into_raw(boxed) as *mut RelativePath;
1589        unsafe { Box::from_raw(rw) }
1590    }
1591}
1592
1593/// Clone implementation for [`Box<RelativePath>`].
1594///
1595/// # Examples
1596///
1597/// ```
1598/// use relative_path::RelativePath;
1599///
1600/// let path: Box<RelativePath> = RelativePath::new("foo/bar").into();
1601/// let path2 = path.clone();
1602/// assert_eq!(&*path, &*path2);
1603/// ```
1604#[cfg(feature = "alloc")]
1605impl Clone for Box<RelativePath> {
1606    #[inline]
1607    fn clone(&self) -> Self {
1608        self.to_relative_path_buf().into_boxed_relative_path()
1609    }
1610}
1611
1612/// Conversion from [`RelativePath`] to [`Arc<RelativePath>`].
1613///
1614/// # Examples
1615///
1616/// ```
1617/// use std::sync::Arc;
1618/// use relative_path::RelativePath;
1619///
1620/// let path: Arc<RelativePath> = RelativePath::new("foo/bar").into();
1621/// assert_eq!(&*path, "foo/bar");
1622/// ```
1623#[cfg(feature = "alloc")]
1624impl From<&RelativePath> for Arc<RelativePath> {
1625    #[inline]
1626    fn from(path: &RelativePath) -> Arc<RelativePath> {
1627        let arc: Arc<str> = path.inner.into();
1628        let rw = Arc::into_raw(arc) as *const RelativePath;
1629        unsafe { Arc::from_raw(rw) }
1630    }
1631}
1632
1633/// Conversion from [`RelativePathBuf`] to [`Arc<RelativePath>`].
1634///
1635/// # Examples
1636///
1637/// ```
1638/// use std::sync::Arc;
1639/// use relative_path::{RelativePath, RelativePathBuf};
1640///
1641/// let path = RelativePathBuf::from("foo/bar");
1642/// let path: Arc<RelativePath> = path.into();
1643/// assert_eq!(&*path, "foo/bar");
1644/// ```
1645#[cfg(feature = "alloc")]
1646impl From<RelativePathBuf> for Arc<RelativePath> {
1647    #[inline]
1648    fn from(path: RelativePathBuf) -> Arc<RelativePath> {
1649        let arc = Arc::<str>::from(path.into_string());
1650        let rw = Arc::into_raw(arc) as *const RelativePath;
1651        unsafe { Arc::from_raw(rw) }
1652    }
1653}
1654
1655/// Conversion from [`RelativePathBuf`] to [`Rc<RelativePath>`].
1656///
1657/// # Examples
1658///
1659/// ```
1660/// use std::rc::Rc;
1661/// use relative_path::RelativePath;
1662///
1663/// let path: Rc<RelativePath> = RelativePath::new("foo/bar").into();
1664/// assert_eq!(&*path, "foo/bar");
1665/// ```
1666#[cfg(feature = "alloc")]
1667impl From<&RelativePath> for Rc<RelativePath> {
1668    #[inline]
1669    fn from(path: &RelativePath) -> Rc<RelativePath> {
1670        let rc: Rc<str> = path.inner.into();
1671        let rw = Rc::into_raw(rc) as *const RelativePath;
1672        unsafe { Rc::from_raw(rw) }
1673    }
1674}
1675
1676/// Conversion from [`RelativePathBuf`] to [`Rc<RelativePath>`].
1677///
1678/// # Examples
1679///
1680/// ```
1681/// use std::rc::Rc;
1682/// use relative_path::{RelativePath, RelativePathBuf};
1683///
1684/// let path = RelativePathBuf::from("foo/bar");
1685/// let path: Rc<RelativePath> = path.into();
1686/// assert_eq!(&*path, "foo/bar");
1687/// ```
1688#[cfg(feature = "alloc")]
1689impl From<RelativePathBuf> for Rc<RelativePath> {
1690    #[inline]
1691    fn from(path: RelativePathBuf) -> Rc<RelativePath> {
1692        let rc = Rc::<str>::from(path.into_string());
1693        let rw = Rc::into_raw(rc) as *const RelativePath;
1694        unsafe { Rc::from_raw(rw) }
1695    }
1696}
1697
1698/// [`ToOwned`] implementation for [`RelativePath`].
1699///
1700/// # Examples
1701///
1702/// ```
1703/// use relative_path::RelativePath;
1704///
1705/// let path = RelativePath::new("foo/bar").to_owned();
1706/// assert_eq!(path, "foo/bar");
1707/// ```
1708#[cfg(feature = "alloc")]
1709impl ToOwned for RelativePath {
1710    type Owned = RelativePathBuf;
1711
1712    #[inline]
1713    fn to_owned(&self) -> RelativePathBuf {
1714        self.to_relative_path_buf()
1715    }
1716}
1717
1718impl fmt::Debug for RelativePath {
1719    #[inline]
1720    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1721        self.inner.fmt(f)
1722    }
1723}
1724
1725/// [`AsRef<RelativePath>`] implementation for [String].
1726///
1727/// # Examples
1728///
1729/// ```
1730/// use relative_path::RelativePath;
1731///
1732/// let path: String = format!("foo/bar");
1733/// let path: &RelativePath = path.as_ref();
1734/// assert_eq!(path, "foo/bar");
1735/// ```
1736#[cfg(feature = "alloc")]
1737impl AsRef<RelativePath> for String {
1738    #[inline]
1739    fn as_ref(&self) -> &RelativePath {
1740        RelativePath::new(self)
1741    }
1742}
1743
1744/// [`AsRef<RelativePath>`] implementation for [`str`].
1745///
1746/// [`str`]: prim@str
1747///
1748/// # Examples
1749///
1750/// ```
1751/// use relative_path::RelativePath;
1752///
1753/// let path: &RelativePath = "foo/bar".as_ref();
1754/// assert_eq!(path, RelativePath::new("foo/bar"));
1755/// ```
1756impl AsRef<RelativePath> for str {
1757    #[inline]
1758    fn as_ref(&self) -> &RelativePath {
1759        RelativePath::new(self)
1760    }
1761}
1762
1763impl AsRef<RelativePath> for RelativePath {
1764    #[inline]
1765    fn as_ref(&self) -> &RelativePath {
1766        self
1767    }
1768}
1769
1770impl cmp::PartialEq for RelativePath {
1771    #[inline]
1772    fn eq(&self, other: &RelativePath) -> bool {
1773        self.components() == other.components()
1774    }
1775}
1776
1777impl cmp::Eq for RelativePath {}
1778
1779impl cmp::PartialOrd for RelativePath {
1780    #[inline]
1781    fn partial_cmp(&self, other: &RelativePath) -> Option<cmp::Ordering> {
1782        Some(self.cmp(other))
1783    }
1784}
1785
1786impl cmp::Ord for RelativePath {
1787    #[inline]
1788    fn cmp(&self, other: &RelativePath) -> cmp::Ordering {
1789        self.components().cmp(other.components())
1790    }
1791}
1792
1793impl Hash for RelativePath {
1794    #[inline]
1795    fn hash<H>(&self, h: &mut H)
1796    where
1797        H: Hasher,
1798    {
1799        for c in self.components() {
1800            c.hash(h);
1801        }
1802    }
1803}
1804
1805impl fmt::Display for RelativePath {
1806    #[inline]
1807    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1808        self.inner.fmt(f)
1809    }
1810}
1811
1812/// Helper struct for printing relative paths.
1813///
1814/// This is not strictly necessary in the same sense as it is for [`Display`],
1815/// because relative paths are guaranteed to be valid UTF-8. But the behavior is
1816/// preserved to simplify the transition between [`Path`] and [`RelativePath`].
1817///
1818/// [`Path`]: std::path::Path
1819/// [`Display`]: core::fmt::Display
1820#[deprecated(note = "RelativePath implements std::fmt::Display directly")]
1821pub struct Display<'a> {
1822    path: &'a RelativePath,
1823}
1824
1825#[allow(deprecated)]
1826impl fmt::Debug for Display<'_> {
1827    #[inline]
1828    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1829        fmt::Debug::fmt(&self.path, f)
1830    }
1831}
1832
1833#[allow(deprecated)]
1834impl fmt::Display for Display<'_> {
1835    #[inline]
1836    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1837        fmt::Display::fmt(&self.path, f)
1838    }
1839}
1840
1841/// [`serde::de::Deserialize`] implementation for [`Box<RelativePath>`].
1842///
1843/// ```
1844/// use serde::Deserialize;
1845/// use relative_path::RelativePath;
1846///
1847/// #[derive(Deserialize)]
1848/// struct Document {
1849///     path: Box<RelativePath>,
1850/// }
1851/// ```
1852#[cfg(all(feature = "alloc", feature = "serde"))]
1853#[cfg_attr(
1854    relative_path_docsrs,
1855    doc(cfg(all(feature = "alloc", feature = "serde")))
1856)]
1857impl<'de> serde_core::de::Deserialize<'de> for Box<RelativePath> {
1858    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1859    where
1860        D: serde_core::de::Deserializer<'de>,
1861    {
1862        struct Visitor;
1863
1864        impl serde_core::de::Visitor<'_> for Visitor {
1865            type Value = Box<RelativePath>;
1866
1867            #[inline]
1868            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1869                formatter.write_str("a relative path")
1870            }
1871
1872            #[cfg(feature = "alloc")]
1873            #[inline]
1874            fn visit_string<E>(self, input: String) -> Result<Self::Value, E>
1875            where
1876                E: serde_core::de::Error,
1877            {
1878                Ok(Box::<RelativePath>::from(input.into_boxed_str()))
1879            }
1880
1881            #[inline]
1882            fn visit_str<E>(self, input: &str) -> Result<Self::Value, E>
1883            where
1884                E: serde_core::de::Error,
1885            {
1886                Ok(Box::<RelativePath>::from(input))
1887            }
1888        }
1889
1890        deserializer.deserialize_str(Visitor)
1891    }
1892}
1893
1894/// [`serde::de::Deserialize`] implementation for a [`RelativePath`] reference.
1895///
1896/// ```
1897/// use serde::Deserialize;
1898/// use relative_path::RelativePath;
1899///
1900/// #[derive(Deserialize)]
1901/// struct Document<'a> {
1902///     #[serde(borrow)]
1903///     path: &'a RelativePath,
1904/// }
1905/// ```
1906#[cfg(feature = "serde")]
1907#[cfg_attr(relative_path_docsrs, doc(cfg(feature = "serde")))]
1908impl<'de: 'a, 'a> serde_core::de::Deserialize<'de> for &'a RelativePath {
1909    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1910    where
1911        D: serde_core::de::Deserializer<'de>,
1912    {
1913        struct Visitor;
1914
1915        impl<'a> serde_core::de::Visitor<'a> for Visitor {
1916            type Value = &'a RelativePath;
1917
1918            #[inline]
1919            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1920                formatter.write_str("a borrowed relative path")
1921            }
1922
1923            #[inline]
1924            fn visit_borrowed_str<E>(self, v: &'a str) -> Result<Self::Value, E>
1925            where
1926                E: serde_core::de::Error,
1927            {
1928                Ok(RelativePath::new(v))
1929            }
1930
1931            #[inline]
1932            fn visit_borrowed_bytes<E>(self, v: &'a [u8]) -> Result<Self::Value, E>
1933            where
1934                E: serde_core::de::Error,
1935            {
1936                let string = str::from_utf8(v).map_err(|_| {
1937                    serde_core::de::Error::invalid_value(
1938                        serde_core::de::Unexpected::Bytes(v),
1939                        &self,
1940                    )
1941                })?;
1942                Ok(RelativePath::new(string))
1943            }
1944        }
1945
1946        deserializer.deserialize_str(Visitor)
1947    }
1948}
1949
1950/// [`serde::ser::Serialize`] implementation for [`RelativePath`].
1951///
1952/// ```
1953/// use serde::Serialize;
1954/// use relative_path::RelativePath;
1955///
1956/// #[derive(Serialize)]
1957/// struct Document<'a> {
1958///     path: &'a RelativePath,
1959/// }
1960/// ```
1961#[cfg(feature = "serde")]
1962#[cfg_attr(relative_path_docsrs, doc(cfg(feature = "serde")))]
1963impl serde_core::ser::Serialize for RelativePath {
1964    #[inline]
1965    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1966    where
1967        S: serde_core::ser::Serializer,
1968    {
1969        serializer.serialize_str(&self.inner)
1970    }
1971}
1972
1973macro_rules! impl_cmp {
1974    (
1975        $(#[cfg(feature = $feature:literal)])?
1976        $lhs:ty, $rhs:ty
1977    ) => {
1978        $(#[cfg(feature = $feature)])*
1979        $(#[cfg_attr(relative_path_docsrs, doc(cfg(feature = $feature)))])*
1980        impl<'a, 'b> PartialEq<$rhs> for $lhs {
1981            #[inline]
1982            fn eq(&self, other: &$rhs) -> bool {
1983                <RelativePath as PartialEq>::eq(self, other)
1984            }
1985        }
1986
1987        $(#[cfg(feature = $feature)])*
1988        $(#[cfg_attr(relative_path_docsrs, doc(cfg(feature = $feature)))])*
1989        impl<'a, 'b> PartialEq<$lhs> for $rhs {
1990            #[inline]
1991            fn eq(&self, other: &$lhs) -> bool {
1992                <RelativePath as PartialEq>::eq(self, other)
1993            }
1994        }
1995
1996        $(#[cfg(feature = $feature)])*
1997        $(#[cfg_attr(relative_path_docsrs, doc(cfg(feature = $feature)))])*
1998        impl<'a, 'b> PartialOrd<$rhs> for $lhs {
1999            #[inline]
2000            fn partial_cmp(&self, other: &$rhs) -> Option<cmp::Ordering> {
2001                <RelativePath as PartialOrd>::partial_cmp(self, other)
2002            }
2003        }
2004
2005        $(#[cfg(feature = $feature)])*
2006        $(#[cfg_attr(relative_path_docsrs, doc(cfg(feature = $feature)))])*
2007        impl<'a, 'b> PartialOrd<$lhs> for $rhs {
2008            #[inline]
2009            fn partial_cmp(&self, other: &$lhs) -> Option<cmp::Ordering> {
2010                <RelativePath as PartialOrd>::partial_cmp(self, other)
2011            }
2012        }
2013    };
2014}
2015
2016impl_cmp!(
2017    #[cfg(feature = "alloc")]
2018    RelativePathBuf,
2019    RelativePath
2020);
2021impl_cmp!(
2022    #[cfg(feature = "alloc")]
2023    RelativePathBuf,
2024    &'a RelativePath
2025);
2026impl_cmp!(#[cfg(feature = "alloc")] Cow<'a, RelativePath>, RelativePath);
2027impl_cmp!(#[cfg(feature = "alloc")] Cow<'a, RelativePath>, &'b RelativePath);
2028impl_cmp!(#[cfg(feature = "alloc")] Cow<'a, RelativePath>, RelativePathBuf);
2029
2030macro_rules! impl_cmp_str {
2031    (
2032        $(#[cfg(feature = $feature:literal)])?
2033        $lhs:ty, $rhs:ty
2034    ) => {
2035        $(#[cfg(feature = $feature)])*
2036        $(#[cfg_attr(relative_path_docsrs, doc(cfg(feature = $feature)))])*
2037        impl<'a, 'b> PartialEq<$rhs> for $lhs {
2038            #[inline]
2039            fn eq(&self, other: &$rhs) -> bool {
2040                <RelativePath as PartialEq>::eq(self, other.as_ref())
2041            }
2042        }
2043
2044        $(#[cfg(feature = $feature)])*
2045        $(#[cfg_attr(relative_path_docsrs, doc(cfg(feature = $feature)))])*
2046        impl<'a, 'b> PartialEq<$lhs> for $rhs {
2047            #[inline]
2048            fn eq(&self, other: &$lhs) -> bool {
2049                <RelativePath as PartialEq>::eq(self.as_ref(), other)
2050            }
2051        }
2052
2053        $(#[cfg(feature = $feature)])*
2054        $(#[cfg_attr(relative_path_docsrs, doc(cfg(feature = $feature)))])*
2055        impl<'a, 'b> PartialOrd<$rhs> for $lhs {
2056            #[inline]
2057            fn partial_cmp(&self, other: &$rhs) -> Option<cmp::Ordering> {
2058                <RelativePath as PartialOrd>::partial_cmp(self, other.as_ref())
2059            }
2060        }
2061
2062        $(#[cfg(feature = $feature)])*
2063        $(#[cfg_attr(relative_path_docsrs, doc(cfg(feature = $feature)))])*
2064        impl<'a, 'b> PartialOrd<$lhs> for $rhs {
2065            #[inline]
2066            fn partial_cmp(&self, other: &$lhs) -> Option<cmp::Ordering> {
2067                <RelativePath as PartialOrd>::partial_cmp(self.as_ref(), other)
2068            }
2069        }
2070    };
2071}
2072
2073impl_cmp_str!(
2074    #[cfg(feature = "alloc")]
2075    RelativePathBuf,
2076    str
2077);
2078impl_cmp_str!(
2079    #[cfg(feature = "alloc")]
2080    RelativePathBuf,
2081    &'a str
2082);
2083impl_cmp_str!(
2084    #[cfg(feature = "alloc")]
2085    RelativePathBuf,
2086    String
2087);
2088impl_cmp_str!(RelativePath, str);
2089impl_cmp_str!(RelativePath, &'a str);
2090impl_cmp_str!(
2091    #[cfg(feature = "alloc")]
2092    RelativePath,
2093    String
2094);
2095impl_cmp_str!(&'a RelativePath, str);
2096impl_cmp_str!(#[cfg(feature = "alloc")] &'a RelativePath, String);