use qx_rs_err::err::*;
use qx_rs_file::file;
use qx_rs_regex::regex;
use qx_rs_val::val;
use std::{collections::HashMap, str::FromStr};
#[derive(Debug, Clone)]
pub struct Env {
pub path: String,
pub key_values: HashMap<String, String>,
}
impl Env {
pub fn new(path: &str) -> Result<Option<Self>> {
let env = _load_env(path)?;
Ok(env)
}
}
impl Env {
pub fn str(&self, key: &str) -> Option<String> {
self.key_values.get(key).cloned()
}
pub fn strs(&self, key: &str, separator: &str) -> Option<Vec<String>> {
if let Some(s) = self.key_values.get(key) {
let arr = _split_strs(s, separator);
if arr.len() > 0 {
Some(arr)
} else {
None
}
} else {
None
}
}
}
impl Env {
pub fn val<F: FromStr>(&self, key: &str) -> Result<Option<F>> {
if let Some(s) = self.str(key) {
let v = val::from_str::<F>(&s)?;
Ok(Some(v))
} else {
Ok(None)
}
}
pub fn vals<F: FromStr>(&self, key: &str, separator: &str) -> Result<Option<Vec<F>>> {
if let Some(ss) = self.strs(key, separator) {
let mut vs = Vec::<F>::new();
for s in ss {
let v = val::from_str::<F>(&s)?;
vs.push(v);
}
Ok(Some(vs))
} else {
Ok(None)
}
}
}
fn _load_env(path: &str) -> Result<Option<Env>> {
let res = file::read_text(path)?;
if let Some(t) = res {
let key_values = _parse_key_vals(&t)?;
let env = Env {
path: path.to_string(),
key_values
};
Ok(Some(env))
} else {
Ok(None)
}
}
fn _parse_key_vals(text: &String) -> Result<HashMap<String, String>> {
static REGEX: &str = "\\s*([a-zA-Z][a-zA-Z0-9._]*)\\s*=\\s*(?:\"([^\"]*)\"|([^#\\s]*))\\s*(?:#.*)?$";
let mut map = HashMap::<String, String>::new();
for line in text.lines() {
let line = line.trim();
if let Some(m) = regex::capture_values(REGEX, line)? {
let k = m.values.get(0).unwrap_or(&"").to_string();
let v = m.values.get(1).unwrap_or(&"").to_string();
map.insert(k, v);
}
}
Ok(map)
}
fn _split_strs(text: &String, separator: &str) -> Vec<String> {
let arr: Vec<&str> = text.split(separator).collect();
let arr: Vec<String> = arr.iter().map(|s| s.to_string()).collect();
arr
}