//! Thin wrappers around `std::path`, distinguishing between absolute and
//! relative paths.
+
+#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
+
use std::{
borrow::Borrow,
- convert::{TryFrom, TryInto},
+ ffi::OsStr,
ops,
path::{Component, Path, PathBuf},
};
.unwrap_or_else(|path| panic!("expected absolute path, got {}", path.display()))
}
- /// Coerces to a `AbsPath` slice.
+ /// Coerces to an `AbsPath` slice.
///
/// Equivalent of [`PathBuf::as_path`] for `AbsPathBuf`.
pub fn as_path(&self) -> &AbsPath {
#[repr(transparent)]
pub struct AbsPath(Path);
-impl ops::Deref for AbsPath {
- type Target = Path;
- fn deref(&self) -> &Path {
+impl AsRef<Path> for AbsPath {
+ fn as_ref(&self) -> &Path {
&self.0
}
}
-impl AsRef<Path> for AbsPath {
- fn as_ref(&self) -> &Path {
- &self.0
+impl ToOwned for AbsPath {
+ type Owned = AbsPathBuf;
+
+ fn to_owned(&self) -> Self::Owned {
+ AbsPathBuf(self.0.to_owned())
}
}
pub fn strip_prefix(&self, base: &AbsPath) -> Option<&RelPath> {
self.0.strip_prefix(base).ok().map(RelPath::new_unchecked)
}
+ pub fn starts_with(&self, base: &AbsPath) -> bool {
+ self.0.starts_with(&base.0)
+ }
+ pub fn ends_with(&self, suffix: &RelPath) -> bool {
+ self.0.ends_with(&suffix.0)
+ }
+
+ // region:delegate-methods
+
+ // Note that we deliberately don't implement `Deref<Target = Path>` here.
+ //
+ // The problem with `Path` is that it directly exposes convenience IO-ing
+ // methods. For example, `Path::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> {
+ self.0.file_name()
+ }
+ pub fn extension(&self) -> Option<&OsStr> {
+ self.0.extension()
+ }
+ pub fn file_stem(&self) -> Option<&OsStr> {
+ self.0.file_stem()
+ }
+ pub fn as_os_str(&self) -> &OsStr {
+ self.0.as_os_str()
+ }
+ pub fn display(&self) -> std::path::Display<'_> {
+ self.0.display()
+ }
+ #[deprecated(note = "use std::fs::metadata().is_ok() instead")]
+ pub fn exists(&self) -> bool {
+ self.0.exists()
+ }
+ // endregion:delegate-methods
}
/// Wrapper around a relative [`PathBuf`].
#[repr(transparent)]
pub struct RelPath(Path);
-impl ops::Deref for RelPath {
- type Target = Path;
- fn deref(&self) -> &Path {
- &self.0
- }
-}
-
impl AsRef<Path> for RelPath {
fn as_ref(&self) -> &Path {
&self.0
/// Taken from <https://github.com/rust-lang/cargo/blob/79c769c3d7b4c2cf6a93781575b7f592ef974255/src/cargo/util/paths.rs#L60-L85>
fn normalize_path(path: &Path) -> PathBuf {
let mut components = path.components().peekable();
- let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() {
+ let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().copied() {
components.next();
PathBuf::from(c.as_os_str())
} else {