1use log::{debug, warn};
2use std::{
3 collections::HashMap,
4 io::{Read, Write},
5 path::{Path, PathBuf},
6};
7
8use crate::{fs, Field, E};
9
10pub(crate) const MAP_FILE_NAME: &str = "map.bstorage";
11
12#[derive(Debug)]
14pub struct Map {
15 cwd: PathBuf,
17 path: PathBuf,
19}
20
21impl Map {
22 pub fn new<P: AsRef<Path>>(cwd: P) -> Self {
32 Self {
33 cwd: fs::as_path_buf(&cwd),
34 path: fs::as_path_buf(&cwd).join(MAP_FILE_NAME),
35 }
36 }
37
38 pub fn read(&self) -> Result<HashMap<String, Field>, E> {
44 if !self.path.exists() {
45 debug!("Storage's map file will be created: {:?}", self.path);
46 }
47 let mut file = fs::create_or_open(&self.path)?;
48 let mut fields: HashMap<String, Field> = HashMap::new();
49 if file.metadata()?.len() > 0 {
50 let mut buffer = Vec::new();
51 file.read_to_end(&mut buffer)?;
52 let decoded: HashMap<String, String> = bincode::deserialize(&buffer)?;
53 for (key, filename) in decoded.into_iter() {
54 let file_path = self.cwd.join(&filename);
55 if !file_path.exists() {
56 warn!("File \"{filename}\" for key \"{key}\" doesn't exist");
57 continue;
58 }
59 fields.insert(key, Field::restore(&file_path));
60 }
61 }
62 Ok(fields)
63 }
64
65 pub fn write(&mut self, fields: &HashMap<String, Field>) -> Result<(), E> {
75 let mut files: HashMap<String, String> = HashMap::new();
76 for (key, field) in fields.iter() {
77 let file_name = field.file_name()?;
78 files.insert(key.to_owned(), file_name);
79 }
80 let buffer = bincode::serialize(&files)?;
81 let mut map = fs::create(&self.path)?;
82 map.write_all(&buffer)?;
83 Ok(())
84 }
85}