use std::{
fmt::Display,
fs::{self, File},
io,
path::{Path, PathBuf},
};
#[derive(Debug)]
pub struct IoErrorAtPath {
pub message: String,
pub path: PathBuf,
pub cause: io::Error,
}
impl Display for IoErrorAtPath {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{} {}: {}",
self.message,
self.path.display(),
self.cause
)
}
}
impl IoErrorAtPath {
pub fn new(
message: impl Into<String>,
path: impl Into<PathBuf>,
cause: impl Into<io::Error>,
) -> IoErrorAtPath {
IoErrorAtPath {
message: message.into(),
path: path.into(),
cause: cause.into(),
}
}
pub fn mapper<I: Into<io::Error>>(
message: impl Into<String>,
path: impl Into<PathBuf>,
) -> impl FnOnce(I) -> IoErrorAtPath {
|cause| IoErrorAtPath::new(message, path, cause)
}
}
pub(crate) fn io_error<I: Into<io::Error>>(
message: impl Into<String>,
path: impl Into<PathBuf>,
) -> impl FnOnce(I) -> IoErrorAtPath {
IoErrorAtPath::mapper(message, path)
}
impl From<IoErrorAtPath> for io::Error {
fn from(value: IoErrorAtPath) -> io::Error {
io::Error::new(value.cause.kind(), value.to_string())
}
}
pub(crate) fn create(path: impl AsRef<Path>) -> Result<File, IoErrorAtPath> {
File::create(&path).map_err(io_error("Failed to create file", path.as_ref()))
}
pub(crate) fn write(path: impl AsRef<Path>, contents: &str) -> Result<(), IoErrorAtPath> {
if let Some(parent) = path.as_ref().parent() {
create_dir_all(parent)?;
}
fs::write(&path, contents).map_err(io_error("Failed to create file", path.as_ref()))
}
pub(crate) fn create_dir_all(path: impl AsRef<Path>) -> Result<(), IoErrorAtPath> {
fs::create_dir_all(&path).map_err(io_error("Failed to create directory", path.as_ref()))?;
Ok(())
}
pub(crate) fn remove_dir(path: impl AsRef<Path>) -> Result<(), IoErrorAtPath> {
fs::remove_dir(&path).map_err(io_error("Failed to remove directory", path.as_ref()))?;
Ok(())
}
pub(crate) fn remove_dir_all(path: impl AsRef<Path>) -> Result<(), IoErrorAtPath> {
fs::remove_dir_all(&path).map_err(io_error("Failed to remove directory", path.as_ref()))?;
Ok(())
}
pub(crate) fn remove_file(path: impl AsRef<Path>) -> Result<(), IoErrorAtPath> {
fs::remove_file(&path).map_err(io_error("Failed to remove file", path.as_ref()))?;
Ok(())
}
pub(crate) fn rename(from: impl AsRef<Path>, to: impl AsRef<Path>) -> Result<(), IoErrorAtPath> {
fs::rename(&from, &to).map_err(io_error("Failed to rename file", from.as_ref()))?;
Ok(())
}