action_core/
env.rs

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    /// Get value from environment.
33    ///
34    /// # Errors
35    /// When the environment variable is not present.
36    fn get<K>(&self, key: K) -> Option<OsString>
37    where
38        K: AsRef<OsStr>;
39}
40
41pub trait Write {
42    /// Set value for environment.
43    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    /// Parses environment from a string.
98    ///
99    /// # Errors
100    /// If the input cannot be parsed as a `HashMap<String, String>`.
101    fn from_str(config: &str) -> Result<HashMap<String, String>, Self::Error>;
102
103    /// Parses environment from a reader.
104    ///
105    /// # Errors
106    /// If the input cannot be parsed as a `HashMap<String, String>`.
107    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}