1use crate::{
2 AtomicWriteExt as _, Dimension, Environment, WallSwitchError, WallSwitchResult, get_config_path,
3};
4use serde::{Deserialize, Serialize};
5use std::{
6 collections::HashMap,
7 fs,
8 io::{BufWriter, Write},
9 path::PathBuf,
10};
11
12const MAX_ITENS: usize = 10_000;
13
14#[derive(Debug, Serialize, Deserialize, Default, Clone)]
16pub struct CacheEntry {
17 pub size: u64,
18 pub mtime: u64,
19 pub hash: String,
20 #[serde(default)]
21 pub dimension: Option<Dimension>,
22}
23
24#[derive(Debug, Serialize, Deserialize, Default)]
26pub struct State {
27 pub history: Vec<PathBuf>,
28 pub hashes: HashMap<PathBuf, CacheEntry>,
29}
30
31impl State {
32 pub fn load(env: &Environment) -> Self {
34 if let Ok(path) = Self::get_path(env)
35 && let Ok(content) = fs::read_to_string(&path)
36 && let Ok(state) = serde_json::from_str(&content)
37 {
38 return state;
39 }
40 State::default()
41 }
42
43 pub fn save(&mut self, env: &Environment) -> WallSwitchResult<()> {
49 if self.history.len() > MAX_ITENS {
50 let start = self.history.len() - MAX_ITENS;
51 self.history = self.history[start..].to_vec();
52 }
53
54 let path = Self::get_path(env)?;
55
56 path.atomic_write(|temp_path| {
57 let file =
58 fs::File::create(temp_path).map_err(|io_error| WallSwitchError::IOError {
59 path: temp_path.to_path_buf(),
60 io_error,
61 })?;
62 let mut writer = BufWriter::new(file);
63 serde_json::to_writer_pretty(&mut writer, self)?;
64 writer.flush()?;
65 Ok(())
66 })?;
67
68 Ok(())
69 }
70
71 pub fn garbage_collect(&mut self) {
73 self.hashes.retain(|path, _| path.exists());
74 self.hashes.shrink_to_fit();
75 }
76
77 fn get_path(env: &Environment) -> WallSwitchResult<PathBuf> {
79 let mut path = get_config_path(env)?;
80 path.set_file_name("wallswitch-state.json");
81 Ok(path)
82 }
83}