use crate::{
AtomicWriteExt as _, Dimension, Environment, WallSwitchError, WallSwitchResult, get_config_path,
};
use serde::{Deserialize, Serialize};
use std::{
collections::HashMap,
fs,
io::{BufWriter, Write},
path::PathBuf,
};
const MAX_ITENS: usize = 10_000;
#[derive(Debug, Serialize, Deserialize, Default, Clone)]
pub struct CacheEntry {
pub size: u64,
pub mtime: u64,
pub hash: String,
#[serde(default)]
pub dimension: Option<Dimension>,
}
#[derive(Debug, Serialize, Deserialize, Default)]
pub struct State {
pub history: Vec<PathBuf>,
pub hashes: HashMap<PathBuf, CacheEntry>,
}
impl State {
pub fn load(env: &Environment) -> Self {
if let Ok(path) = Self::get_path(env)
&& let Ok(content) = fs::read_to_string(&path)
&& let Ok(state) = serde_json::from_str(&content)
{
return state;
}
State::default()
}
pub fn save(&mut self, env: &Environment) -> WallSwitchResult<()> {
if self.history.len() > MAX_ITENS {
let start = self.history.len() - MAX_ITENS;
self.history = self.history[start..].to_vec();
}
let path = Self::get_path(env)?;
path.atomic_write(|temp_path| {
let file =
fs::File::create(temp_path).map_err(|io_error| WallSwitchError::IOError {
path: temp_path.to_path_buf(),
io_error,
})?;
let mut writer = BufWriter::new(file);
serde_json::to_writer_pretty(&mut writer, self)?;
writer.flush()?;
Ok(())
})?;
Ok(())
}
pub fn garbage_collect(&mut self) {
self.hashes.retain(|path, _| path.exists());
self.hashes.shrink_to_fit();
}
fn get_path(env: &Environment) -> WallSwitchResult<PathBuf> {
let mut path = get_config_path(env)?;
path.set_file_name("wallswitch-state.json");
Ok(path)
}
}