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