1
2use std::{fs, io};
3use std::path::{Path, PathBuf};
4use std::marker::PhantomData;
5use std::fmt::Debug;
6
7extern crate serde;
8use serde::{de::DeserializeOwned, Serialize};
9
10extern crate serde_json;
11
12pub struct FileStore<V> {
14 dir: PathBuf,
15 _v: PhantomData<V>,
16}
17
18#[derive(Debug)]
19pub enum Error<E> {
20 Io(io::Error),
21 Inner(E),
22}
23
24impl <E> From<io::Error> for Error<E> {
25 fn from(e: io::Error) -> Self {
26 Error::Io(e)
27 }
28}
29
30
31impl <V, E>FileStore<V>
32where
33 V: EncodeDecode<Value=V, Error=E> + Serialize + DeserializeOwned + Debug,
34 E: Debug
35{
36 pub fn new<P: AsRef<Path>>(dir: P) -> Result<Self, Error<E>> {
38 Ok(FileStore{
39 dir: dir.as_ref().into(),
40 _v: PhantomData
41 })
42 }
43
44 pub fn list(&mut self) -> Result<Vec<String>, Error<E>> {
46 let mut names = vec![];
47
48 for entry in fs::read_dir(&self.dir)? {
49 let entry = entry?;
50 let name = entry.file_name().into_string().unwrap();
51 names.push(name);
52 }
53
54 Ok(names)
55 }
56
57 pub fn load<P: AsRef<Path>>(&mut self, name: P) -> Result<V, Error<E>> {
59 let mut path = self.dir.clone();
60 path.push(name);
61
62 let buff = fs::read(path)?;
63 let obj: V = V::decode(&buff).map_err(|e| Error::Inner(e) )?;
64
65 Ok(obj)
66 }
67
68 pub fn store<P: AsRef<Path>>(&mut self, name: P, v: &V) -> Result<(), Error<E>> {
70 let mut path = self.dir.clone();
71 path.push(name);
72
73 let bin: Vec<u8> = V::encode(v).map_err(|e| Error::Inner(e) )?;
74 fs::write(path, bin)?;
75 Ok(())
76 }
77
78 pub fn load_all(&mut self) -> Result<Vec<(String, V)>, Error<E>> {
80 let mut objs = vec![];
81
82 for entry in fs::read_dir(&self.dir)? {
83 let entry = entry?;
84 let name = entry.file_name().into_string().unwrap();
85
86 let buff = fs::read(entry.path())?;
87 let obj: V = V::decode(&buff).map_err(|e| Error::Inner(e) )?;
88
89 objs.push((name, obj));
90 }
91
92 Ok(objs)
93 }
94
95 pub fn store_all(&mut self, data: &[(String, V)]) -> Result<(), Error<E>> {
97 for (name, value) in data {
98 self.store(name, value)?;
99 }
100
101 Ok(())
102 }
103
104
105 pub fn rm<P: AsRef<Path>>(&mut self, name: P) -> Result<(), Error<E>> {
107 let mut path = self.dir.clone();
108 path.push(name);
109
110 fs::remove_file(path)?;
111
112 Ok(())
113 }
114
115}
116
117pub trait EncodeDecode {
119 type Value;
120 type Error;
121
122 fn encode(value: &Self::Value) -> Result<Vec<u8>, Self::Error>;
123 fn decode(buff: &[u8]) -> Result<Self::Value, Self::Error>;
124}
125
126impl <V> EncodeDecode for V
128where
129 V: Serialize + DeserializeOwned + Debug,
130{
131 type Value = V;
132 type Error = serde_json::Error;
133
134 fn encode(value: &Self::Value) -> Result<Vec<u8>, Self::Error> {
135 serde_json::to_vec(value)
136 }
137
138 fn decode(buff: &[u8]) -> Result<Self::Value, Self::Error> {
139 serde_json::from_slice(&buff)
140 }
141}
142
143
144#[cfg(test)]
145mod tests {
146 use std::env;
147
148 use super::*;
149
150 const N: usize = 3;
151
152 #[test]
153 fn mock_database() {
154
155 let dir = env::temp_dir();
156
157 let mut s = FileStore::new(dir).unwrap();
158
159 for i in 0..N {
160 let name = format!("{}", i);
161
162 s.store(&name, &i).unwrap();
163
164 let v = s.load(&name).unwrap();
165
166 assert_eq!(i, v);
167 }
168 }
169}