use std::{ ops, path::{ PathBuf, Path }, fmt, }; use lazy_static::lazy_static; pub mod error; #[derive(Debug, PartialEq, Eq, Hash)] pub struct TempFile(PathBuf); const FILENAME_LEN_BYTES: usize = 16; const PREFIX: &'static str = "lolistealer-"; lazy_static! { pub static ref LOCATION: &'static Path = { Box::leak(std::env::temp_dir().into_boxed_path()) }; } /// Generate a new random byte string for a filename. fn generate_filename(mut to: impl fmt::Write) -> Result<(), error::Error> { let mut buffer = [0u8; FILENAME_LEN_BYTES]; getrandom::getrandom(&mut buffer[..])?; write!(to, "{}", PREFIX)?; for byte in buffer.iter() { write!(to, "{:02x}", *byte)?; } Ok(()) } impl TempFile { /// Create a new temp file path pub fn new() -> Self { let mut buffer = String::with_capacity((FILENAME_LEN_BYTES*2) + PREFIX.len()); generate_filename(&mut buffer).expect("tf fatal"); Self(LOCATION.join(buffer)) } /// Try to create a new temp file path pub fn try_new() -> Result { let mut buffer = String::with_capacity((FILENAME_LEN_BYTES*2) + PREFIX.len()); generate_filename(&mut buffer)?; Ok(Self(LOCATION.join(buffer))) } /// Consume the `TempFile` and return the raw path, performing no cleanup. pub fn into_pathbuf(mut self) -> PathBuf { let pb = std::mem::replace(&mut self.0, PathBuf::default()); std::mem::forget(self); pb } } impl ops::Drop for TempFile { fn drop(&mut self) { if self.0.exists() { if self.0.is_file() { let _ = std::fs::remove_file(&self.0); } else { let _ = std::fs::remove_dir_all(&self.0); } } } } impl AsRef for TempFile { fn as_ref(&self) -> &Path { self.0.as_ref() } } impl ops::Deref for TempFile { type Target = Path; fn deref(&self) -> &Self::Target { self.0.as_ref() } }