lazin 1.0.3

Primarily a dotfiles manager
use std::{
    env,
    fs::{self, File, OpenOptions},
    path::{Path, PathBuf},
    sync::atomic::AtomicUsize,
};

static FILE_COUNT: AtomicUsize = AtomicUsize::new(0);

fn next_unique_file_ext() -> String {
    format!(
        "{}",
        FILE_COUNT.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
    )
}

pub struct TempFilepath(PathBuf);

impl TempFilepath {
    pub fn new() -> Self {
        let file_path = env::temp_dir().join(Self::next_file());
        OpenOptions::new()
            .create_new(true)
            .write(true)
            .open(&file_path)
            .expect("a valid new file");

        Self(file_path)
    }

    pub fn new_with_parent_dir(parent_dir: &Path) -> Self {
        assert!(parent_dir.is_dir(), "not a directory");

        Self(parent_dir.join(Self::next_file()))
    }

    pub fn path(&self) -> &Path {
        self.0.as_path()
    }

    fn next_file() -> String {
        format!("lazin_test_file_{}", next_unique_file_ext())
    }

    pub fn file(&self) -> File {
        fs::OpenOptions::new()
            .write(true)
            .read(true)
            .open(&self.0)
            .expect("an open test file")
    }
}

impl Drop for TempFilepath {
    fn drop(&mut self) {
        let _ = fs::remove_file(&self.0);
    }
}

pub struct TempDir(PathBuf);

impl TempDir {
    pub fn new() -> Self {
        let dir_path = env::temp_dir().join(Self::next_dir());
        fs::create_dir(&dir_path).expect("a valid temp directory path");
        Self(dir_path)
    }

    pub fn path(&self) -> &Path {
        self.0.as_path()
    }

    fn next_dir() -> String {
        format!("lazin_test_dir_{}", next_unique_file_ext())
    }
}

impl Drop for TempDir {
    fn drop(&mut self) {
        let _ = fs::remove_dir_all(&self.0);
    }
}