#![deny(warnings, clippy::all)]
use std::{
io::ErrorKind,
path::{Path, PathBuf},
};
mod rel_fs;
pub use rel_fs::RelFs;
#[derive(thiserror::Error, Debug, PartialEq, Eq)]
pub enum Error {
#[error("Failed to locate {path:?}")]
NotFound { path: PathBuf },
#[error("Failed to access {path:?}")]
AccessDenied { path: PathBuf },
#[error("The path {path:?} is outside acceptable bounds")]
PathOutsideBounds { path: PathBuf },
#[error("The path {path:?} is not a directory")]
NotADirectory { path: PathBuf },
#[error("{0}")]
Other(String),
}
impl Error {
pub fn to_io_error(&self) -> std::io::Error {
match self {
Self::NotFound { .. } => ErrorKind::NotFound.into(),
Self::AccessDenied { .. } => ErrorKind::PermissionDenied.into(),
Self::PathOutsideBounds { .. } => ErrorKind::InvalidInput.into(),
Self::NotADirectory { .. } => {
std::io::Error::new(ErrorKind::Other, "Not a directory")
}
Self::Other(message) => std::io::Error::new(ErrorKind::Other, message.as_str()),
}
}
pub fn from_io(path: PathBuf, e: std::io::Error) -> Self {
match e.kind() {
ErrorKind::NotFound => Self::NotFound { path },
ErrorKind::PermissionDenied => Self::AccessDenied { path },
_ => {
let msg = e.to_string();
match msg.as_str().split_once(" (os error") {
Some(("Not a directory", _)) => Self::NotADirectory { path },
_ => Self::Other(msg),
}
}
}
}
}
pub trait LogixVfs: std::fmt::Debug + Send + Sync {
type RoFile: std::io::Read;
type ReadDir: Iterator<Item = Result<PathBuf, Error>>;
fn canonicalize_path(&self, path: &Path) -> Result<PathBuf, Error>;
fn open_file(&self, path: &Path) -> Result<Self::RoFile, Error>;
fn read_dir(&self, path: &Path) -> Result<Self::ReadDir, Error>;
}