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
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::ffi::OsString;
/// Represents env variables loaded into memory
#[derive(Default)]
pub struct ParsedEnv {
map: BTreeMap<String, OsString>,
}
impl ParsedEnv {
/// Get the OsString. This is useful if you want to raise an error with context if it not valid
/// utf8.
pub(crate) fn get<'a>(&'a self, name: &str) -> Option<&'a OsString> {
self.map.get(name)
}
/// Get the OsString as a lossy string, or "" if it's not present.
/// This is useful when rendering help text
pub(crate) fn get_lossy_or_default<'a>(&'a self, name: &str) -> Cow<'a, str> {
self.map
.get(name)
.map(|os_str| os_str.to_string_lossy())
.unwrap_or_default()
}
}
/// Parse a generic thing that looks like std::env::vars_os but might be test data,
/// and store it in a searchable container.
pub fn parse_env<K, V>(env_vars_os: impl IntoIterator<Item = (K, V)>) -> ParsedEnv
where
K: Into<OsString>,
V: Into<OsString>,
{
// Drop any non-utf8 env keys, since there's no way the parser can read them anyways, since we
// don't give the user a way to specify a non-utf8 env value that should be read.
// If some values are non-utf8, that's also going to fail if they are read, but it's possible
// our program doesn't actually need to read those, so let's fail at the time it actually
// reads them instead.
ParsedEnv {
map: env_vars_os
.into_iter()
.filter_map(|(into_key, into_val)| {
if let Ok(key) = into_key.into().into_string() {
Some((key, into_val.into()))
} else {
None
}
})
.collect(),
}
}