]> git.lizzy.rs Git - rust.git/blobdiff - crates/paths/src/lib.rs
Auto merge of #12808 - Veykril:check-workspace, r=Veykril
[rust.git] / crates / paths / src / lib.rs
index 48dac14c4abbf9f1781b5a8b7ff111f00aa97fc2..6ae23ac841adaa6a7f97d8841c57aec96f2d2439 100644 (file)
@@ -1,8 +1,11 @@
 //! 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},
 };
@@ -76,7 +79,7 @@ pub fn assert(path: PathBuf) -> AbsPathBuf {
             .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 {
@@ -97,16 +100,17 @@ pub fn pop(&mut self) -> bool {
 #[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())
     }
 }
 
@@ -168,6 +172,43 @@ pub fn to_path_buf(&self) -> AbsPathBuf {
     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`].
@@ -224,13 +265,6 @@ pub fn as_path(&self) -> &RelPath {
 #[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
@@ -247,7 +281,7 @@ pub fn new_unchecked(path: &Path) -> &RelPath {
 /// 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 {