easy_safe/
mapenv.rs

1use std::collections::HashMap;
2use std::fs::File;
3use std::io::{Read, Write};
4
5use serde::{Deserialize, Serialize};
6
7pub struct PersistenceEnv {
8    name: String,
9}
10
11impl PersistenceEnv {
12    pub fn save_to_local(&self, to_save: &str) {
13        let mut file = File::create(&self.name).unwrap();
14        file.write_all(to_save.as_bytes()).expect("could not write");
15    }
16
17    pub fn load_from_local(&self) -> String {
18        let mut file = File::open(&self.name).unwrap();
19        let mut contents = String::new();
20        file.read_to_string(&mut contents).expect("could not read");
21        contents
22    }
23
24    pub fn init_env(&self, with: &str) {
25        if File::open(&self.name).is_ok() {} else {
26            let mut file = File::create(&self.name).unwrap();
27            file.write_all(with.as_bytes()).expect("could not write");
28
29            let mut file = File::open(&self.name).unwrap();
30            let mut contents = String::new();
31            file.read_to_string(&mut contents).expect("could not read");
32        }
33    }
34}
35
36/// creates a "environment" on the disk, it just wraps writing and reading from a file
37pub fn env_default_at(name: &str) -> PersistenceEnv {
38    PersistenceEnv {
39        name: name.parse().unwrap()
40    }
41}
42
43
44pub mod disk_pers {
45    use std::collections::HashMap;
46
47    use crate::mapenv::{env_default_at, MapWrapper, PersistenceEnv};
48
49    pub struct MapEnv {
50        inner: MapWrapper,
51        env: PersistenceEnv,
52    }
53
54    impl MapEnv {
55        /// put will first try to load the newest file,
56        /// puts the value into the in memory map and then saves the map to disk
57        /// also returns the value
58        pub fn put(&mut self, key: &str, value: &str) -> Option<String> {
59            self.update_inner();
60            let value = self.inner.inner.insert(
61                key.parse().unwrap(),
62                value.parse().unwrap()
63            );
64            self.update_outer();
65            value
66        }
67
68        /// deletes the value in the in memory map and then saves the map to disk
69        /// and also returns the value
70        pub fn delete(&mut self, key: &str) {
71            self.inner.inner.remove(key);
72            self.update_outer();
73        }
74
75        /// get trys to load the map from disk and then attempts to get the value from the in memory map
76        pub fn get(&mut self, key: &str) -> Option<&String> {
77            self.update_inner();
78            self.inner.inner.get(&*key)
79        }
80
81        fn update_inner(&mut self) {
82            let from_file = self.env.load_from_local();
83
84            let map: MapWrapper = serde_json::from_str(&*from_file).unwrap();
85            for (key, value) in &map.inner {
86                self.inner.inner.insert(key.clone(), value.clone());
87            }
88        }
89
90        fn update_outer(&mut self) {
91            let serialized = serde_json::to_string(&self.inner);
92            self.env.save_to_local(&*serialized.unwrap())
93        }
94
95        /// returns the name of the inner environment
96        pub(crate) fn get_name(&self) -> &String { &self.env.name }
97    }
98
99
100    /// creates a new map environment with the specified name
101    /// the name corresponds to the file saved and loaded in your filesystem
102    /// If the file is already there it will load from that file
103    ///
104    /// This means you can always come back and access your file if you call it with the right name
105    ///
106    /// # Examples
107    ///```
108    ///  use easy_safe::{create_or_load_map_env, MapEnv};
109    ///  let mut  map_env: MapEnv = create_or_load_map_env("somename");
110    ///  map_env.put("somekey", "somevalue");
111    ///  let value = map_env.get("somekey").unwrap();
112    ///  assert_eq!(value, "somevalue");
113    ///
114    ///  let mut  same_file_map_env: MapEnv = create_or_load_map_env("somename");
115    ///  let also_the_value = same_file_map_env.get("somekey").unwrap();
116    ///  assert_eq!(value, "somevalue");
117    ///```
118    pub fn create_or_load_map_env(name: &str) -> MapEnv {
119        let pers_env = env_default_at(name);
120
121        let map_wrapper = MapWrapper {
122            inner: HashMap::new()
123        };
124        pers_env.init_env(&serde_json::to_string(&map_wrapper).unwrap());
125        MapEnv {
126            inner: map_wrapper,
127            env: pers_env,
128        }
129    }
130    pub struct LateSaveMapEnv {
131        inner: MapWrapper,
132        env: PersistenceEnv,
133    }
134
135    impl LateSaveMapEnv {
136
137        /// put will first try to load the newest file,
138        /// puts the value into the in memory map
139        /// also returns the value
140        pub fn put(&mut self, key: &str, value: &str) -> Option<String> {
141            self.update_inner();
142            let value = self.inner.inner.insert(
143                key.parse().unwrap(),
144                value.parse().unwrap(),
145            );
146            value
147        }
148
149        /// deletes the value in the in memory map
150        /// and also returns the value
151        pub fn delete(&mut self, key: &str) {
152            self.update_inner();
153            self.inner.inner.remove(key);
154        }
155
156        /// get trys to load the map from disk and then attempts to get the value from the in memory map
157        pub fn get(&mut self, key: &str) -> Option<&String> {
158            self.update_inner();
159            self.inner.inner.get(&*key)
160        }
161
162        fn update_inner(&mut self) {
163            let from_file = self.env.load_from_local();
164
165            let map: MapWrapper = serde_json::from_str(&*from_file).unwrap();
166            for (key, value) in &map.inner {
167                self.inner.inner.insert(key.clone(), value.clone());
168            }
169        }
170
171        pub fn save(&mut self) {
172            let serialized = serde_json::to_string(&self.inner);
173            self.env.save_to_local(&*serialized.unwrap())
174        }
175
176        /// returns the name of the inner environment
177        pub(crate) fn get_name(&self) -> &String { &self.env.name }
178
179    }
180
181    /// creates a new map environment with the specified name that does not save everytime
182    /// an operation is done on the map
183    /// the name corresponds to the file saved and loaded in your filesystem
184    /// If the file is already there it will load from that file
185    ///
186    /// This means you can always come back and access your file if you call it with the right name
187    ///
188    /// # Examples
189    ///```
190    ///  use easy_safe::{create_or_load_late_save_map_env, LateSaveMapEnv};
191    ///  let mut  map_env: LateSaveMapEnv = create_or_load_late_save_map_env("somename");
192    ///  map_env.put("somekey", "somevalue");
193    ///  map_env.save();
194    ///
195    ///  let mut  same_file_map_env: LateSaveMapEnv = create_or_load_late_save_map_env("somename");
196    ///  let also_the_value = same_file_map_env.get("somekey").unwrap();
197    ///  assert_eq!(also_the_value, "somevalue");
198    ///```
199    pub fn create_or_load_late_save_map_env(name: &str) -> LateSaveMapEnv {
200        let pers_env = env_default_at(name);
201
202        let map_wrapper = MapWrapper {
203            inner: HashMap::new()
204        };
205        pers_env.init_env(&serde_json::to_string(&map_wrapper).unwrap());
206        LateSaveMapEnv {
207            inner: map_wrapper,
208            env: pers_env,
209        }
210    }
211}
212
213/// the wrapping struct to the map, this is what will be saved as json on the disk
214/// this is mostly to not break interfaces and it should make it always possible
215/// to load old files if needed
216#[derive(Serialize, Deserialize)]
217struct MapWrapper {
218    inner: HashMap<String, String>,
219}