1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
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)?))
}
}