// IO error // A wrapper around the tokio IO functions that adds the path to the error message, instead of the uninformative std::io::Error. use std::path::Path; #[derive(Debug, thiserror::Error)] pub enum IOError { #[error("{source}, path: {path}")] IOPathError { #[source] source: std::io::Error, path: String, }, #[error(transparent)] IOError(#[from] std::io::Error), } impl IOError { pub fn from(source: std::io::Error) -> Self { Self::IOError(source) } pub fn with_path( source: std::io::Error, path: impl AsRef, ) -> Self { let path = path.as_ref(); Self::IOPathError { source, path: path.to_string_lossy().to_string(), } } } // dunce canonicalize pub fn canonicalize( path: impl AsRef, ) -> Result { let path = path.as_ref(); dunce::canonicalize(path).map_err(|e| IOError::IOPathError { source: e, path: path.to_string_lossy().to_string(), }) } // read_dir pub async fn read_dir( path: impl AsRef, ) -> Result { let path = path.as_ref(); tokio::fs::read_dir(path) .await .map_err(|e| IOError::IOPathError { source: e, path: path.to_string_lossy().to_string(), }) } // create_dir_all pub async fn create_dir_all( path: impl AsRef, ) -> Result<(), IOError> { let path = path.as_ref(); tokio::fs::create_dir_all(path) .await .map_err(|e| IOError::IOPathError { source: e, path: path.to_string_lossy().to_string(), }) } // remove_dir_all pub async fn remove_dir_all( path: impl AsRef, ) -> Result<(), IOError> { let path = path.as_ref(); tokio::fs::remove_dir_all(path) .await .map_err(|e| IOError::IOPathError { source: e, path: path.to_string_lossy().to_string(), }) } // read_to_string pub async fn read_to_string( path: impl AsRef, ) -> Result { let path = path.as_ref(); tokio::fs::read_to_string(path) .await .map_err(|e| IOError::IOPathError { source: e, path: path.to_string_lossy().to_string(), }) } // read pub async fn read( path: impl AsRef, ) -> Result, IOError> { let path = path.as_ref(); tokio::fs::read(path) .await .map_err(|e| IOError::IOPathError { source: e, path: path.to_string_lossy().to_string(), }) } // write pub async fn write( path: impl AsRef, data: impl AsRef<[u8]>, ) -> Result<(), IOError> { let path = path.as_ref(); tokio::fs::write(path, data) .await .map_err(|e| IOError::IOPathError { source: e, path: path.to_string_lossy().to_string(), }) } // rename pub async fn rename( from: impl AsRef, to: impl AsRef, ) -> Result<(), IOError> { let from = from.as_ref(); let to = to.as_ref(); tokio::fs::rename(from, to) .await .map_err(|e| IOError::IOPathError { source: e, path: from.to_string_lossy().to_string(), }) } // copy pub async fn copy( from: impl AsRef, to: impl AsRef, ) -> Result { let from: &Path = from.as_ref(); let to = to.as_ref(); tokio::fs::copy(from, to) .await .map_err(|e| IOError::IOPathError { source: e, path: from.to_string_lossy().to_string(), }) } // remove file pub async fn remove_file( path: impl AsRef, ) -> Result<(), IOError> { let path = path.as_ref(); tokio::fs::remove_file(path) .await .map_err(|e| IOError::IOPathError { source: e, path: path.to_string_lossy().to_string(), }) }