forked from transact-rs/sqlx
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcache.rs
More file actions
97 lines (79 loc) · 2.42 KB
/
Copy pathcache.rs
File metadata and controls
97 lines (79 loc) · 2.42 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
use std::path::{Path, PathBuf};
use std::sync::Mutex;
use std::time::SystemTime;
/// A cached value derived from one or more files, which is automatically invalidated
/// if the modified-time of any watched file changes.
pub struct MtimeCache<T> {
inner: Mutex<Option<MtimeCacheInner<T>>>,
}
pub struct MtimeCacheBuilder {
file_mtimes: Vec<(PathBuf, Option<SystemTime>)>,
}
struct MtimeCacheInner<T> {
builder: MtimeCacheBuilder,
cached: T,
}
impl<T: Clone> MtimeCache<T> {
pub fn new() -> Self {
MtimeCache {
inner: Mutex::new(None),
}
}
/// Get the cached value, or (re)initialize it if it does not exist or a file's mtime has changed.
pub fn get_or_try_init<E>(
&self,
init: impl FnOnce(&mut MtimeCacheBuilder) -> Result<T, E>,
) -> Result<T, E> {
let mut inner = self.inner.lock().unwrap_or_else(|e| {
// Reset the cache on-panic.
let mut locked = e.into_inner();
*locked = None;
locked
});
if let Some(inner) = &*inner {
if !inner.builder.any_modified() {
return Ok(inner.cached.clone());
}
}
let mut builder = MtimeCacheBuilder::new();
let value = init(&mut builder)?;
*inner = Some(MtimeCacheInner {
builder,
cached: value.clone(),
});
Ok(value)
}
}
impl MtimeCacheBuilder {
fn new() -> Self {
MtimeCacheBuilder {
file_mtimes: Vec::new(),
}
}
/// Add a file path to watch.
///
/// The cached value will be automatically invalidated if the modified-time of the file changes,
/// or if the file does not exist but is created sometime after this call.
pub fn add_path(&mut self, path: PathBuf) {
let mtime = get_mtime(&path);
#[cfg(any(sqlx_macros_unstable, procmacro2_semver_exempt))]
{
proc_macro::tracked::path(&path);
}
self.file_mtimes.push((path, mtime));
}
fn any_modified(&self) -> bool {
for (path, expected_mtime) in &self.file_mtimes {
let actual_mtime = get_mtime(path);
if expected_mtime != &actual_mtime {
return true;
}
}
false
}
}
fn get_mtime(path: &Path) -> Option<SystemTime> {
std::fs::metadata(path)
.and_then(|metadata| metadata.modified())
.ok()
}