1use parking_lot::Mutex;
2use std::collections::HashMap;
3use std::ffi::{OsStr, OsString};
4use std::sync::Arc;
5
6#[derive(Debug, Default)]
7pub struct EnvMap {
8 inner: Arc<Mutex<HashMap<OsString, OsString>>>,
9}
10
11impl<K, V> FromIterator<(K, V)> for EnvMap
12where
13 K: Into<OsString>,
14 V: Into<OsString>,
15{
16 fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
17 Self::new(HashMap::from_iter(
18 iter.into_iter().map(|(k, v)| (k.into(), v.into())),
19 ))
20 }
21}
22
23impl EnvMap {
24 #[must_use]
25 pub fn new(inner: HashMap<OsString, OsString>) -> Self {
26 let inner = Arc::new(Mutex::new(inner));
27 Self { inner }
28 }
29}
30
31pub trait Read {
32 fn get<K>(&self, key: K) -> Option<OsString>
37 where
38 K: AsRef<OsStr>;
39}
40
41pub trait Write {
42 fn set<K, V>(&self, key: K, value: V)
44 where
45 K: AsRef<OsStr>,
46 V: AsRef<OsStr>;
47}
48
49impl Read for EnvMap {
50 fn get<K>(&self, key: K) -> Option<OsString>
51 where
52 K: AsRef<OsStr>,
53 {
54 self.inner.lock().get(key.as_ref()).cloned()
55 }
56}
57
58impl Write for EnvMap {
59 fn set<K, V>(&self, key: K, value: V)
60 where
61 K: AsRef<OsStr>,
62 V: AsRef<OsStr>,
63 {
64 self.inner
65 .lock()
66 .insert(key.as_ref().to_os_string(), value.as_ref().to_os_string());
67 }
68}
69
70#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
71pub struct OsEnv;
72
73impl Read for OsEnv {
74 fn get<K>(&self, key: K) -> Option<OsString>
75 where
76 K: AsRef<OsStr>,
77 {
78 std::env::var_os(key)
79 }
80}
81
82impl Write for OsEnv {
83 fn set<K, V>(&self, key: K, value: V)
84 where
85 K: AsRef<OsStr>,
86 V: AsRef<OsStr>,
87 {
88 unsafe {
89 std::env::set_var(key, value);
90 }
91 }
92}
93
94pub trait Parse {
95 type Error: std::error::Error;
96
97 fn from_str(config: &str) -> Result<HashMap<String, String>, Self::Error>;
102
103 fn from_reader(reader: impl std::io::Read) -> Result<HashMap<String, String>, Self::Error>;
108}
109
110#[cfg(test)]
111mod tests {
112 use super::{EnvMap, Read, Write};
113 use similar_asserts::assert_eq as sim_assert_eq;
114
115 #[test]
116 fn get_env_map() {
117 let input_name = "SOME_NAME";
118 let env = EnvMap::from_iter([(input_name, "SET")]);
119 sim_assert_eq!(env.get(input_name), Some("SET".into()));
120 }
121
122 #[test]
123 fn set_env_map() {
124 let input_name = "SOME_NAME";
125 let env = EnvMap::default();
126 env.set(input_name, "SET");
127 sim_assert_eq!(env.get(input_name), Some("SET".into()));
128 }
129}