// use std::{ marker::PhantomData, path::{Path, PathBuf}, }; use crate::fs::{Error, Result}; pub trait PathType {} pub struct PathG; impl PathType for PathG {} pub struct FileG; impl PathType for FileG {} pub struct DirG; impl PathType for DirG {} #[derive(Debug)] pub struct PathReal<'base, 'path, T: PathType> { base: &'base Path, path: &'path Path, _phanton: PhantomData, pub(super) error: Option, } impl<'base, 'path, T: PathType> PathReal<'base, 'path, T> { pub(super) fn new(base: &'base Path, path: &'path Path) -> Self { Self { base, path, _phanton: PhantomData::, error: PathReal::::validate(base, path), } } pub fn as_pathbuf(&self) -> PathBuf { self.base.join(self.path) } pub(super) fn put(&mut self, error: Error) { if self.error.is_none() { self.error.replace(error); } } fn validate(base: &Path, path: &Path) -> Option { match PathReal::::clean_path(path) { Err(error) => Some(error), Ok(path) => { if !path.starts_with(base) { return Some(Error::PathTraversal { base: base.to_path_buf(), path, }); } None } } } fn clean_path(path: &Path) -> Result { // let path = path.as_ref(); use path_clean::PathClean; let abs_path = if path.is_absolute() { path.to_path_buf() } else { std::env::current_dir().expect("current_dir").join(path) } .clean(); Ok(abs_path) } pub(super) fn check_error(&mut self) -> Result<()> { if let Some(error) = self.error.take() { return Err(error); } Ok(()) } pub fn exists(&mut self) -> Result { self.check_error()?; Ok(self.as_pathbuf().exists()) } pub fn is_dir(&mut self) -> Result { self.check_error()?; Ok(self.as_pathbuf().is_dir()) } pub fn is_file(&mut self) -> Result { self.check_error()?; Ok(self.as_pathbuf().is_file()) } pub fn as_dir(&mut self) -> Result>> { self.check_error()?; if self.as_pathbuf().is_dir() { Ok(Some(PathReal::new(self.base, self.path))) } else { Ok(None) } } pub fn as_file(&mut self) -> Result>> { self.check_error()?; if self.as_pathbuf().is_file() { Ok(Some(PathReal::new(self.base, self.path))) } else { Ok(None) } } } impl From> for PathBuf { fn from(path: PathReal) -> Self { path.base.join(path.path) } }