1use serde::Serialize;
2use serde::de::DeserializeOwned;
3use std::fmt::Display;
4use std::ops::Deref;
5use std::path::PathBuf;
6use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
7use std::{fs, sync::Arc};
8
9#[derive(Clone, Debug)]
10pub struct Saved<T: FsTrait>(Arc<RwLock<T>>);
11
12impl<T: FsTrait> Saved<T> {
13 pub fn new(item: T) -> Self {
14 item.save();
15 Self(Arc::new(RwLock::new(item)))
16 }
17
18 pub fn load(id: T::Key) -> Option<Self> {
19 let item = T::load(id)?;
20 Some(Self(Arc::new(RwLock::new(item))))
21 }
22
23 pub fn read(&self) -> RwLockReadGuard<T> {
24 self.0.read().unwrap()
25 }
26
27 pub fn write(&self) -> MyWriteGuard<T> {
28 MyWriteGuard(self.0.write().unwrap())
29 }
30}
31
32pub struct MyWriteGuard<'a, T: FsTrait>(RwLockWriteGuard<'a, T>);
34
35impl<'a, T: FsTrait> Drop for MyWriteGuard<'a, T> {
36 fn drop(&mut self) {
37 self.save();
38 }
39}
40
41impl<'a, T: FsTrait> Deref for MyWriteGuard<'a, T> {
42 type Target = T;
43
44 fn deref(&self) -> &Self::Target {
45 &self.0
46 }
47}
48
49pub trait FsTrait
50where
51 Self: DeserializeOwned + Serialize + Sized,
52{
53 type Key: Display;
54
55 fn item_id(&self) -> Self::Key;
56
57 fn crate_name() -> String {
58 std::env::current_exe()
59 .unwrap()
60 .file_stem()
61 .unwrap()
62 .to_str()
63 .unwrap()
64 .to_string()
65 .to_lowercase()
66 }
67
68 fn root() -> PathBuf {
69 dirs::data_local_dir().unwrap().join(Self::crate_name())
70 }
71
72 fn items_path() -> PathBuf {
73 let name = std::any::type_name::<Self>();
74 let path = Self::root().join(name);
75 fs::create_dir_all(&path).unwrap();
76 path
77 }
78
79 fn item_path(&self) -> PathBuf {
80 Self::items_path().join(self.item_id().to_string())
81 }
82
83 fn load(id: Self::Key) -> Option<Self> {
84 let path = Self::items_path().join(id.to_string());
85 if !path.exists() {
86 return None;
87 }
88
89 let s: String = fs::read_to_string(&path).unwrap();
90 let t: Self = serde_json::from_str(&s).unwrap();
91 Some(t)
92 }
93
94 fn save(&self) {
95 use std::io::Write;
96
97 let path = self.item_path();
98 let s: String = serde_json::to_string(self).unwrap();
99 let mut f = fs::File::create(&path).unwrap();
100 f.write_all(&s.as_bytes()).unwrap();
101 }
102}