1use serde::de::DeserializeOwned;
2use serde::Serialize;
3
4use crate::error::{DocError, Result};
5use crate::iterator::DocDbIterator;
6use crate::serialization::{SerializationMethod, Serializer};
7use std::fs;
8use std::time::{SystemTime, UNIX_EPOCH};
9use std::{
10 collections::HashMap,
11 path::{Path, PathBuf},
12 time::{Duration, Instant},
13};
14
15pub enum DumpPolicy {
17 NeverDump,
19 AutoDump,
20 DumpRelyRequest,
21 PeriodicDump(Duration),
22}
23
24pub struct DocDb {
25 map: HashMap<String, Vec<u8>>,
27 serializer: Serializer,
28 db_file_path: PathBuf,
29 dump_policy: DumpPolicy,
30 last_dump: Instant,
31}
32
33impl DocDb {
34 pub fn new<P: AsRef<Path>>(
35 db_path: P,
36 dump_policy: DumpPolicy,
37 serialize_method: SerializationMethod,
38 ) -> Self {
39 let mut path_buf = PathBuf::new();
40 path_buf.push(db_path);
41
42 Self {
43 map: HashMap::new(),
44 serializer: Serializer::new(serialize_method),
45 db_file_path: path_buf,
46 dump_policy: dump_policy,
47 last_dump: Instant::now(),
48 }
49 }
50
51 #[cfg(feature = "json")]
52 pub fn new_json<P: AsRef<Path>>(db_path: P, dump_policy: DumpPolicy) -> Self {
53 DocDb::new(db_path, dump_policy, SerializationMethod::Json)
54 }
55
56 #[cfg(feature = "yaml")]
57 pub fn new_yaml<P: AsRef<Path>>(db_path: P, dump_policy: DumpPolicy) -> Self {
58 DocDb::new(db_path, dump_policy, SerializationMethod::Yaml)
59 }
60
61 #[cfg(feature = "bincode")]
62 pub fn new_bincode<P: AsRef<Path>>(db_path: P, dump_policy: DumpPolicy) -> Self {
63 DocDb::new(db_path, dump_policy, SerializationMethod::Bin)
64 }
65
66 pub fn load<P: AsRef<Path>>(
67 db_path: P,
68 dump_policy: DumpPolicy,
69 ser_method: SerializationMethod,
70 ) -> Result<DocDb> {
71 let content = match fs::read(db_path.as_ref()) {
72 Ok(file_content) => file_content,
73 Err(err) => return Err(DocError::IO(err)),
74 };
75
76 let serializer = Serializer::new(ser_method);
77
78 let maps_from_file = match serializer.deserialize_db(&content) {
79 Ok(maps) => maps,
80 Err(err) => return Err(err),
81 };
82
83 let mut db_path_buf = PathBuf::new();
84 db_path_buf.push(db_path);
85
86 Ok(DocDb {
87 map: maps_from_file,
88 serializer,
89 db_file_path: db_path_buf,
90 dump_policy,
91 last_dump: Instant::now(),
92 })
93 }
94
95 pub fn load_read_only<P: AsRef<Path>>(
96 db_path: P,
97 serialization_method: SerializationMethod,
98 ) -> Result<DocDb> {
99 DocDb::load(db_path, DumpPolicy::NeverDump, serialization_method)
100 }
101
102 #[cfg(feature = "json")]
103 pub fn load_json<P: AsRef<Path>>(db_path: P, dump_policy: DumpPolicy) -> Result<Self> {
104 DocDb::load(db_path, dump_policy, SerializationMethod::Json)
105 }
106
107 #[cfg(feature = "yaml")]
108 pub fn load_yaml<P: AsRef<Path>>(db_path: P, dump_policy: DumpPolicy) -> Result<Self> {
109 Self::load(db_path, dump_policy, SerializationMethod::Yaml)
110 }
111
112 #[cfg(feature = "bincode")]
113 pub fn load_bin<P: AsRef<Path>>(db_path: P, dump_policy: DumpPolicy) -> Result<Self> {
114 Self::load(db_path, dump_policy, SerializationMethod::Bin)
115 }
116
117 pub fn dump(&mut self) -> Result<()> {
118 if let DumpPolicy::NeverDump = self.dump_policy {
119 return Ok(());
120 }
121
122 match self.serializer.serialize_db(&self.map) {
123 Ok(ser_data) => {
124 let temp_file_path = format!(
125 "{}.temp.{}",
126 self.db_file_path.to_str().unwrap(),
127 SystemTime::now()
128 .duration_since(UNIX_EPOCH)
129 .unwrap()
130 .as_secs()
131 );
132
133 fs::write(&temp_file_path, ser_data)?;
134 fs::rename(temp_file_path, &self.db_file_path)?;
140 if let DumpPolicy::PeriodicDump(_dur) = self.dump_policy {
146 self.last_dump = Instant::now();
147 }
148 Ok(())
149 }
150 Err(err) => Err(err),
151 }
152 }
153
154 pub fn dump_now(&mut self) -> Result<()> {
155 match self.dump_policy {
156 DumpPolicy::AutoDump => self.dump(),
157 DumpPolicy::PeriodicDump(duration) => {
158 if Instant::now().duration_since(self.last_dump) > duration {
160 self.last_dump = Instant::now();
161 self.dump()?;
162 }
163 Ok(())
164 }
165 _ => Ok(()),
166 }
167 }
168
169 pub fn set<T: Serialize>(&mut self, key: &str, val: &T) -> Result<()> {
170 let ser_data = match self.serializer.serialize_data(val) {
171 Ok(data) => data,
172 Err(err) => return Err(err),
173 };
174
175 let original_val = self.map.insert(key.to_string(), ser_data);
176
177 match self.dump_now() {
178 Ok(_) => Ok(()),
179 Err(err) => {
181 match original_val {
182 None => self.map.remove(key),
184 Some(orig_val) => self.map.insert(String::from(key), orig_val.to_vec()),
186 };
187
188 Err(err)
189 }
190 }
191 }
192
193 pub fn get<T: DeserializeOwned>(&self, key: &str) -> Option<T> {
194 match self.map.get(key) {
195 Some(v) => self.serializer.deserialize_data(v),
196 None => None,
197 }
198 }
199
200 pub fn exist(&self, key: &str) -> bool {
201 self.map.get(key).is_some()
202 }
203
204 pub fn get_all_keys(&self) -> Vec<String> {
209 self.map.keys().cloned().collect()
210 }
211
212 pub fn total_nums(&self) -> usize {
214 self.map.len()
215 }
216
217 pub fn rem(&mut self, key: &str) -> Result<bool> {
218 let remove_map = match self.map.remove(key) {
219 Some(v) => match self.dump_now() {
221 Ok(_) => Some(v),
223 Err(err) => {
225 self.map.insert(key.to_string(), v);
226 return Err(err);
227 }
228 },
229 None => None,
230 };
231
232 Ok(remove_map.is_some())
233 }
234
235 pub fn iter(&self) -> DocDbIterator {
236 DocDbIterator {
237 map_iter: self.map.iter(),
238 serializer: &self.serializer,
239 }
240 }
241}
242
243impl Drop for DocDb {
244 fn drop(&mut self) {
245 if !matches!(
246 self.dump_policy,
247 DumpPolicy::NeverDump | DumpPolicy::DumpRelyRequest
248 ) {
249 let _ = self.dump();
250 }
251 }
252}