1use serde::{Deserialize, Serialize};
2use std::fs::{read_to_string, File};
3use std::io::Read;
4use std::path::PathBuf;
5
6pub trait Persist: for<'a> Deserialize<'a> + Serialize {
7 fn name(&self) -> String;
8 fn dir_name() -> String;
9
10 fn dir() -> PathBuf {
11 let p = home::home_dir()
12 .unwrap()
13 .join(format!(".local/share/{}", Self::dir_name()));
14 std::fs::create_dir_all(p.as_path()).unwrap();
15 p
16 }
17
18 fn path(&self) -> PathBuf {
19 let mut x = Self::dir().join(self.name());
20 x.set_extension("toml");
21 x
22 }
23
24 fn save(&self) {
25 std::fs::create_dir_all(Self::dir()).unwrap();
26 let s = toml::to_string(self).unwrap();
27 std::fs::write(self.path().as_path(), s).unwrap();
28 }
29
30 fn delete(self) {
31 std::fs::remove_file(self.path()).unwrap();
32 }
33
34 fn open(&self) {
35 std::process::Command::new("open")
36 .arg(self.path())
37 .status()
38 .expect("Failed to open file");
39 }
40
41 fn load_all() -> Vec<Self> {
42 let mut instances = Vec::new();
43 let paths = std::fs::read_dir(Self::dir()).expect("Failed to read directory");
44
45 for path in paths {
46 let path = path.expect("Failed to read path").path();
47 if path.extension().map(|ext| ext == "toml").unwrap_or(false) {
48 let mut file = File::open(&path).expect("Failed to open file");
49 let mut contents = String::new();
50 file.read_to_string(&mut contents)
51 .expect("Failed to read file");
52
53 if let Ok(instance) = toml::from_str(&contents) {
54 instances.push(instance);
55 }
56 }
57 }
58
59 instances
60 }
61}
62
63pub trait SingletonPersist: for<'a> Deserialize<'a> + Serialize + Default {
66 fn name() -> String;
67 fn dir_name() -> String;
68 fn save(&self) {
69 std::fs::create_dir_all(Self::dir()).unwrap();
70 let s = toml::to_string(self).unwrap();
71 std::fs::write(Self::path().as_path(), s).unwrap();
72 }
73
74 fn delete(self) {
75 std::fs::remove_file(Self::path()).unwrap();
76 }
77
78 fn open() {
79 std::process::Command::new("open")
80 .arg(Self::path())
81 .status()
82 .expect("Failed to open file");
83 }
84
85 fn dir() -> PathBuf {
86 let p = home::home_dir()
87 .unwrap()
88 .join(format!(".local/share/{}", Self::dir_name()));
89 std::fs::create_dir_all(p.as_path()).unwrap();
90 p
91 }
92
93 fn path() -> PathBuf {
94 let mut x = Self::dir().join(Self::name());
95 x.set_extension("toml");
96 x
97 }
98
99 fn load() -> Self {
100 let path = Self::path();
101 if !path.exists() {
102 Self::default().save();
103 }
104 let content = read_to_string(path).unwrap();
105 toml::from_str(content.as_str()).unwrap()
106 }
107}