1use std::collections::HashMap;
6use std::fs;
7use std::io::{Error, ErrorKind};
8use std::ops::Index;
9
10const DEFAULT_KEY_VALUE_SEP: &str = "=";
11const DEFAULT_PAIR_SEP: &str = "\n";
12
13pub struct FileToMap<'a> {
15 key_value_sep: &'a str,
16 pair_sep: &'a str,
17 map: HashMap<String, String>,
18 file_name: &'a str,
19}
20
21impl<'a> FileToMap<'a> {
22 pub fn new(file_name: &'a str) -> Self {
24 FileToMap {
25 key_value_sep: DEFAULT_KEY_VALUE_SEP,
26 pair_sep: DEFAULT_PAIR_SEP,
27 map: HashMap::new(),
28 file_name: file_name,
29 }
30 }
31
32 pub fn set_key_value_separator(mut self, sep: &'a str) -> Self {
34 self.key_value_sep = sep;
35 return self;
36 }
37
38 pub fn set_pair_separator(mut self, sep: &'a str) -> Self {
41 self.pair_sep = sep;
42 return self;
43 }
44
45 pub fn build(mut self) -> Result<Self, Error> {
48 let data = fs::read_to_string(self.file_name)?; let data = self.strip_trailing_newline(&data); let splitted_data: Vec<String> =
52 data.split(self.pair_sep).map(|s| String::from(s)).collect(); let data_parse_result = splitted_data
55 .iter()
56 .try_for_each(|s| -> std::io::Result<()> {
57 let key_val: Vec<&str> = s.splitn(2, self.key_value_sep).collect(); if key_val.len() != 2 {
59 return Err(Error::new(
61 ErrorKind::Other,
62 format!("Cannot find {} in {}", self.key_value_sep, s),
63 ));
64 }
65 self.map
66 .insert(String::from(key_val[0]), String::from(key_val[1])); Ok(())
68 });
69
70 let ret: Result<Self, Error> = match data_parse_result {
71 Ok(()) => Ok(self),
72 Err(e) => Err(e),
73 };
74
75 ret
76 }
77
78 pub fn get(&self, key: &str) -> Option<&String> {
80 self.map.get(key)
81 }
82 fn strip_trailing_newline(&self, input: &'a str) -> &'a str {
84 input
85 .strip_suffix("\r\n")
86 .or(input.strip_suffix("\n"))
87 .unwrap_or(input)
88 }
89}
90
91impl<'a> Index<&str> for FileToMap<'a> {
92 type Output = String;
93 fn index(&self, key: &str) -> &String {
98 self.map
99 .get(key)
100 .expect(format!("Cannot find {} in FileToMap", key).as_str())
101 }
102}
103#[cfg(test)]
104mod test;