qx_rs_env 0.0.0

quick env util in rust.
Documentation
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
}