use crate::{Error, Result};
use core::fmt;
use std::fs;
use std::path::{Path, PathBuf};
#[derive(Debug)]
pub struct SPath {
path: PathBuf,
}
impl AsRef<Path> for SPath {
fn as_ref(&self) -> &Path {
self.path.as_ref()
}
}
impl fmt::Display for SPath {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.to_str())
}
}
impl From<SPath> for String {
fn from(val: SPath) -> Self {
val.to_str().to_string()
}
}
impl From<&SPath> for String {
fn from(val: &SPath) -> Self {
val.to_str().to_string()
}
}
impl SPath {
pub fn from_path(path: impl AsRef<Path>) -> Result<Self> {
let path = path.as_ref();
validate_spath_for_result(path)?;
Ok(Self {
path: path.to_path_buf(),
})
}
pub fn from_path_ok(path: impl AsRef<Path>) -> Option<Self> {
let path = path.as_ref();
validate_spath_for_option(path)?;
Some(Self {
path: path.to_path_buf(),
})
}
pub fn from_path_buf_ok(path_buf: PathBuf) -> Option<Self> {
validate_spath_for_option(&path_buf)?;
Some(Self { path: path_buf })
}
pub fn from_fs_entry_ok(fs_entry: fs::DirEntry) -> Option<Self> {
let path_buf = fs_entry.path();
validate_spath_for_option(&path_buf)?;
Some(Self { path: path_buf })
}
pub fn from_walkdir_entry_ok(wd_entry: walkdir::DirEntry) -> Option<Self> {
let path = wd_entry.path();
validate_spath_for_option(path)?;
Some(Self {
path: wd_entry.into_path(),
})
}
}
impl TryFrom<&str> for SPath {
type Error = Error;
fn try_from(path: &str) -> Result<SPath> {
let path = Path::new(path);
validate_spath_for_result(path)?;
Ok(Self {
path: path.to_path_buf(),
})
}
}
impl TryFrom<String> for SPath {
type Error = Error;
fn try_from(path: String) -> Result<SPath> {
SPath::try_from(path.as_str())
}
}
impl TryFrom<&String> for SPath {
type Error = Error;
fn try_from(path: &String) -> Result<SPath> {
SPath::try_from(path.as_str())
}
}
impl TryFrom<PathBuf> for SPath {
type Error = Error;
fn try_from(path_buf: PathBuf) -> Result<SPath> {
validate_spath_for_result(&path_buf)?;
Ok(Self { path: path_buf })
}
}
impl TryFrom<fs::DirEntry> for SPath {
type Error = Error;
fn try_from(fs_entry: fs::DirEntry) -> Result<SPath> {
let path_buf = fs_entry.path();
validate_spath_for_result(&path_buf)?;
Ok(Self { path: path_buf })
}
}
impl TryFrom<walkdir::DirEntry> for SPath {
type Error = Error;
fn try_from(wd_entry: walkdir::DirEntry) -> Result<SPath> {
let path = wd_entry.path();
validate_spath_for_result(path)?;
Ok(Self {
path: wd_entry.into_path(),
})
}
}
pub(crate) fn validate_spath_for_result(path: &Path) -> Result<()> {
if path.to_str().is_none() {
return Err(Error::PathNotUtf8(path.to_string_lossy().to_string()));
}
if path.file_name().is_none() {
return Err(Error::PathHasNoFileName(path.to_string_lossy().to_string()));
}
Ok(())
}
pub(crate) fn validate_spath_for_option(path: &Path) -> Option<()> {
path.to_str()?;
path.file_name()?;
Some(())
}
impl SPath {
pub fn into_path_buf(self) -> PathBuf {
self.path
}
pub fn path(&self) -> &Path {
&self.path
}
}
impl SPath {
pub fn to_str(&self) -> &str {
self.path.to_str().unwrap_or_default()
}
pub fn file_name(&self) -> &str {
self.path.file_name().and_then(|n| n.to_str()).unwrap_or_default()
}
pub fn stem(&self) -> &str {
self.path.file_stem().and_then(|n| n.to_str()).unwrap_or_default()
}
pub fn extension(&self) -> Option<&str> {
self.path.extension().and_then(|os_str| os_str.to_str())
}
}