internal: make it easier to isolate IO

This commit is contained in:
Aleksey Kladov 2021-07-17 16:43:33 +03:00
parent a2f83c956e
commit 9318c643f1
8 changed files with 58 additions and 35 deletions

View file

@ -3,6 +3,7 @@
use std::{
borrow::Borrow,
convert::{TryFrom, TryInto},
ffi::OsStr,
ops,
path::{Component, Path, PathBuf},
};
@ -97,13 +98,6 @@ impl AbsPathBuf {
#[repr(transparent)]
pub struct AbsPath(Path);
impl ops::Deref for AbsPath {
type Target = Path;
fn deref(&self) -> &Path {
&self.0
}
}
impl AsRef<Path> for AbsPath {
fn as_ref(&self) -> &Path {
&self.0
@ -168,6 +162,40 @@ impl AbsPath {
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)
}
// 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 +252,6 @@ impl RelPathBuf {
#[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