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
use std::{env, fmt};
pub trait Source: fmt::Debug {
fn get(&self, key: &str) -> Option<String>;
}
pub trait Initialize: Sized {
fn init(config: &Anulap<'_>) -> Option<Self>;
}
#[derive(Debug, Default)]
pub struct Anulap<'s> {
sources: Vec<Box<dyn Source + 's>>,
}
impl<'s> Anulap<'s> {
pub fn new() -> Self {
Self::default()
}
pub fn with<S>(mut self, source: S) -> Self
where
S: Source + 's,
{
self.sources.push(Box::new(source));
self
}
pub fn init<I>(&self) -> Option<I>
where
I: Initialize,
{
I::init(&self)
}
pub fn get(&self, key: &str) -> Option<String> {
self.loop_get(key)
}
#[inline]
fn loop_get(&self, key: &str) -> Option<String> {
for source in &self.sources {
if let Some(value) = source.get(key) {
return Some(value);
}
}
None
}
}
#[derive(Debug, Default)]
pub struct EnvSource {
prefix: Option<String>,
}
impl EnvSource {
pub fn new() -> Self {
Self::default()
}
pub fn prefixed<P>(prefix: P) -> Self
where
P: fmt::Display,
{
Self {
prefix: Some(prefix.to_string()),
}
}
}
impl Source for EnvSource {
fn get(&self, key: &str) -> Option<String> {
let key = if let Some(prefix) = &self.prefix {
format!("{}_{}", prefix, key)
} else {
key.to_string()
}
.to_uppercase();
env::var(key).ok()
}
}