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 super::parse_value;
use crate::config::{HandlerError, ParseEnvResult};
use std::str::FromStr;
pub struct EnvManager {
count: u8,
/// Prefixes to apply to derived keys, in order of precedence. The
/// container's own prefix comes first, then the one a parent passed
/// in with `#[setting(nested, env_prefix)]`. The container's own must
/// win, because `finalize` re-reads the environment without a parent
/// in the picture, and that read is applied last.
prefixes: Vec<String>,
}
impl EnvManager {
pub fn new<T: AsRef<str>>(override_prefix: Option<T>, prefix: Option<T>) -> Self {
Self {
count: 0,
prefixes: vec![override_prefix, prefix]
.into_iter()
.flatten()
.map(|pre| pre.as_ref().to_string())
.filter(|pre| !pre.is_empty())
.collect(),
}
}
pub fn is_empty(&self) -> bool {
self.count == 0
}
/// Get a variable using the exact key, ignoring the prefix.
/// For explicit keys defined with `#[setting(env)]`.
pub fn get<T: FromStr>(&mut self, key: &str) -> ParseEnvResult<T> {
self.get_and_parse(key, |value| parse_value(value).map(|v| Some(v)))
}
/// Get and parse a variable using the exact key, ignoring the prefix.
/// For explicit keys defined with `#[setting(env)]`.
pub fn get_and_parse<T>(
&mut self,
key: &str,
parser: impl Fn(String) -> ParseEnvResult<T>,
) -> ParseEnvResult<T> {
self.read(key, parser)
}
/// Get a variable using the key with a prefix applied.
/// For keys derived from setting names when using `env_prefix`.
pub fn get_prefixed<T: FromStr>(&mut self, key: &str) -> ParseEnvResult<T> {
self.get_and_parse_prefixed(key, |value| parse_value(value).map(|v| Some(v)))
}
/// Get and parse a variable using the key with a prefix applied. Each
/// prefix is tried in order, and the first variable found wins.
/// For keys derived from setting names when using `env_prefix`.
pub fn get_and_parse_prefixed<T>(
&mut self,
key: &str,
parser: impl Fn(String) -> ParseEnvResult<T>,
) -> ParseEnvResult<T> {
for index in 0..self.prefixes.len() {
let full_key = format!("{}{key}", self.prefixes[index]);
if let Some(value) = self.read(&full_key, &parser)? {
return Ok(Some(value));
}
}
Ok(None)
}
fn read<T>(
&mut self,
key: &str,
parser: impl Fn(String) -> ParseEnvResult<T>,
) -> ParseEnvResult<T> {
if let Ok(value) = std::env::var(key) {
return parser(value)
.inspect(|inner| {
if inner.is_some() {
self.count += 1;
}
})
.map_err(|error| {
HandlerError(format!("Invalid environment variable {key}. {error}"))
});
}
Ok(None)
}
pub fn nested<T>(&mut self, partial: Option<T>) -> ParseEnvResult<T> {
if partial.is_some() {
self.count += 1;
}
Ok(partial)
}
}