use context::Context;
use std::env;
use std::error::Error as StdError;
use std::fmt;
use Error;
#[derive(Debug)]
struct EmptyError;
impl fmt::Display for EmptyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "parse method no implemented!")
}
}
impl StdError for EmptyError {
fn description(&self) -> &str {
"Method parse is not implemented"
}
fn source(&self) -> Option<&(dyn StdError + 'static)> {
None
}
}
pub trait Yasec {
fn init() -> Result<Self, Error>
where
Self: Sized,
{
Self::with_prefix("")
}
fn with_prefix(prefix: impl AsRef<str>) -> Result<Self, Error>
where
Self: Sized,
{
Self::with_context(Context::new(prefix))
}
fn with_context(context: Context<Self>) -> Result<Self, Error>
where
Self: Sized,
{
let mut context = context;
let env_var_name = context.infer_var_name();
match env::var(&env_var_name) {
Ok(ref x) => Self::parse(x).map_err(|e| Error::new(e, env_var_name, x.to_owned())),
Err(e) => match context.take_default_var_value() {
Some(default) => Ok(default),
None => Err(Error::new(Box::new(e), env_var_name, None)),
},
}
}
fn parse(_val: &str) -> Result<Self, Box<dyn StdError>>
where
Self: Sized,
{
Err(Box::new(EmptyError))
}
}
macro_rules! implement {
($x:ident) => {
impl Yasec for $x {
fn parse(val: &str) -> Result<Self, Box<dyn StdError>> {
Ok(val.parse::<$x>()?)
}
}
};
}
implement!(char);
implement!(u8);
implement!(u16);
implement!(u32);
implement!(u64);
implement!(i8);
implement!(i16);
implement!(i32);
implement!(i64);
implement!(f32);
implement!(f64);
impl Yasec for String {
fn parse(val: &str) -> Result<Self, Box<dyn StdError>> {
Ok(val.to_owned())
}
}
impl<T: Yasec> Yasec for Option<T> {
fn with_context(context: Context<Self>) -> Result<Self, Error> {
let env_var_name = context.prefix();
let env_var_result = env::var(&env_var_name);
match env_var_result {
Ok(ref x) => Self::parse(x).map_err(|e| Error::new(e, env_var_name, x.to_owned())),
Err(_) => Ok(None),
}
}
fn parse(val: &str) -> Result<Self, Box<dyn StdError>> {
Ok(Some(T::parse(val)?))
}
}