serde_envfile/
value.rs

1cfg_if::cfg_if! {
2    if #[cfg(feature = "preserve_order")] {
3        use indexmap::IndexMap as Map;
4    } else {
5        // std::collections::HashMap vs hashbrown::HashMap
6        // https://users.rust-lang.org/t/hashmap-and-hashbrown/114535/2
7        use std::collections::HashMap as Map;
8    }
9}
10
11/// Flexible representation of environment variables.
12///
13/// # Example
14///
15/// ```
16/// use serde_envfile::{Value, Error, from_str};
17///
18/// fn flexible_example() -> Result<(), Error> {
19///     let envfile = "HELLO=WORLD";
20///
21///     let value: Value = from_str(envfile)?;
22///     println!("{:?}", value);
23///     
24///     Ok(())
25/// }
26/// ```
27#[derive(Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
28#[serde(transparent)]
29pub struct Value(Map<String, String>);
30
31impl Default for Value {
32    fn default() -> Self {
33        Self::new()
34    }
35}
36
37impl Value {
38    /// Create an empty [`Value`].
39    ///
40    /// Internally, the [`Value`] object uses a map to store the key-value pairs.
41    pub fn new() -> Self {
42        Self(Default::default())
43    }
44}
45
46impl std::ops::Deref for Value {
47    type Target = Map<String, String>;
48
49    fn deref(&self) -> &Self::Target {
50        &self.0
51    }
52}
53
54impl std::ops::DerefMut for Value {
55    fn deref_mut(&mut self) -> &mut Self::Target {
56        &mut self.0
57    }
58}
59
60impl<K, V> FromIterator<(K, V)> for Value
61where
62    K: Into<String>,
63    V: Into<String>,
64{
65    /// Create a new [`Value`] from an iterator of key-value pairs.
66    ///
67    /// # Example
68    ///
69    /// ```rust
70    /// use serde_envfile::Value;
71    ///
72    /// let env = Value::from_iter([("KEY1", "VALUE1"), ("KEY2", "VALUE2")]);
73    /// # assert_eq!(env.get("KEY1").unwrap(), "VALUE1");
74    /// # assert_eq!(env.get("KEY2").unwrap(), "VALUE2");
75    /// ```
76    ///
77    fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
78        let iter = iter.into_iter().map(|(k, v)| (k.into(), v.into()));
79        Self(FromIterator::from_iter(iter))
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use super::Value;
86    use crate::{de::from_str, ser::to_string};
87
88    #[test]
89    fn value_to_string() {
90        //* Given
91        let env = Value::from_iter([("KEY1", "VALUE1"), ("KEY2", "VALUE2")]);
92
93        //* When
94        let value_serialized = to_string(&env).expect("Failed to convert Value to String");
95        let value_deserialized =
96            from_str::<Value>(&value_serialized).expect("Failed to deserialize Value");
97
98        //* Then
99        // Assert that both expected lines are present
100        // The order of keys in the serialized output is not guaranteed without the `preserve_order` feature
101        assert!(value_serialized.contains(r#"KEY1="VALUE1""#));
102        assert!(value_serialized.contains(r#"KEY2="VALUE2""#));
103
104        // Assert the deserialize output follows the order of the original input
105        // when the `preserve_order` feature is enabled
106        #[cfg(feature = "preserve_order")]
107        {
108            let expected_serialized = "KEY1=\"VALUE1\"\nKEY2=\"VALUE2\"";
109            assert_eq!(value_serialized, expected_serialized);
110        }
111
112        // Create a new Value with lowercase keys to match the deserialization behavior
113        let expected_deserialized = Value::from_iter([("key1", "VALUE1"), ("key2", "VALUE2")]);
114        assert_eq!(value_deserialized, expected_deserialized);
115    }
116}