1use anyhow::Result;
21use rmp_serde::Serializer;
22use serde::de::DeserializeOwned;
23#[allow(unused_imports)]
25use serde::{Deserialize, Serialize};
26use std::collections::HashMap;
27use std::fs::{create_dir_all, metadata, read, read_dir, remove_dir, remove_file, write};
28
29pub struct PackDb<T: DeserializeOwned + Serialize> {
30 store: String,
31 #[allow(dead_code)]
33 a: Option<T>,
34}
35impl<T: DeserializeOwned + Serialize> PackDb<T> {
36 pub fn new(store: Option<String>) -> Self {
38 let loc = store.unwrap_or_else(|| "data".into());
39 create_dir_all(&loc).unwrap();
40 PackDb::<T> {
41 store: loc,
42 a: None,
43 }
44 }
45 fn path<K: std::fmt::Display>(&self, key: K) -> String {
46 format!("{}/{}.pak", &self.store, key)
47 }
48 pub fn has<K: std::fmt::Display>(&self, key: K) -> bool {
50 let exists = metadata(self.path(key));
51 exists.is_ok()
52 }
53 pub fn set<K: std::fmt::Display>(&self, key: K, val: T) -> Result<()> {
55 let mut buf = vec![];
56 val.serialize(&mut Serializer::new(&mut buf))?;
57 write(self.path(key), buf)?;
58 Ok(())
59 }
60 pub fn get<K: std::fmt::Display>(&self, key: K) -> Result<T> {
62 let r = read(self.path(key))?;
63 Ok(rmp_serde::from_read_ref(&r)?)
64 }
65
66 pub fn get_all(&self) -> Result<HashMap<String, T>> {
68 let mut res = HashMap::new();
69 let entries = read_dir(&self.store)?;
70
71 for entry in entries.flatten() {
72 let name = entry.file_name().to_string_lossy().replace(".pak", "");
73 res.insert(name.clone(), self.get(&name)?);
74 }
75
76 Ok(res)
77 }
78 pub fn keys(&self) -> Result<Vec<String>> {
80 let mut res = vec![];
81 let entries = read_dir(&self.store)?;
82 for entry in entries.flatten() {
83 let name = entry.file_name().to_string_lossy().replace(".pak", "");
84 res.push(name);
85 }
86 Ok(res)
87 }
88 pub fn len(&self) -> Result<usize> {
90 let entries = read_dir(&self.store)?;
91 Ok(entries.flatten().count())
92 }
93
94 pub fn is_empty(&self) -> Result<bool> {
96 Ok(self.len()? == 0)
97 }
98
99 pub fn insert_many<K: std::fmt::Display>(&self, data: HashMap<K, T>) -> Result<bool> {
101 for (key, val) in data {
102 self.set(key, val)?;
103 }
104 Ok(true)
105 }
106
107 pub fn delete<K: std::fmt::Display>(&self, key: K) -> bool {
109 let exists = remove_file(self.path(key));
110 exists.is_ok()
111 }
112
113 pub fn clear(&self) -> Result<bool> {
115 remove_dir(&self.store)?;
116 create_dir_all(&self.store)?;
117 Ok(true)
118 }
119
120 pub fn drain(&self) -> Result<HashMap<String, T>> {
122 let data = self.get_all();
123 self.clear()?;
124 data
125 }
126}
127
128#[cfg(test)]
129mod test {
130 #[derive(Debug, PartialEq, Deserialize, Serialize)]
131 struct Human {
132 age: u32,
133 name: String,
134 }
135
136 use super::*;
137 #[test]
138 fn test() -> Result<()> {
139 let storage = PackDb::<Human>::new(Some("store".to_owned()));
140
141 storage.set(
142 "testing",
143 Human {
144 age: 22,
145 name: "this is a test".into(),
146 },
147 )?;
148
149 let user = storage.get("testing")?;
150
151 assert_eq!(user.name, "this is a test".to_owned());
152
153 let users = storage.get_all()?;
154 let _user = users.get("testing").unwrap();
155
156 assert_eq!(storage.has("testing"), true);
157 assert_eq!(storage.delete("testing"), true);
158 assert_eq!(storage.has("testing"), false);
159 Ok(())
160 }
161}