Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/paths/src/lib.rs')
-rw-r--r--crates/paths/src/lib.rs242
1 files changed, 163 insertions, 79 deletions
diff --git a/crates/paths/src/lib.rs b/crates/paths/src/lib.rs
index a63d251c20..2d3653401d 100644
--- a/crates/paths/src/lib.rs
+++ b/crates/paths/src/lib.rs
@@ -1,4 +1,4 @@
-//! Thin wrappers around `std::path`, distinguishing between absolute and
+//! Thin wrappers around `std::path`/`camino::path`, distinguishing between absolute and
//! relative paths.
#![warn(rust_2018_idioms, unused_lifetimes)]
@@ -7,16 +7,24 @@ use std::{
borrow::Borrow,
ffi::OsStr,
fmt, ops,
- path::{Component, Path, PathBuf},
+ path::{Path, PathBuf},
};
-/// Wrapper around an absolute [`PathBuf`].
-#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
-pub struct AbsPathBuf(PathBuf);
+pub use camino::*;
+
+/// Wrapper around an absolute [`Utf8PathBuf`].
+#[derive(Debug, Clone, Ord, PartialOrd, Eq, Hash)]
+pub struct AbsPathBuf(Utf8PathBuf);
+
+impl From<AbsPathBuf> for Utf8PathBuf {
+ fn from(AbsPathBuf(path_buf): AbsPathBuf) -> Utf8PathBuf {
+ path_buf
+ }
+}
impl From<AbsPathBuf> for PathBuf {
fn from(AbsPathBuf(path_buf): AbsPathBuf) -> PathBuf {
- path_buf
+ path_buf.into()
}
}
@@ -27,9 +35,21 @@ impl ops::Deref for AbsPathBuf {
}
}
+impl AsRef<Utf8Path> for AbsPathBuf {
+ fn as_ref(&self) -> &Utf8Path {
+ self.0.as_path()
+ }
+}
+
+impl AsRef<OsStr> for AbsPathBuf {
+ fn as_ref(&self) -> &OsStr {
+ self.0.as_ref()
+ }
+}
+
impl AsRef<Path> for AbsPathBuf {
fn as_ref(&self) -> &Path {
- self.0.as_path()
+ self.0.as_ref()
}
}
@@ -45,26 +65,36 @@ impl Borrow<AbsPath> for AbsPathBuf {
}
}
+impl TryFrom<Utf8PathBuf> for AbsPathBuf {
+ type Error = Utf8PathBuf;
+ fn try_from(path_buf: Utf8PathBuf) -> Result<AbsPathBuf, Utf8PathBuf> {
+ if !path_buf.is_absolute() {
+ return Err(path_buf);
+ }
+ Ok(AbsPathBuf(path_buf))
+ }
+}
+
impl TryFrom<PathBuf> for AbsPathBuf {
type Error = PathBuf;
fn try_from(path_buf: PathBuf) -> Result<AbsPathBuf, PathBuf> {
if !path_buf.is_absolute() {
return Err(path_buf);
}
- Ok(AbsPathBuf(path_buf))
+ Ok(AbsPathBuf(Utf8PathBuf::from_path_buf(path_buf)?))
}
}
impl TryFrom<&str> for AbsPathBuf {
- type Error = PathBuf;
- fn try_from(path: &str) -> Result<AbsPathBuf, PathBuf> {
- AbsPathBuf::try_from(PathBuf::from(path))
+ type Error = Utf8PathBuf;
+ fn try_from(path: &str) -> Result<AbsPathBuf, Utf8PathBuf> {
+ AbsPathBuf::try_from(Utf8PathBuf::from(path))
}
}
-impl PartialEq<AbsPath> for AbsPathBuf {
- fn eq(&self, other: &AbsPath) -> bool {
- self.as_path() == other
+impl<P: AsRef<Path> + ?Sized> PartialEq<P> for AbsPathBuf {
+ fn eq(&self, other: &P) -> bool {
+ self.0.as_std_path() == other.as_ref()
}
}
@@ -74,19 +104,31 @@ impl AbsPathBuf {
/// # Panics
///
/// Panics if `path` is not absolute.
- pub fn assert(path: PathBuf) -> AbsPathBuf {
+ pub fn assert(path: Utf8PathBuf) -> AbsPathBuf {
AbsPathBuf::try_from(path)
- .unwrap_or_else(|path| panic!("expected absolute path, got {}", path.display()))
+ .unwrap_or_else(|path| panic!("expected absolute path, got {}", path))
+ }
+
+ /// Wrap the given absolute path in `AbsPathBuf`
+ ///
+ /// # Panics
+ ///
+ /// Panics if `path` is not absolute.
+ pub fn assert_utf8(path: PathBuf) -> AbsPathBuf {
+ AbsPathBuf::assert(
+ Utf8PathBuf::from_path_buf(path)
+ .unwrap_or_else(|path| panic!("expected utf8 path, got {}", path.display())),
+ )
}
/// Coerces to an `AbsPath` slice.
///
- /// Equivalent of [`PathBuf::as_path`] for `AbsPathBuf`.
+ /// Equivalent of [`Utf8PathBuf::as_path`] for `AbsPathBuf`.
pub fn as_path(&self) -> &AbsPath {
AbsPath::assert(self.0.as_path())
}
- /// Equivalent of [`PathBuf::pop`] for `AbsPathBuf`.
+ /// Equivalent of [`Utf8PathBuf::pop`] for `AbsPathBuf`.
///
/// Note that this won't remove the root component, so `self` will still be
/// absolute.
@@ -97,18 +139,36 @@ impl AbsPathBuf {
impl fmt::Display for AbsPathBuf {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Display::fmt(&self.0.display(), f)
+ fmt::Display::fmt(&self.0, f)
}
}
-/// Wrapper around an absolute [`Path`].
-#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
+/// Wrapper around an absolute [`Utf8Path`].
+#[derive(Debug, Ord, PartialOrd, Eq, Hash)]
#[repr(transparent)]
-pub struct AbsPath(Path);
+pub struct AbsPath(Utf8Path);
+
+impl<P: AsRef<Path> + ?Sized> PartialEq<P> for AbsPath {
+ fn eq(&self, other: &P) -> bool {
+ self.0.as_std_path() == other.as_ref()
+ }
+}
+
+impl AsRef<Utf8Path> for AbsPath {
+ fn as_ref(&self) -> &Utf8Path {
+ &self.0
+ }
+}
impl AsRef<Path> for AbsPath {
fn as_ref(&self) -> &Path {
- &self.0
+ self.0.as_ref()
+ }
+}
+
+impl AsRef<OsStr> for AbsPath {
+ fn as_ref(&self) -> &OsStr {
+ self.0.as_ref()
}
}
@@ -120,9 +180,9 @@ impl ToOwned for AbsPath {
}
}
-impl<'a> TryFrom<&'a Path> for &'a AbsPath {
- type Error = &'a Path;
- fn try_from(path: &'a Path) -> Result<&'a AbsPath, &'a Path> {
+impl<'a> TryFrom<&'a Utf8Path> for &'a AbsPath {
+ type Error = &'a Utf8Path;
+ fn try_from(path: &'a Utf8Path) -> Result<&'a AbsPath, &'a Utf8Path> {
if !path.is_absolute() {
return Err(path);
}
@@ -136,24 +196,24 @@ impl AbsPath {
/// # Panics
///
/// Panics if `path` is not absolute.
- pub fn assert(path: &Path) -> &AbsPath {
+ pub fn assert(path: &Utf8Path) -> &AbsPath {
assert!(path.is_absolute());
- unsafe { &*(path as *const Path as *const AbsPath) }
+ unsafe { &*(path as *const Utf8Path as *const AbsPath) }
}
- /// Equivalent of [`Path::parent`] for `AbsPath`.
+ /// Equivalent of [`Utf8Path::parent`] for `AbsPath`.
pub fn parent(&self) -> Option<&AbsPath> {
self.0.parent().map(AbsPath::assert)
}
- /// Equivalent of [`Path::join`] for `AbsPath` with an additional normalize step afterwards.
- pub fn absolutize(&self, path: impl AsRef<Path>) -> AbsPathBuf {
+ /// Equivalent of [`Utf8Path::join`] for `AbsPath` with an additional normalize step afterwards.
+ pub fn absolutize(&self, path: impl AsRef<Utf8Path>) -> AbsPathBuf {
self.join(path).normalize()
}
- /// Equivalent of [`Path::join`] for `AbsPath`.
- pub fn join(&self, path: impl AsRef<Path>) -> AbsPathBuf {
- self.as_ref().join(path).try_into().unwrap()
+ /// Equivalent of [`Utf8Path::join`] for `AbsPath`.
+ pub fn join(&self, path: impl AsRef<Utf8Path>) -> AbsPathBuf {
+ Utf8Path::join(self.as_ref(), path).try_into().unwrap()
}
/// Normalize the given path:
@@ -172,7 +232,7 @@ impl AbsPath {
AbsPathBuf(normalize_path(&self.0))
}
- /// Equivalent of [`Path::to_path_buf`] for `AbsPath`.
+ /// Equivalent of [`Utf8Path::to_path_buf`] for `AbsPath`.
pub fn to_path_buf(&self) -> AbsPathBuf {
AbsPathBuf::try_from(self.0.to_path_buf()).unwrap()
}
@@ -181,7 +241,7 @@ impl AbsPath {
panic!("We explicitly do not provide canonicalization API, as that is almost always a wrong solution, see #14430")
}
- /// Equivalent of [`Path::strip_prefix`] for `AbsPath`.
+ /// Equivalent of [`Utf8Path::strip_prefix`] for `AbsPath`.
///
/// Returns a relative path.
pub fn strip_prefix(&self, base: &AbsPath) -> Option<&RelPath> {
@@ -195,57 +255,61 @@ impl AbsPath {
}
pub fn name_and_extension(&self) -> Option<(&str, Option<&str>)> {
- Some((
- self.file_stem()?.to_str()?,
- self.extension().and_then(|extension| extension.to_str()),
- ))
+ Some((self.file_stem()?, self.extension()))
}
// region:delegate-methods
- // Note that we deliberately don't implement `Deref<Target = Path>` here.
+ // Note that we deliberately don't implement `Deref<Target = Utf8Path>` here.
//
- // The problem with `Path` is that it directly exposes convenience IO-ing
- // methods. For example, `Path::exists` delegates to `fs::metadata`.
+ // The problem with `Utf8Path` is that it directly exposes convenience IO-ing
+ // methods. For example, `Utf8Path::exists` delegates to `fs::metadata`.
//
// For `AbsPath`, we want to make sure that this is a POD type, and that all
// IO goes via `fs`. That way, it becomes easier to mock IO when we need it.
- pub fn file_name(&self) -> Option<&OsStr> {
+ pub fn file_name(&self) -> Option<&str> {
self.0.file_name()
}
- pub fn extension(&self) -> Option<&OsStr> {
+ pub fn extension(&self) -> Option<&str> {
self.0.extension()
}
- pub fn file_stem(&self) -> Option<&OsStr> {
+ pub fn file_stem(&self) -> Option<&str> {
self.0.file_stem()
}
pub fn as_os_str(&self) -> &OsStr {
self.0.as_os_str()
}
+ pub fn as_str(&self) -> &str {
+ self.0.as_str()
+ }
#[deprecated(note = "use Display instead")]
- pub fn display(&self) -> std::path::Display<'_> {
- self.0.display()
+ pub fn display(&self) -> ! {
+ unimplemented!()
}
#[deprecated(note = "use std::fs::metadata().is_ok() instead")]
- pub fn exists(&self) -> bool {
- self.0.exists()
+ pub fn exists(&self) -> ! {
+ unimplemented!()
+ }
+
+ pub fn components(&self) -> Utf8Components<'_> {
+ self.0.components()
}
// endregion:delegate-methods
}
impl fmt::Display for AbsPath {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Display::fmt(&self.0.display(), f)
+ fmt::Display::fmt(&self.0, f)
}
}
-/// Wrapper around a relative [`PathBuf`].
+/// Wrapper around a relative [`Utf8PathBuf`].
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
-pub struct RelPathBuf(PathBuf);
+pub struct RelPathBuf(Utf8PathBuf);
-impl From<RelPathBuf> for PathBuf {
- fn from(RelPathBuf(path_buf): RelPathBuf) -> PathBuf {
+impl From<RelPathBuf> for Utf8PathBuf {
+ fn from(RelPathBuf(path_buf): RelPathBuf) -> Utf8PathBuf {
path_buf
}
}
@@ -257,15 +321,21 @@ impl ops::Deref for RelPathBuf {
}
}
+impl AsRef<Utf8Path> for RelPathBuf {
+ fn as_ref(&self) -> &Utf8Path {
+ self.0.as_path()
+ }
+}
+
impl AsRef<Path> for RelPathBuf {
fn as_ref(&self) -> &Path {
- self.0.as_path()
+ self.0.as_ref()
}
}
-impl TryFrom<PathBuf> for RelPathBuf {
- type Error = PathBuf;
- fn try_from(path_buf: PathBuf) -> Result<RelPathBuf, PathBuf> {
+impl TryFrom<Utf8PathBuf> for RelPathBuf {
+ type Error = Utf8PathBuf;
+ fn try_from(path_buf: Utf8PathBuf) -> Result<RelPathBuf, Utf8PathBuf> {
if !path_buf.is_relative() {
return Err(path_buf);
}
@@ -274,65 +344,79 @@ impl TryFrom<PathBuf> for RelPathBuf {
}
impl TryFrom<&str> for RelPathBuf {
- type Error = PathBuf;
- fn try_from(path: &str) -> Result<RelPathBuf, PathBuf> {
- RelPathBuf::try_from(PathBuf::from(path))
+ type Error = Utf8PathBuf;
+ fn try_from(path: &str) -> Result<RelPathBuf, Utf8PathBuf> {
+ RelPathBuf::try_from(Utf8PathBuf::from(path))
}
}
impl RelPathBuf {
/// Coerces to a `RelPath` slice.
///
- /// Equivalent of [`PathBuf::as_path`] for `RelPathBuf`.
+ /// Equivalent of [`Utf8PathBuf::as_path`] for `RelPathBuf`.
pub fn as_path(&self) -> &RelPath {
RelPath::new_unchecked(self.0.as_path())
}
}
-/// Wrapper around a relative [`Path`].
+/// Wrapper around a relative [`Utf8Path`].
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
#[repr(transparent)]
-pub struct RelPath(Path);
+pub struct RelPath(Utf8Path);
+
+impl AsRef<Utf8Path> for RelPath {
+ fn as_ref(&self) -> &Utf8Path {
+ &self.0
+ }
+}
impl AsRef<Path> for RelPath {
fn as_ref(&self) -> &Path {
- &self.0
+ self.0.as_ref()
}
}
impl RelPath {
/// Creates a new `RelPath` from `path`, without checking if it is relative.
- pub fn new_unchecked(path: &Path) -> &RelPath {
- unsafe { &*(path as *const Path as *const RelPath) }
+ pub fn new_unchecked(path: &Utf8Path) -> &RelPath {
+ unsafe { &*(path as *const Utf8Path as *const RelPath) }
}
- /// Equivalent of [`Path::to_path_buf`] for `RelPath`.
+ /// Equivalent of [`Utf8Path::to_path_buf`] for `RelPath`.
pub fn to_path_buf(&self) -> RelPathBuf {
RelPathBuf::try_from(self.0.to_path_buf()).unwrap()
}
+
+ pub fn as_utf8_path(&self) -> &Utf8Path {
+ self.as_ref()
+ }
+
+ pub fn as_str(&self) -> &str {
+ self.0.as_str()
+ }
}
/// Taken from <https://github.com/rust-lang/cargo/blob/79c769c3d7b4c2cf6a93781575b7f592ef974255/src/cargo/util/paths.rs#L60-L85>
-fn normalize_path(path: &Path) -> PathBuf {
+fn normalize_path(path: &Utf8Path) -> Utf8PathBuf {
let mut components = path.components().peekable();
- let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().copied() {
+ let mut ret = if let Some(c @ Utf8Component::Prefix(..)) = components.peek().copied() {
components.next();
- PathBuf::from(c.as_os_str())
+ Utf8PathBuf::from(c.as_str())
} else {
- PathBuf::new()
+ Utf8PathBuf::new()
};
for component in components {
match component {
- Component::Prefix(..) => unreachable!(),
- Component::RootDir => {
- ret.push(component.as_os_str());
+ Utf8Component::Prefix(..) => unreachable!(),
+ Utf8Component::RootDir => {
+ ret.push(component.as_str());
}
- Component::CurDir => {}
- Component::ParentDir => {
+ Utf8Component::CurDir => {}
+ Utf8Component::ParentDir => {
ret.pop();
}
- Component::Normal(c) => {
+ Utf8Component::Normal(c) => {
ret.push(c);
}
}