1use crate::{Fail, Result};
4use std::collections::HashMap;
5use std::fs::{File, OpenOptions, remove_file, rename};
6use std::io::prelude::*;
7
8#[derive(Debug)]
10pub struct StorageFile {
11 file: File,
12 raw: String,
13 cache: HashMap<String, String>,
14}
15
16impl StorageFile {
17 pub fn new(file_name: impl AsRef<str>) -> Result<Self> {
19 let mut file = open_file(file_name)?;
21 let raw = read_file(&mut file)?;
22 let raw = String::from_utf8(raw)?;
23 let cache = parse(&raw);
24
25 Ok(Self { file, raw, cache })
27 }
28
29 pub fn raw(&self) -> &str {
31 &self.raw
32 }
33
34 pub fn raw_write(&mut self, raw: String) -> Result<()> {
36 self.raw = raw;
38 self.cache = parse(&self.raw);
39 write_file(&mut self.file, &self.raw)
40 }
41
42 pub fn cache(&self) -> &HashMap<String, String> {
44 &self.cache
45 }
46
47 pub fn cache_mut(&mut self) -> &mut HashMap<String, String> {
49 &mut self.cache
50 }
51
52 pub fn write(&mut self) -> Result<()> {
54 self.raw = serialize(self.cache());
56 write_file(&mut self.file, &self.raw)
57 }
58}
59
60pub fn open_file(file_name: impl AsRef<str>) -> Result<File> {
62 OpenOptions::new()
64 .read(true)
65 .write(true)
66 .create(true)
67 .truncate(false)
68 .open(file_name.as_ref())
69 .or_else(Fail::from)
70}
71
72pub fn delete_file(file_name: impl AsRef<str>) -> Result<()> {
74 remove_file(file_name.as_ref()).or_else(Fail::from)
76}
77
78pub fn move_file(file_name: impl AsRef<str>, new_file_name: impl AsRef<str>) -> Result<()> {
80 rename(file_name.as_ref(), new_file_name.as_ref()).or_else(Fail::from)
82}
83
84pub fn read_file(file: &mut File) -> Result<Vec<u8>> {
86 file.rewind()?;
88
89 let mut buf = Vec::with_capacity(match file.metadata() {
91 Ok(metadata) => metadata.len() as usize,
92 Err(_) => 8192,
93 });
94
95 file.read_to_end(&mut buf)?;
97 Ok(buf)
98}
99
100pub fn write_file(file: &mut File, data: impl AsRef<[u8]>) -> Result<()> {
102 file.set_len(0)?;
104
105 file.rewind()?;
107
108 file.write_all(data.as_ref())?;
110 file.flush().or_else(Fail::from)
111}
112
113pub fn parse(buf: &str) -> HashMap<String, String> {
115 let mut conf = HashMap::new();
117 buf.split('\n')
118 .map(|l| l.splitn(2, '=').map(|c| c.trim()).collect())
120 .for_each(|kv: Vec<&str>| {
122 if kv.len() == 2 {
124 conf.insert(kv[0].to_lowercase(), kv[1].to_string());
125 }
126 });
127
128 conf
130}
131
132pub fn serialize(data: &HashMap<String, String>) -> String {
134 let mut buf = String::with_capacity(data.len() * 10);
136
137 for (k, v) in data {
139 buf.push_str(k);
140 buf.push('=');
141 buf.push_str(v);
142 buf.push('\n');
143 }
144
145 buf
147}