use std::io;
use std::path::{Path, PathBuf};
use crate::unique_name;
#[derive(Debug)]
pub struct NamedTempFile {
path: PathBuf,
cleanup_on_drop: bool,
}
impl NamedTempFile {
pub fn new() -> io::Result<Self> {
let name = unique_name(12);
let pid = std::process::id();
let path = std::env::temp_dir().join(format!(".tmpfile-{pid}-{name}"));
std::fs::File::create(&path)?;
Ok(Self {
path,
cleanup_on_drop: true,
})
}
pub fn with_prefix(prefix: &str) -> io::Result<Self> {
let name = unique_name(12);
let path = std::env::temp_dir().join(format!("{prefix}-{name}"));
std::fs::File::create(&path)?;
Ok(Self {
path,
cleanup_on_drop: true,
})
}
pub fn path(&self) -> &Path {
&self.path
}
pub fn persist(mut self) -> PathBuf {
self.cleanup_on_drop = false;
self.path.clone()
}
pub fn cleanup_on_drop(&self) -> bool {
self.cleanup_on_drop
}
}
impl Drop for NamedTempFile {
fn drop(&mut self) {
if self.cleanup_on_drop {
let _ = std::fs::remove_file(&self.path);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn creates_file() {
let f = NamedTempFile::new().unwrap();
assert!(f.path().exists());
assert!(f.path().is_file());
}
#[test]
fn auto_cleanup() {
let path = {
let f = NamedTempFile::new().unwrap();
f.path().to_path_buf()
};
assert!(!path.exists());
}
#[test]
fn persist_disables_cleanup() {
let f = NamedTempFile::new().unwrap();
let path = f.persist();
assert!(path.exists());
std::fs::remove_file(&path).unwrap();
}
#[test]
fn with_prefix_works() {
let f = NamedTempFile::with_prefix("named").unwrap();
let name = f.path().file_name().unwrap().to_string_lossy();
assert!(name.starts_with("named-"));
}
#[test]
fn two_files_unique() {
let a = NamedTempFile::new().unwrap();
let b = NamedTempFile::new().unwrap();
assert_ne!(a.path(), b.path());
}
}