ephemeral_dir/
lib.rs

1use std::fs;
2use std::path::{Path, PathBuf};
3
4pub struct EphemeralDir {
5    // TODO: should we use a Box<Path> here instead of PathBuf?
6    path: PathBuf,
7}
8
9impl EphemeralDir {
10    pub fn new(path: impl AsRef<Path>) -> eyre::Result<Self> {
11        let path = path.as_ref();
12        assert!(!path.exists());
13
14        fs::create_dir_all(path)?;
15
16        Ok(Self {
17            path: PathBuf::from(path),
18        })
19    }
20
21    pub fn new_forced(path: impl AsRef<Path>) -> eyre::Result<Self> {
22        let path = path.as_ref();
23        if path.exists() {
24            fs::remove_dir_all(path)?;
25        }
26
27        Self::new(path)
28    }
29
30    pub fn path(&self) -> &Path {
31        self.path.as_ref()
32    }
33}
34
35impl Drop for EphemeralDir {
36    fn drop(&mut self) {
37        let _ = fs::remove_dir_all(self.path());
38    }
39}
40
41#[test]
42fn test_dir_exists_after_creation() {
43    let path = "/tmp/ephemeral_dir_test";
44    let res_dir = EphemeralDir::new_forced(path);
45    assert!(res_dir.is_ok());
46    let Ok(dir) = res_dir else { unreachable!() };
47    assert!(dir.path().exists());
48    let dir_path_str = format!("{}", dir.path().display());
49    assert_eq!(dir_path_str, path);
50}
51
52#[test]
53fn test_dir_does_not_exist_after_going_out_of_scope() {
54    let path = "/tmp/ephemeral_dir_test";
55    let res_dir = EphemeralDir::new_forced(path);
56    assert!(res_dir.is_ok());
57    {
58        let Ok(dir) = res_dir else { unreachable!() };
59        assert!(dir.path().exists());
60        let dir_path_str = format!("{}", dir.path().display());
61        assert_eq!(dir_path_str, path);
62        let dir_path = Path::new(&dir_path_str);
63        assert!(dir_path.exists());
64    }
65    let path_path = Path::new(path);
66    assert!(!path_path.exists());
67}