Skip to main content

irox_tools/fs/
temp.rs

1// SPDX-License-Identifier: MIT
2// Copyright 2025 IROX Contributors
3//
4
5use crate::cfg_feature_std;
6use core::fmt::{Debug, Formatter};
7use std::path::{Path, PathBuf};
8
9pub struct TempFilePath {
10    path: PathBuf,
11}
12impl Debug for TempFilePath {
13    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
14        write!(f, "TempFile({})", self.path.display())
15    }
16}
17
18impl Drop for TempFilePath {
19    fn drop(&mut self) {
20        let _ = std::fs::remove_file(&self.path);
21    }
22}
23impl TempFilePath {
24    pub fn new<T: AsRef<Path>>(path: T) -> Self {
25        Self {
26            path: path.as_ref().into(),
27        }
28    }
29    /// Returns the temporary path.
30    pub fn get_path(&self) -> &PathBuf {
31        &self.path
32    }
33
34    cfg_feature_std! {
35        /// Creates a new temporary file with the default prefix of `.tmpirxf_`
36        /// that will be deleted when this object is dropped.
37        pub fn new_tempfile() -> Result<Self, std::io::Error> {
38            Self::new_tempfile_prefixed(".tmpirxf_")
39        }
40        /// Creates a new temporary file with the provided prefix that will be
41        /// deleted when this object is dropped.
42        pub fn new_tempfile_prefixed(prefix: &str) -> Result<Self, std::io::Error> {
43            let prefix = crate::fs::clean_filename(&prefix);
44            let tmpdir = std::env::temp_dir().join(format!("{prefix}{}", crate::uuid::UUID::new_random()));
45            let p = std::fs::OpenOptions::new()
46                .read(true)
47                .write(true)
48                .create_new(true)
49                .truncate(true)
50                .open(&tmpdir)?;
51            drop(p);
52            Ok(TempFilePath {
53                path: tmpdir
54            })
55        }
56        pub fn open(&self, opts: &std::fs::OpenOptions) -> Result<std::fs::File, std::io::Error> {
57            opts.open(&self.path)
58        }
59        pub fn open_write_buffered(&self, opts: &std::fs::OpenOptions) -> Result<std::io::BufWriter<std::fs::File>, std::io::Error> {
60            Ok(std::io::BufWriter::new(self.open(opts)?))
61        }
62        pub fn open_read_buffered(&self, opts: &std::fs::OpenOptions) -> Result<std::io::BufReader<std::fs::File>, std::io::Error> {
63            Ok(std::io::BufReader::new(self.open(opts)?))
64        }
65    }
66}
67macro_rules! impl_from {
68    ($dst:ident) => {
69        impl From<PathBuf> for $dst {
70            fn from(value: PathBuf) -> Self {
71                Self { path: value }
72            }
73        }
74        impl From<&PathBuf> for $dst {
75            fn from(value: &PathBuf) -> Self {
76                Self {
77                    path: value.clone(),
78                }
79            }
80        }
81    };
82}
83impl_from!(TempFilePath);
84pub struct TempDirPath {
85    path: PathBuf,
86}
87impl Drop for TempDirPath {
88    fn drop(&mut self) {
89        let _ = std::fs::remove_dir_all(&self.path);
90    }
91}
92impl Debug for TempDirPath {
93    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
94        write!(f, "TempDir({})", self.path.display())
95    }
96}
97impl TempDirPath {
98    pub fn new<T: AsRef<Path>>(path: T) -> Self {
99        Self {
100            path: path.as_ref().into(),
101        }
102    }
103    /// Returns the temporary path.
104    pub fn get_path(&self) -> &PathBuf {
105        &self.path
106    }
107    cfg_feature_std! {
108        /// Creates a new temporary directory that will be removed upon dropping
109        /// of this object with the default prefix of `.tmpirx_` and then a
110        /// random UUID.
111        pub fn new_temp_dir() -> Result<Self, std::io::Error> {
112            Self::new_temp_dir_prefixed(".tmpirxd_")
113        }
114        /// Creates a new temporary directory that will be removed upon dropping
115        /// of this object with the provided prefix and then a random UUID.
116        pub fn new_temp_dir_prefixed(prefix: &str) -> Result<Self, std::io::Error> {
117            let prefix = crate::fs::clean_filename(&prefix);
118            let tmpdir = std::env::temp_dir().join(format!("{prefix}{}", crate::uuid::UUID::new_random()));
119            std::fs::create_dir_all(&tmpdir)?;
120            Ok(Self {
121                path: tmpdir
122            })
123        }
124        /// Creates a new temporary file within this directory and returns the
125        /// path to that file.
126        pub fn new_temp_file(&self) -> Result<TempFilePath, std::io::Error> {
127            let f = self.path.join(crate::uuid::UUID::new_random().to_string());
128            let p = std::fs::OpenOptions::new()
129                .read(true)
130                .write(true)
131                .create_new(true)
132                .truncate(true)
133                .open(&f)?;
134            drop(p);
135            Ok(TempFilePath {
136                path: f
137            })
138        }
139
140    }
141}
142impl_from!(TempDirPath);