use std::borrow::Borrow;
use std::fmt;
use std::ops::Deref;
use std::path::Path;
use std::path::PathBuf;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub(crate) struct AbsolutePath(PathBuf);
impl AbsolutePath {
pub(crate) fn as_path(&self) -> &Path { &self.0 }
pub(crate) fn to_path_buf(&self) -> PathBuf { self.0.clone() }
pub(crate) fn display_path(&self) -> DisplayPath {
DisplayPath::new(home_relative_path(&self.0))
}
pub(crate) fn resolve(raw: &str, base: &Path) -> Self {
let raw_path = Path::new(raw);
let resolved = if raw_path.is_absolute() {
PathBuf::from(raw)
} else {
base.join(raw)
};
Self::from(resolved.canonicalize().unwrap_or(resolved))
}
pub(crate) fn resolve_no_canonicalize(raw: &str, base: &Path) -> Self {
let raw_path = Path::new(raw);
if raw_path.is_absolute() {
Self::from(raw)
} else {
Self::from(base.join(raw))
}
}
}
impl PartialEq<Path> for AbsolutePath {
fn eq(&self, other: &Path) -> bool { self.0.as_path() == other }
}
impl PartialEq<AbsolutePath> for Path {
fn eq(&self, other: &AbsolutePath) -> bool { self == other.0.as_path() }
}
impl PartialEq<AbsolutePath> for PathBuf {
fn eq(&self, other: &AbsolutePath) -> bool { self.as_path() == other.0.as_path() }
}
impl PartialEq<PathBuf> for AbsolutePath {
fn eq(&self, other: &PathBuf) -> bool { self.0.as_path() == other.as_path() }
}
impl Deref for AbsolutePath {
type Target = Path;
fn deref(&self) -> &Path { &self.0 }
}
impl AsRef<Path> for AbsolutePath {
fn as_ref(&self) -> &Path { &self.0 }
}
impl Borrow<Path> for AbsolutePath {
fn borrow(&self) -> &Path { &self.0 }
}
impl fmt::Display for AbsolutePath {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.display().fmt(f) }
}
impl From<PathBuf> for AbsolutePath {
fn from(path: PathBuf) -> Self {
debug_assert!(
path.is_absolute(),
"AbsolutePath requires an absolute path: {}",
path.display()
);
Self(path)
}
}
impl From<String> for AbsolutePath {
fn from(path: String) -> Self {
let pb = PathBuf::from(path);
debug_assert!(
pb.is_absolute(),
"AbsolutePath requires an absolute path: {}",
pb.display()
);
Self(pb)
}
}
impl From<&str> for AbsolutePath {
fn from(path: &str) -> Self {
let pb = PathBuf::from(path);
debug_assert!(
pb.is_absolute(),
"AbsolutePath requires an absolute path: {path}"
);
Self(pb)
}
}
impl From<&Path> for AbsolutePath {
fn from(path: &Path) -> Self {
debug_assert!(
path.is_absolute(),
"AbsolutePath requires an absolute path: {}",
path.display()
);
Self(path.to_path_buf())
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub(crate) struct DisplayPath(String);
impl DisplayPath {
pub(crate) const fn new(s: String) -> Self { Self(s) }
pub(crate) fn as_str(&self) -> &str { &self.0 }
pub(crate) fn into_string(self) -> String { self.0 }
}
impl fmt::Display for DisplayPath {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) }
}
impl AsRef<str> for DisplayPath {
fn as_ref(&self) -> &str { self.as_str() }
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) struct RootDirectoryName(pub(super) String);
impl RootDirectoryName {
pub(crate) fn as_str(&self) -> &str { &self.0 }
pub(crate) fn into_string(self) -> String { self.0 }
}
impl fmt::Display for RootDirectoryName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) }
}
impl AsRef<str> for RootDirectoryName {
fn as_ref(&self) -> &str { self.as_str() }
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) struct PackageName(pub(super) String);
impl PackageName {
pub(crate) fn as_str(&self) -> &str { &self.0 }
pub(crate) fn into_string(self) -> String { self.0 }
}
impl fmt::Display for PackageName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) }
}
impl AsRef<str> for PackageName {
fn as_ref(&self) -> &str { self.as_str() }
}
pub(crate) fn home_relative_path(path: &Path) -> String {
if let Some(home) = dirs::home_dir()
&& let Ok(rel) = path.strip_prefix(&home)
{
return format!("~/{}", rel.display());
}
path.display().to_string()
}
pub(super) fn directory_leaf(path: &Path) -> String {
path.file_name()
.and_then(std::ffi::OsStr::to_str)
.unwrap_or("")
.to_string()
}