bstorage/
map.rs

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/// `Map` is a struct representing the mapping of keys to fields within the storage.
13#[derive(Debug)]
14pub struct Map {
15    /// Path to storage folder
16    cwd: PathBuf,
17    /// Path to map file
18    path: PathBuf,
19}
20
21impl Map {
22    /// Creates a new `Map` instance for the specified directory.
23    ///
24    /// # Arguments
25    ///
26    /// * `cwd` - A path reference to the current working directory.
27    ///
28    /// # Returns
29    ///
30    /// * `Self` - Returns a newly created instance of `Map`.
31    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    /// Reads the map file and returns a `HashMap` of keys to fields.
39    ///
40    /// # Returns
41    ///
42    /// * `Result<HashMap<String, Field>, E>` - Returns the map of keys to fields, or an error.
43    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    /// Writes the current map of fields to the map file.
66    ///
67    /// # Arguments
68    ///
69    /// * `fields` - A reference to the `HashMap` of fields to be written.
70    ///
71    /// # Returns
72    ///
73    /// * `Result<(), E>` - Returns Ok(()) if successful, or an error.
74    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}