oasiscap/
map.rs

1//! A container type for CAP >=1.1 key value maps.
2
3use serde::ser::SerializeSeq;
4use serde::{Deserialize, Deserializer, Serialize, Serializer};
5
6/// An order-preserving `String` => `String` key/value map which supports duplicate entries.
7///
8/// `Map` is parameterized by its element type, since different CAP standards use different
9/// kinds of elements which must be serialized/deserialized differently.
10///
11/// `Map<E: MapEntry>` implements `FromIterator` for key-value `(String, String)` or `(&str, &str)`
12/// tuples:
13///
14/// ```
15/// let map: oasiscap::v1dot1::Map = [
16///     ("foo", "bar"),
17///     ("foo", "baz"),
18///     ("quxx", "flummox"),
19/// ].into_iter().collect();
20/// ```
21///
22/// `&Map<E: MapEntry>` implements `IntoIterator` for easy iteration:
23///
24/// ```
25/// # let map: oasiscap::v1dot1::Map = [
26/// #     ("foo", "bar"),
27/// #     ("foo", "baz"),
28/// #     ("quxx", "flummox"),
29/// # ].into_iter().collect();
30/// for (key, value) in &map {
31///     println!("{:?} = {:?}", key, value);
32/// }
33/// ```
34///
35/// `Map<E: MapEntry>` implements `IntoIterator<Item=(String, String)>`, which allows easy
36/// conversion from `Map` to other kinds of containers:
37///
38/// ```
39/// # let map: oasiscap::v1dot1::Map = [
40/// #     ("foo", "bar"),
41/// #     ("foo", "baz"),
42/// #     ("quxx", "flummox"),
43/// # ].into_iter().collect();
44/// // Just note that Map is duplicate-preserving:
45/// assert_eq!(map.get("foo"), Some("bar"));
46/// assert_eq!(map.get_all("foo").collect::<Vec<_>>(), vec!["bar", "baz"]);
47///
48/// // ...while most other containers are not:
49/// let btree_map: std::collections::BTreeMap<String, String> = map.into_iter().collect();
50/// assert_eq!(btree_map.get("foo"), Some(&"baz".into()));
51/// ```
52///
53#[derive(Debug, Clone, Eq, PartialEq)]
54pub struct Map<E>(Vec<E>);
55
56/// The behaviors needed for a map entry.
57pub trait Entry: From<(String, String)> + Into<(String, String)> {
58    /// The value name (i.e. key) of this entry.
59    fn value_name(&self) -> &str;
60
61    /// The value of this entry.
62    fn value(&self) -> &str;
63
64    /// Set the value of this entry, returning the old value.
65    fn set_value(&mut self, new_value: String) -> String;
66}
67
68impl<E: Entry> Map<E> {
69    /// Instantiate an empty map.
70    ///
71    /// # Example
72    ///
73    /// ```
74    /// let map = oasiscap::v1dot1::Map::new();
75    /// ```
76    pub fn new() -> Self {
77        Self(Vec::new())
78    }
79
80    /// Get the first value for this key, if any.
81    ///
82    /// # Example
83    ///
84    /// ```
85    /// let map: oasiscap::v1dot1::Map = [
86    ///     ("foo", "bar"),
87    ///     ("foo", "baz"),
88    ///     ("quxx", "flummox"),
89    /// ].into_iter().collect();
90    ///
91    /// assert_eq!(map.get("foo"), Some("bar"));
92    /// ```
93    pub fn get<S: AsRef<str>>(&self, value_name: S) -> Option<&str> {
94        let value_name = value_name.as_ref();
95        self.0
96            .iter()
97            .find(|e| e.value_name() == value_name)
98            .map(|e| e.value())
99    }
100
101    /// Iterate over all the values for a given key.
102    ///
103    /// # Example
104    ///
105    /// ```
106    /// let map: oasiscap::v1dot1::Map = [
107    ///     ("foo", "bar"),
108    ///     ("foo", "baz"),
109    ///     ("quxx", "flummox"),
110    /// ].into_iter().collect();
111    ///
112    /// assert_eq!(map.get_all("foo").collect::<Vec<&str>>(), vec!["bar", "baz"]);
113    /// ```
114    pub fn get_all<S: AsRef<str>>(&self, value_name: S) -> impl Iterator<Item = &str> {
115        self.0.iter().filter_map(move |e| {
116            if e.value_name() == value_name.as_ref() {
117                Some(e.value())
118            } else {
119                None
120            }
121        })
122    }
123
124    /// Push a new key-value entry onto an existing map.
125    ///
126    /// # Example
127    ///
128    /// ```
129    /// let mut map: oasiscap::v1dot1::Map = [
130    ///     ("foo", "bar"),
131    ///     ("foo", "baz"),
132    ///     ("quxx", "flummox"),
133    /// ].into_iter().collect();
134    ///
135    /// map.push("foo", "waldo");
136    ///
137    /// assert_eq!(map.get_all("foo").collect::<Vec<&str>>(), vec!["bar", "baz", "waldo"]);
138    /// ```
139    pub fn push<K: Into<String>, V: Into<String>>(&mut self, value_name: K, value: V) {
140        self.0.push(E::from((value_name.into(), value.into())));
141    }
142
143    /// Returns the number of entries in the map.
144    pub fn len(&self) -> usize {
145        self.0.len()
146    }
147
148    /// Returns `true` if the map contains no entries.
149    pub fn is_empty(&self) -> bool {
150        self.0.is_empty()
151    }
152
153    /// Returns an iterator over the map.
154    #[must_use]
155    pub fn iter(&self) -> Iter<E> {
156        Iter(self.0.iter())
157    }
158}
159
160impl<E> Default for Map<E> {
161    fn default() -> Self {
162        Self(Vec::new())
163    }
164}
165
166impl<E: Entry + Serialize> Serialize for Map<E> {
167    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
168    where
169        S: Serializer,
170    {
171        let mut seq = serializer.serialize_seq(Some(self.0.len()))?;
172        for entry in &self.0 {
173            seq.serialize_element(entry)?;
174        }
175        seq.end()
176    }
177}
178
179impl<'de, E: Entry + Deserialize<'de>> Deserialize<'de> for Map<E> {
180    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
181    where
182        D: Deserializer<'de>,
183    {
184        let entries = <Vec<E>>::deserialize(deserializer)?;
185        Ok(Self(entries))
186    }
187}
188
189impl<'a, E: Entry> FromIterator<(&'a str, &'a str)> for Map<E> {
190    fn from_iter<T: IntoIterator<Item = (&'a str, &'a str)>>(iter: T) -> Self {
191        Self(
192            iter.into_iter()
193                .map(|(value_name, value)| E::from((value_name.into(), value.into())))
194                .collect(),
195        )
196    }
197}
198
199impl<E: Entry> FromIterator<(String, String)> for Map<E> {
200    fn from_iter<T: IntoIterator<Item = (String, String)>>(iter: T) -> Self {
201        Self(
202            iter.into_iter()
203                .map(|(value_name, value)| E::from((value_name, value)))
204                .collect(),
205        )
206    }
207}
208
209impl<E> FromIterator<E> for Map<E> {
210    fn from_iter<T: IntoIterator<Item = E>>(iter: T) -> Self {
211        Self(iter.into_iter().collect())
212    }
213}
214
215impl<'a, E: Entry> IntoIterator for &'a Map<E> {
216    type Item = (&'a str, &'a str);
217    type IntoIter = Iter<'a, E>;
218
219    fn into_iter(self) -> Self::IntoIter {
220        self.iter()
221    }
222}
223
224impl<E: Entry> IntoIterator for Map<E> {
225    type Item = (String, String);
226    type IntoIter = IntoIter<E>;
227
228    fn into_iter(self) -> Self::IntoIter {
229        IntoIter(self.0.into_iter())
230    }
231}
232
233/// An iterator over a map.
234#[derive(Debug)]
235pub struct Iter<'a, E>(std::slice::Iter<'a, E>);
236
237impl<'a, E: Entry> Iterator for Iter<'a, E> {
238    type Item = (&'a str, &'a str);
239
240    fn next(&mut self) -> Option<Self::Item> {
241        self.0.next().map(|e| (e.value_name(), e.value()))
242    }
243
244    fn size_hint(&self) -> (usize, Option<usize>) {
245        self.0.size_hint()
246    }
247}
248
249impl<'a, E: Entry> ExactSizeIterator for Iter<'a, E> {}
250
251/// An iterator that moves out of a map.
252#[derive(Debug)]
253pub struct IntoIter<E>(std::vec::IntoIter<E>);
254
255impl<E: Entry> Iterator for IntoIter<E> {
256    type Item = (String, String);
257
258    fn next(&mut self) -> Option<Self::Item> {
259        self.0.next().map(|e| e.into())
260    }
261
262    fn size_hint(&self) -> (usize, Option<usize>) {
263        self.0.size_hint()
264    }
265}
266
267impl<E: Entry> ExactSizeIterator for IntoIter<E> {}
268
269impl<E: Entry> From<crate::v1dot0::Map> for Map<E> {
270    fn from(prev: crate::v1dot0::Map) -> Self {
271        prev.into_iter()
272            .map(|(key, value)| (key.into(), value))
273            .collect()
274    }
275}