auto_delete_path/
lib.rs

1//! A super small crate which contains [AutoDeletePath](struct.AutoDeletePath.html),
2//! a path which gets automatically deleted when it goes out of scope.
3//!
4//! # Examples
5//! ```
6//! {
7//!     let tmp_path = auto_delete_path::AutoDeletePath::temp(); // creates a new path at the default temp folder
8//!     std::fs::create_dir(&tmp_path); // AutoDeletePath implements AsRef<Path>
9//!     let subfile = tmp_path.as_ref().join("subfile"); // create a subfile
10//!     std::fs::File::create(&subfile).unwrap();
11//! } // tmp_path dies here, so the directory and its contents will be deleted
12//!```
13//!
14//! See [AutoDeletePath](struct.AutoDeletePath.html) and [include_to_auto_delete_path](macro.include_to_auto_delete_path.html)
15//! for more examples.
16
17use std::path::{Path, PathBuf};
18
19/// Macro for including a source file, and writing it to a new `AutoDeletePath::temp`.
20///
21/// Useful for testing.
22///
23/// # Panics
24///
25/// Panics if writing to the tempfile fails.
26///
27/// # Example
28///
29/// ```
30/// let tmp_path = auto_delete_path::include_to_auto_delete_path!("test-resources/test-include.txt");
31/// assert_eq!(std::fs::read_to_string(&tmp_path).unwrap(), "Included file!\n");
32/// ```
33#[macro_export]
34macro_rules! include_to_auto_delete_path {
35    ($file:expr) => {{
36        use std::io::Write;
37
38        let tmp_path = $crate::AutoDeletePath::temp();
39        let file_bytes = include_bytes!($file);
40        let mut file = std::fs::File::create(&tmp_path).unwrap();
41        file.write_all(file_bytes).unwrap();
42        tmp_path
43    }};
44}
45
46/// This struct simply holds an instance of `std::path::PathBuf`.
47/// However, when such an instance goes out of scope and is destroyed, its destructor will be called,
48/// which attempts to delete the owned path (either file or directory).
49///
50/// This works even if the program panics.
51///
52/// Useful for creating temporary files that you want to be deleted automatically.
53#[derive(Debug)]
54pub struct AutoDeletePath {
55    path: PathBuf,
56}
57
58impl AutoDeletePath {
59    /// Creates an AutoDeletePath in the default temp directory.
60    /// This method just returns a path; If you want to actually make a file or folder,
61    /// you have to do that manually.
62    ///
63    /// # Examples
64    ///
65    /// File:
66    /// ```
67    /// let mut temp_path_clone = std::path::PathBuf::new();
68    /// {
69    ///     let temp_path = auto_delete_path::AutoDeletePath::temp();
70    ///
71    ///     temp_path_clone = temp_path.as_ref().to_owned();
72    ///     assert!(!temp_path_clone.exists());
73    ///     std::fs::write(&temp_path, "spam").unwrap();
74    ///     assert!(temp_path_clone.exists());
75    /// } // temp_path dies here, so the file is deleted
76    /// assert!(!temp_path_clone.exists());
77    /// ```
78    ///
79    /// Directory:
80    /// ```
81    /// let mut temp_path_clone = std::path::PathBuf::new();
82    /// {
83    ///     let temp_path = auto_delete_path::AutoDeletePath::temp();
84    ///     temp_path_clone = temp_path.as_ref().to_owned();
85    ///     assert!(!temp_path_clone.exists());
86    ///     std::fs::create_dir(&temp_path).unwrap();
87    ///     assert!(temp_path_clone.exists());
88    /// } // temp_path dies here, so the directory is deleted
89    /// assert!(!temp_path_clone.exists());
90    /// ```
91    pub fn temp() -> Self {
92        Self {
93            path: create_temp_path(),
94        }
95    }
96}
97
98impl std::convert::AsRef<Path> for AutoDeletePath {
99    fn as_ref(&self) -> &Path {
100        &self.path
101    }
102}
103
104impl Drop for AutoDeletePath {
105    fn drop(&mut self) {
106        if self.path.is_dir() {
107            std::fs::remove_dir_all(&self.path).ok();
108        } else {
109            std::fs::remove_file(&self.path).ok();
110        }
111    }
112}
113
114/// Creates a random path at the default temp directory (usually /tmp).
115fn create_temp_path() -> PathBuf {
116    create_temp_path_at_directory(std::env::temp_dir())
117}
118
119/// Creates a random path at the specified directory.
120fn create_temp_path_at_directory<P: AsRef<Path>>(directory: P) -> PathBuf {
121    PathBuf::from(format!(
122        "{}/rustytemp-{}",
123        directory.as_ref().display(),
124        fastrand::u64(..)
125    ))
126}