1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
extern crate rand;
use std::{env, fs};
use std::io::{Error, ErrorKind, Result};
use std::path::{Path, PathBuf};
pub struct Directory {
path: PathBuf,
removed: bool,
}
impl Directory {
#[inline]
pub fn new(prefix: &str) -> Result<Directory> {
Directory::new_in(env::temp_dir(), prefix)
}
pub fn new_in<T: AsRef<Path>>(root: T, prefix: &str) -> Result<Directory> {
use rand::Rng;
const RETRIES: u32 = 1 << 31;
const CHARS: usize = 12;
let root = root.as_ref();
if !root.is_absolute() {
let current = try!(env::current_dir());
return Directory::new_in(current.join(root), prefix);
}
let mut generator = rand::thread_rng();
for _ in 0..RETRIES {
let suffix: String = generator.gen_ascii_chars().take(CHARS).collect();
let path = if prefix.is_empty() {
root.join(&suffix)
} else {
root.join(&format!("{}.{}", prefix, suffix))
};
match fs::create_dir(&path) {
Ok(_) => return Ok(Directory {
path: path.to_path_buf(),
removed: false,
}),
Err(error) => match error.kind() {
ErrorKind::AlreadyExists => {},
_ => return Err(error),
},
}
}
Err(Error::new(ErrorKind::AlreadyExists, "failed to find a vacant name"))
}
#[inline]
pub fn path<'d>(&'d self) -> &'d Path {
&self.path
}
#[inline]
pub fn remove(mut self) -> Result<()> {
self.cleanup()
}
#[inline]
pub fn unwrap(mut self) -> Result<()> {
self.removed = true;
Ok(())
}
fn cleanup(&mut self) -> Result<()> {
if self.removed {
return Ok(());
}
self.removed = true;
fs::remove_dir_all(&self.path)
}
}
impl Drop for Directory {
#[inline]
fn drop(&mut self) {
let _ = self.cleanup();
}
}
#[cfg(test)]
mod tests {
use super::Directory;
#[test]
fn new() {
use std::fs;
let path = {
let directory = Directory::new("foo").unwrap();
assert!(fs::metadata(directory.path()).is_ok());
directory.path().to_path_buf()
};
assert!(fs::metadata(path).is_err());
}
}