1use std::collections::HashMap;
2use std::path::Path;
3
4use serde::{Deserialize, Serialize};
5
6const CACHE_FILE: &str = ".raudit-cache.json";
7
8#[derive(Debug, Serialize, Deserialize)]
9pub struct Cache {
10 version: u32,
11 files: HashMap<String, u128>,
12}
13
14impl Cache {
15 pub fn load() -> Self {
16 let content = match std::fs::read_to_string(CACHE_FILE) {
17 Ok(c) => c,
18 Err(_) => return Self::empty(),
19 };
20 serde_json::from_str(&content).unwrap_or_else(|_| Self::empty())
21 }
22
23 pub fn save(&self) {
24 if let Ok(content) = serde_json::to_string_pretty(self) {
25 let _ = std::fs::write(CACHE_FILE, content);
26 }
27 }
28
29 fn empty() -> Self {
30 Self {
31 version: 1,
32 files: HashMap::new(),
33 }
34 }
35
36 pub fn is_unchanged_clean(&self, path: &Path) -> bool {
37 let path_str = path.to_string_lossy().to_string();
38 match self.files.get(&path_str) {
39 Some(&cached_mtime) => cached_mtime == mtime_nanos(path).unwrap_or(0),
40 None => false,
41 }
42 }
43
44 pub fn mark_clean(&mut self, path: &Path) {
45 if let Some(mtime) = mtime_nanos(path) {
46 self.files.insert(path.to_string_lossy().to_string(), mtime);
47 }
48 }
49
50 pub fn mark_dirty(&mut self, path: &Path) {
51 self.files.remove(&path.to_string_lossy().to_string());
52 }
53}
54
55fn mtime_nanos(path: &Path) -> Option<u128> {
56 let meta = std::fs::metadata(path).ok()?;
57 let mtime = meta.modified().ok()?;
58 Some(mtime.duration_since(std::time::UNIX_EPOCH).ok()?.as_nanos())
59}