use std::collections::HashSet;
use std::fmt::Display;
use std::str::FromStr;
use log::{error, info, warn};
use serde::de::DeserializeOwned;
pub struct Loader {
names: HashSet<String>,
}
impl Default for Loader {
fn default() -> Self {
Self::new()
}
}
impl Loader {
pub fn new() -> Self {
Self {
names: HashSet::new(),
}
}
pub fn is_duplicated(&mut self, name: &str) -> bool {
!self.names.insert(name.into())
}
pub fn load_and_map<T, F, E>(&mut self, fallback: T, name: &str, map: F) -> T
where
F: FnOnce(&str) -> Result<T, E>,
E: Display,
{
let name = name.to_uppercase();
if self.is_duplicated(&name) {
warn!("econf: warning: {} is ambiguous", name);
}
match std::env::var(&name) {
Ok(s) => match map(&s) {
Ok(v) => {
info!("econf: loading {}: found {}", name, s);
v
}
Err(e) => {
error!("econf: loading {}: error on parsing \"{}\": {}", name, s, e);
fallback
}
},
Err(_) => {
info!("econf: loading {}: not found", name);
fallback
}
}
}
pub fn load_from_yaml<T>(&mut self, fallback: T, name: &str) -> T
where
T: DeserializeOwned,
{
self.load_and_map(fallback, name, |s| serde_yaml::from_str(s))
}
pub fn load_from_str<T>(&mut self, fallback: T, name: &str) -> T
where
T: FromStr,
T::Err: Display,
{
self.load_and_map(fallback, name, |s| T::from_str(s))
}
}