Skip to main content

prototty_file_storage/
lib.rs

1pub use prototty_storage::*;
2use std::env;
3use std::fs::{self, File};
4use std::io::{self, Read, Write};
5use std::path::{Path, PathBuf};
6
7pub struct FileStorage {
8    base_path: PathBuf,
9}
10
11pub enum IfDirectoryMissing {
12    Create,
13    Error,
14}
15
16#[derive(Debug)]
17pub enum Error {
18    FailedToCreateDirectory(io::Error),
19    DirectoryMissing(PathBuf),
20    FailedToFindCurrentExePath(io::Error),
21}
22
23impl FileStorage {
24    pub fn new<P: AsRef<Path>>(path: P, if_directory_missing: IfDirectoryMissing) -> Result<Self, Error> {
25        if !path.as_ref().exists() {
26            match if_directory_missing {
27                IfDirectoryMissing::Create => {
28                    fs::create_dir_all(path.as_ref()).map_err(Error::FailedToCreateDirectory)?
29                }
30                IfDirectoryMissing::Error => return Err(Error::DirectoryMissing(path.as_ref().to_path_buf())),
31            }
32        }
33        Ok(Self {
34            base_path: path.as_ref().to_path_buf(),
35        })
36    }
37
38    pub fn next_to_exe<P: AsRef<Path>>(
39        relative_path: P,
40        if_directory_missing: IfDirectoryMissing,
41    ) -> Result<Self, Error> {
42        let mut exe_path = env::current_exe().map_err(Error::FailedToFindCurrentExePath)?;
43        // remove binary's name from the path
44        exe_path.pop();
45        Self::new(exe_path.join(relative_path), if_directory_missing)
46    }
47
48    pub fn full_path<S: AsRef<str>>(&self, path: S) -> PathBuf {
49        let relative_path: PathBuf = path.as_ref().into();
50        self.base_path.join(relative_path)
51    }
52}
53
54impl Storage for FileStorage {
55    fn exists<K>(&self, key: K) -> bool
56    where
57        K: AsRef<str>,
58    {
59        self.full_path(key).exists()
60    }
61
62    fn clear(&mut self) {
63        fs::remove_dir_all(&self.base_path).expect("Failed to remove base dir");
64        fs::create_dir_all(&self.base_path).expect("Failed to create base dir");
65    }
66
67    fn remove<K>(&mut self, key: K) -> Result<(), RemoveError>
68    where
69        K: AsRef<str>,
70    {
71        let path = self.full_path(key);
72        fs::remove_file(path).map_err(|_| RemoveError::IoError)
73    }
74
75    fn load_raw<K>(&self, key: K) -> Result<Vec<u8>, LoadRawError>
76    where
77        K: AsRef<str>,
78    {
79        let mut file = File::open(self.full_path(key)).map_err(|_| LoadRawError::NoSuchKey)?;
80        let mut contents = Vec::new();
81        file.read_to_end(&mut contents).map_err(|_| LoadRawError::IoError)?;
82        Ok(contents)
83    }
84
85    fn store_raw<K, V>(&mut self, key: K, value: V) -> Result<(), StoreRawError>
86    where
87        K: AsRef<str>,
88        V: AsRef<[u8]>,
89    {
90        let mut file = File::create(self.full_path(key)).map_err(|_| StoreRawError::IoError)?;
91        file.write_all(value.as_ref()).map_err(|_| StoreRawError::IoError)?;
92        Ok(())
93    }
94}