1use std::{
4 env,
5 fs::{self, File, OpenOptions, ReadDir},
6 io,
7 path::{Path, PathBuf},
8};
9
10pub struct TmpDir(PathBuf);
19
20impl TmpDir {
21 pub fn new() -> Result<Self, io::Error> {
23 let path = env::temp_dir().join(uuid::Uuid::new_v4().to_string());
24 fs::create_dir(&path)?;
25 Ok(TmpDir(path))
26 }
27
28 pub fn path(&self) -> PathBuf {
30 self.0.clone()
31 }
32
33 pub fn unique_path(&self) -> PathBuf {
35 self.0.join(uuid::Uuid::new_v4().to_string())
36 }
37
38 pub fn write_file<P, C>(&self, path: P, contents: C) -> io::Result<()>
41 where
42 P: AsRef<Path>,
43 C: AsRef<[u8]>,
44 {
45 fs::write(self.0.join(path), contents)
46 }
47
48 pub fn read_file<P>(&self, path: P) -> io::Result<Vec<u8>>
51 where
52 P: AsRef<Path>,
53 {
54 fs::read(self.0.join(path))
55 }
56
57 pub fn create_dir<P>(&self, path: P) -> io::Result<()>
60 where
61 P: AsRef<Path>,
62 {
63 fs::create_dir(self.0.join(path))
64 }
65
66 pub fn create_dir_all<P>(&self, path: P) -> io::Result<()>
69 where
70 P: AsRef<Path>,
71 {
72 fs::create_dir_all(self.0.join(path))
73 }
74
75 pub fn create_file<P>(&self, path: P) -> io::Result<File>
78 where
79 P: AsRef<Path>,
80 {
81 File::create(self.0.join(path))
82 }
83
84 pub fn open_readable<P>(&self, path: P) -> io::Result<File>
87 where
88 P: AsRef<Path>,
89 {
90 File::open(self.0.join(path))
91 }
92
93 pub fn open_writable<P>(&self, path: P) -> io::Result<File>
96 where
97 P: AsRef<Path>,
98 {
99 OpenOptions::new().write(true).open(self.0.join(path))
100 }
101
102 pub fn open_with_opts<P>(&self, opts: &mut OpenOptions, path: P) -> io::Result<File>
105 where
106 P: AsRef<Path>,
107 {
108 opts.open(self.0.join(path))
109 }
110
111 pub fn metadata<P>(&self, path: P) -> io::Result<fs::Metadata>
113 where
114 P: AsRef<Path>,
115 {
116 self.0.join(path.as_ref()).metadata()
117 }
118
119 pub fn exists<P>(&self, path: P) -> bool
122 where
123 P: AsRef<Path>,
124 {
125 self.0.join(path.as_ref()).exists()
126 }
127
128 pub fn read_dir<P>(&self, path: P) -> io::Result<ReadDir>
130 where
131 P: AsRef<Path>,
132 {
133 fs::read_dir(&self.0.join(path))
134 }
135
136 pub fn remove_file<P>(&self, path: P) -> io::Result<()>
139 where
140 P: AsRef<Path>,
141 {
142 fs::remove_file(&self.0.join(path))
143 }
144
145 pub fn remove_dir<P>(&self, path: P) -> io::Result<()>
148 where
149 P: AsRef<Path>,
150 {
151 fs::remove_dir(&self.0.join(path))
152 }
153
154 pub fn remove_dir_all<P>(&self, path: P) -> io::Result<()>
157 where
158 P: AsRef<Path>,
159 {
160 fs::remove_dir_all(&self.0.join(path))
161 }
162}
163
164impl Drop for TmpDir {
165 fn drop(&mut self) {
168 fs::remove_dir_all(&self.0).ok();
169 }
170}
171
172pub struct TmpFile(PathBuf);
177
178impl TmpFile {
179 pub fn new() -> Result<Self, io::Error> {
181 let path = env::temp_dir().join(uuid::Uuid::new_v4().to_string());
182 fs::write(&path, &[])?;
183 Ok(TmpFile(path))
184 }
185
186 pub fn path(&self) -> PathBuf {
188 self.0.clone()
189 }
190
191 pub fn write<C>(&self, contents: C) -> io::Result<()>
193 where
194 C: AsRef<[u8]>,
195 {
196 fs::write(&self.0, contents)
197 }
198
199 pub fn read(&self) -> io::Result<Vec<u8>> {
201 fs::read(&self.0)
202 }
203
204 pub fn open_readable(&self) -> io::Result<File> {
207 File::open(&self.0)
208 }
209
210 pub fn open_writable(&self) -> io::Result<File> {
212 OpenOptions::new().write(true).open(&self.0)
213 }
214
215 pub fn open_with_opts(&self, opts: &mut OpenOptions) -> io::Result<File> {
218 opts.open(&self.0)
219 }
220}
221
222impl Drop for TmpFile {
223 fn drop(&mut self) {
226 fs::remove_dir_all(&self.0).ok();
227 }
228}