-
Notifications
You must be signed in to change notification settings - Fork 461
Expand file tree
/
Copy pathtemp.rs
More file actions
154 lines (134 loc) · 3.61 KB
/
Copy pathtemp.rs
File metadata and controls
154 lines (134 loc) · 3.61 KB
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#![allow(static_mut_refs)] // FIXME: use appropriate std types for `FILES` and `DIRS`.
use std::fs;
use std::path::{Path, PathBuf};
use crate::errors::Result;
// open temporary directories and files so we ensure we cleanup on exit.
static mut FILES: Vec<tempfile::NamedTempFile> = vec![];
static mut DIRS: Vec<tempfile::TempDir> = vec![];
fn data_dir() -> Option<PathBuf> {
directories::BaseDirs::new().map(|d| d.data_dir().to_path_buf())
}
pub fn dir() -> Result<PathBuf> {
data_dir()
.map(|p| p.join("cross-rs").join("tmp"))
.ok_or(eyre::eyre!("unable to get data directory"))
}
pub(crate) fn has_tempfiles() -> bool {
// SAFETY: safe, since we only check if the stack is empty.
#[allow(static_mut_refs)]
unsafe {
!FILES.is_empty() || !DIRS.is_empty()
}
}
/// # Safety
/// Safe as long as we have single-threaded execution.
pub(crate) unsafe fn clean() {
// don't expose FILES or DIRS outside this module,
// so we can only add or remove from the stack using
// our wrappers, guaranteeing add/remove in order.
#[allow(static_mut_refs)]
unsafe {
FILES.clear();
}
#[allow(static_mut_refs)]
unsafe {
DIRS.clear();
}
}
/// # Safety
/// Safe as long as we have single-threaded execution.
unsafe fn push_tempfile() -> Result<&'static mut tempfile::NamedTempFile> {
let parent = dir()?;
fs::create_dir_all(&parent).ok();
let file = tempfile::NamedTempFile::new_in(&parent)?;
#[allow(static_mut_refs)]
unsafe {
FILES.push(file);
}
#[allow(static_mut_refs)]
unsafe {
Ok(FILES.last_mut().expect("file list should not be empty"))
}
}
/// # Safety
/// Safe as long as we have single-threaded execution.
unsafe fn pop_tempfile() -> Option<tempfile::NamedTempFile> {
#[allow(static_mut_refs)]
unsafe {
FILES.pop()
}
}
#[derive(Debug)]
pub struct TempFile {
file: &'static mut tempfile::NamedTempFile,
}
impl TempFile {
/// # Safety
/// Safe as long as we have single-threaded execution.
pub unsafe fn new() -> Result<Self> {
Ok(Self {
file: unsafe { push_tempfile()? },
})
}
pub fn file(&mut self) -> &mut tempfile::NamedTempFile {
self.file
}
#[must_use]
pub fn path(&self) -> &Path {
self.file.path()
}
}
impl Drop for TempFile {
fn drop(&mut self) {
// SAFETY: safe if we only modify the stack via `TempFile`.
unsafe {
pop_tempfile();
}
}
}
/// # Safety
/// Safe as long as we have single-threaded execution.
unsafe fn push_tempdir() -> Result<&'static Path> {
let parent = dir()?;
fs::create_dir_all(&parent).ok();
let dir = tempfile::TempDir::new_in(&parent)?;
#[allow(static_mut_refs)]
unsafe {
DIRS.push(dir);
}
#[allow(static_mut_refs)]
Ok(unsafe { DIRS.last().expect("should not be empty").path() })
}
/// # Safety
/// Safe as long as we have single-threaded execution.
unsafe fn pop_tempdir() -> Option<tempfile::TempDir> {
#[allow(static_mut_refs)]
unsafe {
DIRS.pop()
}
}
#[derive(Debug)]
pub struct TempDir {
path: &'static Path,
}
impl TempDir {
/// # Safety
/// Safe as long as we have single-threaded execution.
pub unsafe fn new() -> Result<Self> {
Ok(Self {
path: unsafe { push_tempdir()? },
})
}
#[must_use]
pub fn path(&self) -> &'static Path {
self.path
}
}
impl Drop for TempDir {
fn drop(&mut self) {
// SAFETY: safe if we only modify the stack via `TempDir`.
unsafe {
pop_tempdir();
}
}
}