odds/persistence/
persistable.rs1use anyhow::{Context, Ok};
2use serde::{Serialize, de::DeserializeOwned};
3use std::{fs, path::PathBuf};
4
5use crate::paths;
6
7pub trait Persistable: Serialize + DeserializeOwned + Sized {
8 const FILE: &'static str;
9
10 fn before_save(&mut self) {}
11
12 fn save(&mut self) -> anyhow::Result<()> {
13 self.before_save();
15
16 let path = Self::path();
17
18 if let Some(parent) = path.parent() {
19 fs::create_dir_all(parent)
20 .with_context(|| format!("Failed to create directory structure: {:?}", parent))?;
21 }
22
23 let contents = serde_json::to_string_pretty(self).with_context(|| "Failed to serialise data to JSON.")?;
24
25 fs::write(&path, contents).with_context(|| format!("Failed to write persistence file to {:?}", path))?;
26
27 Ok(())
28 }
29
30 fn load() -> anyhow::Result<Self> {
31 let path = Self::path();
32
33 let data = fs::read_to_string(&path).with_context(|| format!("Failed to read file: {:?}", path))?;
34 let result: Self =
35 serde_json::from_str(&data).with_context(|| format!("Failed to deserialise {}.", Self::FILE))?;
36
37 Ok(result)
38 }
39
40 fn reset() {
41 let path = Self::path();
42 if let Err(e) = fs::remove_file(&path) {
43 eprintln!("Failed to remove file: {:?}: {}", path, e);
44 }
45 }
46
47 fn path() -> PathBuf {
48 paths::persistence_path(Self::FILE)
49 }
50}