use std::collections::HashMap;
use std::fs;
use std::io::{Error, ErrorKind};
use std::ops::Index;
const DEFAULT_KEY_VALUE_SEP: &str = "=";
const DEFAULT_PAIR_SEP: &str = "\n";
pub struct FileToMap<'a> {
key_value_sep: &'a str,
pair_sep: &'a str,
map: HashMap<String, String>,
file_name: &'a str,
}
impl<'a> FileToMap<'a> {
pub fn new(file_name: &'a str) -> Self {
FileToMap {
key_value_sep: DEFAULT_KEY_VALUE_SEP,
pair_sep: DEFAULT_PAIR_SEP,
map: HashMap::new(),
file_name: file_name,
}
}
pub fn set_key_value_separator(mut self, sep: &'a str) -> Self {
self.key_value_sep = sep;
return self;
}
pub fn set_pair_separator(mut self, sep: &'a str) -> Self {
self.pair_sep = sep;
return self;
}
pub fn build(mut self) -> Result<Self, Error> {
let data = fs::read_to_string(self.file_name)?; let data = self.strip_trailing_newline(&data);
let splitted_data: Vec<String> =
data.split(self.pair_sep).map(|s| String::from(s)).collect();
let data_parse_result = splitted_data
.iter()
.try_for_each(|s| -> std::io::Result<()> {
let key_val: Vec<&str> = s.splitn(2, self.key_value_sep).collect(); if key_val.len() != 2 {
return Err(Error::new(
ErrorKind::Other,
format!("Cannot find {} in {}", self.key_value_sep, s),
));
}
self.map
.insert(String::from(key_val[0]), String::from(key_val[1])); Ok(())
});
let ret: Result<Self, Error> = match data_parse_result {
Ok(()) => Ok(self),
Err(e) => Err(e),
};
ret
}
pub fn get(&self, key: &str) -> Option<&String> {
self.map.get(key)
}
fn strip_trailing_newline(&self, input: &'a str) -> &'a str {
input
.strip_suffix("\r\n")
.or(input.strip_suffix("\n"))
.unwrap_or(input)
}
}
impl<'a> Index<&str> for FileToMap<'a> {
type Output = String;
fn index(&self, key: &str) -> &String {
self.map
.get(key)
.expect(format!("Cannot find {} in FileToMap", key).as_str())
}
}
#[cfg(test)]
mod test;