libimagstore/file_abstraction/
inmemory.rs1use std::path::PathBuf;
21use std::collections::HashMap;
22use std::sync::Mutex;
23use std::cell::RefCell;
24use std::sync::Arc;
25use std::ops::Deref;
26
27use libimagerror::errors::ErrorMsg as EM;
28
29use failure::Fallible as Result;
30use failure::Error;
31use failure::err_msg;
32
33use super::FileAbstraction;
34use super::FileAbstractionInstance;
35use super::Drain;
36use crate::store::Entry;
37use crate::storeid::StoreIdWithBase;
38use crate::file_abstraction::iter::PathIterator;
39use crate::file_abstraction::iter::PathIterBuilder;
40
41type Backend = Arc<Mutex<RefCell<HashMap<PathBuf, Entry>>>>;
42
43#[derive(Debug)]
47pub struct InMemoryFileAbstractionInstance {
48 fs_abstraction: Backend,
49 absent_path: PathBuf,
50}
51
52impl InMemoryFileAbstractionInstance {
53
54 pub fn new(fs: Backend, pb: PathBuf) -> InMemoryFileAbstractionInstance {
55 InMemoryFileAbstractionInstance {
56 fs_abstraction: fs,
57 absent_path: pb
58 }
59 }
60
61}
62
63impl FileAbstractionInstance for InMemoryFileAbstractionInstance {
64
65 fn get_file_content(&mut self, _: StoreIdWithBase<'_>) -> Result<Option<Entry>> {
69 debug!("Getting lazy file: {:?}", self);
70
71 self.fs_abstraction
72 .lock()
73 .map_err(|_| Error::from(EM::LockError))
74 .map(|mut mtx| {
75 mtx.get_mut()
76 .get(&self.absent_path)
77 .cloned()
78 })
79 .map_err(Error::from)
80 }
81
82 fn write_file_content(&mut self, buf: &Entry) -> Result<()> {
83 let absent_path = &self.absent_path;
84 let mut mtx = self.fs_abstraction.lock().expect("Locking Mutex failed");
85 let backend = mtx.get_mut();
86 let _ = backend.insert(absent_path.clone(), buf.clone());
87 Ok(())
88 }
89}
90
91#[derive(Debug, Default)]
92pub struct InMemoryFileAbstraction {
93 virtual_filesystem: Backend,
94}
95
96impl InMemoryFileAbstraction {
97
98 pub fn backend(&self) -> &Backend {
99 &self.virtual_filesystem
100 }
101
102 fn backend_cloned(&self) -> Result<HashMap<PathBuf, Entry>> {
103 self.virtual_filesystem
104 .lock()
105 .map_err(|_| Error::from(EM::LockError))
106 .map(|mtx| mtx.deref().borrow().clone())
107 }
108
109}
110
111impl FileAbstraction for InMemoryFileAbstraction {
112
113 fn remove_file(&self, path: &PathBuf) -> Result<()> {
114 debug!("Removing: {:?}", path);
115 self.backend()
116 .lock()
117 .expect("Locking Mutex failed")
118 .get_mut()
119 .remove(path)
120 .map(|_| ())
121 .ok_or_else(|| EM::FileNotFound.into())
122 }
123
124 fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<()> {
125 debug!("Copying : {:?} -> {:?}", from, to);
126 let mut mtx = self.backend().lock().expect("Locking Mutex failed");
127 let backend = mtx.get_mut();
128
129 let a = backend.get(from).cloned().ok_or_else(|| EM::FileNotFound)?;
130 backend.insert(to.clone(), a);
131 debug!("Copying: {:?} -> {:?} worked", from, to);
132 Ok(())
133 }
134
135 fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<()> {
136 debug!("Renaming: {:?} -> {:?}", from, to);
137 let mut mtx = self.backend().lock().expect("Locking Mutex failed");
138 let backend = mtx.get_mut();
139
140 let a = backend.remove(from).ok_or_else(|| EM::FileNotFound)?;
141 let new_entry = {
142 let new_location = if to.starts_with("/") {
143 let s = to.to_str().map(String::from).ok_or_else(|| err_msg("Failed to convert path to str"))?;
144 PathBuf::from(s.replace("/", ""))
145 } else {
146 to.to_path_buf()
147 };
148
149 Entry::from_str(crate::storeid::StoreId::new(new_location)?, &a.to_str()?)?
150 };
151
152 backend.insert(to.clone(), new_entry);
153 debug!("Renaming: {:?} -> {:?} worked", from, to);
154 Ok(())
155 }
156
157 fn create_dir_all(&self, _: &PathBuf) -> Result<()> {
158 Ok(())
159 }
160
161 fn exists(&self, pb: &PathBuf) -> Result<bool> {
162 let mut mtx = self.backend().lock().expect("Locking Mutex failed");
163 let backend = mtx.get_mut();
164
165 Ok(backend.contains_key(pb))
166 }
167
168 fn is_file(&self, pb: &PathBuf) -> Result<bool> {
169 self.exists(pb)
173 }
174
175 fn new_instance(&self, p: PathBuf) -> Box<dyn FileAbstractionInstance> {
176 Box::new(InMemoryFileAbstractionInstance::new(self.backend().clone(), p))
177 }
178
179 fn drain(&self) -> Result<Drain> {
180 self.backend_cloned().map(Drain::new)
181 }
182
183 fn fill(&mut self, mut d: Drain) -> Result<()> {
184 debug!("Draining into : {:?}", self);
185 let mut mtx = self.backend()
186 .lock()
187 .map_err(|_| EM::LockError)?;
188 let backend = mtx.get_mut();
189
190 for (path, element) in d.iter() {
191 debug!("Drain into {:?}: {:?}", self, path);
192 backend.insert(path, element);
193 }
194
195 Ok(())
196 }
197
198 fn pathes_recursively<'a>(&self, _basepath: PathBuf, storepath: &'a PathBuf, backend: Arc<dyn FileAbstraction>) -> Result<PathIterator<'a>> {
199 trace!("Building PathIterator object (inmemory implementation)");
200 let keys : Vec<PathBuf> = self
201 .backend()
202 .lock()
203 .map_err(|_| EM::LockError)?
204 .get_mut()
205 .keys()
206 .map(PathBuf::from)
207 .map(Ok)
208 .collect::<Result<_>>()?; Ok(PathIterator::new(Box::new(InMemPathIterBuilder(keys)), storepath, backend))
211 }
212}
213
214#[derive(Debug)]
215pub struct InMemPathIterBuilder(Vec<PathBuf>);
216
217impl PathIterBuilder for InMemPathIterBuilder {
218 fn build_iter(&self) -> Box<dyn Iterator<Item = Result<PathBuf>>> {
219 Box::new(self.0.clone().into_iter().map(Ok))
220 }
221
222 fn in_collection(&mut self, c: &str) -> Result<()> {
223 debug!("Altering PathIterBuilder path with: {:?}", c);
224 self.0.retain(|p| p.starts_with(c));
225 debug!(" -> path : {:?}", self.0);
226 Ok(())
227 }
228}
229