use std::{
fs, io,
path::{Path, PathBuf},
};
#[derive(Debug)]
pub struct OwnedDirectory {
path: PathBuf,
armed: bool,
}
impl OwnedDirectory {
#[must_use]
pub const fn new(path: PathBuf) -> Self {
Self { path, armed: true }
}
#[must_use]
pub fn path(&self) -> &Path {
&self.path
}
#[must_use]
pub const fn is_armed(&self) -> bool {
self.armed
}
pub const fn disarm(&mut self) {
self.armed = false;
}
pub fn preserve(mut self) {
self.disarm();
}
pub fn try_cleanup(&mut self) -> io::Result<()> {
remove_path_if_present(&self.path)?;
self.disarm();
Ok(())
}
pub fn cleanup(self) -> io::Result<()> {
self.cleanup_with(remove_path_if_present)
}
fn cleanup_with(mut self, remove: impl FnOnce(&Path) -> io::Result<()>) -> io::Result<()> {
self.disarm();
remove(&self.path)
}
}
impl Drop for OwnedDirectory {
fn drop(&mut self) {
if self.armed {
let _ = remove_path_if_present(&self.path);
self.disarm();
}
}
}
pub fn remove_path_if_present(path: &Path) -> io::Result<()> {
let metadata = match fs::symlink_metadata(path) {
Ok(metadata) => metadata,
Err(error) if error.kind() == io::ErrorKind::NotFound => return Ok(()),
Err(error) => return Err(error),
};
if metadata.file_type().is_dir() {
fs::remove_dir_all(path)
} else {
fs::remove_file(path)
}
}
#[cfg(test)]
mod tests;