Skip to main content

solti_model/domain/
kv.rs

1//! # Key-value pair
2//!
3//! [`KeyValue`] stores one ordered key-value entry.
4//! It does not apply key or value format validation.
5
6use serde::{Deserialize, Serialize};
7
8/// Key-value pair used for environment variables or generic metadata.
9///
10/// ## Example
11///
12/// ```
13/// use solti_model::KeyValue;
14///
15/// let kv = KeyValue::new("APP_MODE", "batch");
16/// assert_eq!(kv.key(), "APP_MODE");
17/// assert_eq!(kv.value(), "batch");
18/// ```
19#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
20#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
21#[serde(deny_unknown_fields)]
22pub struct KeyValue {
23    /// Name of the variable or key.
24    key: String,
25    /// Value associated with the key.
26    value: String,
27}
28
29impl KeyValue {
30    /// Creates a key-value pair.
31    #[inline]
32    pub fn new<K, V>(key: K, value: V) -> Self
33    where
34        K: Into<String>,
35        V: Into<String>,
36    {
37        Self {
38            key: key.into(),
39            value: value.into(),
40        }
41    }
42
43    /// Returns the key.
44    #[inline]
45    pub fn key(&self) -> &str {
46        &self.key
47    }
48
49    /// Returns the value.
50    #[inline]
51    pub fn value(&self) -> &str {
52        &self.value
53    }
54}
55
56impl From<(String, String)> for KeyValue {
57    #[inline]
58    fn from((key, value): (String, String)) -> Self {
59        Self { key, value }
60    }
61}
62
63impl From<(&str, &str)> for KeyValue {
64    #[inline]
65    fn from((key, value): (&str, &str)) -> Self {
66        Self {
67            key: key.to_string(),
68            value: value.to_string(),
69        }
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    use super::KeyValue;
76
77    #[test]
78    fn constructors_and_equality_preserve_key_and_value() {
79        let expected = KeyValue::new("FOO", "bar");
80        let from_str: KeyValue = ("FOO", "bar").into();
81        let from_string: KeyValue = (String::from("FOO"), String::from("bar")).into();
82
83        assert_eq!(expected.key(), "FOO");
84        assert_eq!(expected.value(), "bar");
85        assert_eq!(from_str, expected);
86        assert_eq!(from_string, expected);
87        assert_ne!(KeyValue::new("FOO", "baz"), expected);
88    }
89
90    #[test]
91    fn serde_roundtrip_preserves_fields() {
92        let kv = KeyValue::new("FOO", "bar");
93        let json = serde_json::to_string(&kv).unwrap();
94        assert_eq!(json, r#"{"key":"FOO","value":"bar"}"#);
95        let back: KeyValue = serde_json::from_str(&json).unwrap();
96        assert_eq!(back, kv);
97    }
98}