Skip to main content

cbor_core/
map.rs

1use std::collections::{BTreeMap, HashMap};
2
3use crate::{Error, Value};
4
5/// Conversion helper for [`Value::map`].
6///
7/// This type wraps `BTreeMap<Value, Value>` and provides `From`
8/// implementations for common collection types, so that
9/// `Value::map()` can accept them all through a single
10/// `impl Into<Map>` bound.
11///
12/// Supported source types (where `K: Into<Value>`, `V: Into<Value>`):
13///
14/// - `[(K, V); N]` (fixed-size array of pairs)
15/// - `&[(K, V)]` (slice of pairs; requires `K: Copy, V: Copy`)
16/// - `Vec<(K, V)>` (vector of pairs)
17/// - `Box<[(K, V)]>` (boxed slice of pairs)
18/// - `BTreeMap<Value, Value>` (already-sorted map; moved as-is)
19/// - `&BTreeMap<K, V>` (borrowed map; requires `K: Copy, V: Copy`)
20/// - `&HashMap<K, V>` (borrowed hash map; requires `K: Copy, V: Copy`)
21/// - `()` (empty map)
22///
23/// Keys and values are converted via their `Into<Value>`
24/// implementations. Keys are automatically sorted in CBOR canonical
25/// order.
26///
27/// ```
28/// # use cbor_core::Value;
29/// // From a fixed-size array of pairs:
30/// let m = Value::map([("x", 1), ("y", 2)]);
31///
32/// // From a Vec of pairs with mixed key types:
33/// let pairs: Vec<(Value, Value)> = vec![
34///     (Value::from(1), Value::from("one")),
35///     (Value::from(2), Value::from("two")),
36/// ];
37/// let m = Value::map(pairs);
38///
39/// // From a BTreeMap:
40/// let mut bt = std::collections::BTreeMap::new();
41/// bt.insert(Value::from("a"), Value::from(1));
42/// let m = Value::map(bt);
43///
44/// // From a &HashMap:
45/// let mut hm = std::collections::HashMap::new();
46/// hm.insert(1, 2);
47/// let m = Value::map(&hm);
48///
49/// // Empty map via ():
50/// let m = Value::map(());
51/// assert_eq!(m.len(), Some(0));
52/// ```
53#[derive(Debug, Default, Clone, PartialEq, Eq)]
54pub struct Map<'a>(pub(crate) BTreeMap<Value<'a>, Value<'a>>);
55
56impl<'a> Map<'a> {
57    /// Create an empty map.
58    #[must_use]
59    pub const fn new() -> Self {
60        Self(BTreeMap::new())
61    }
62
63    /// Borrow the inner `BTreeMap`.
64    #[must_use]
65    pub const fn get_ref(&self) -> &BTreeMap<Value<'a>, Value<'a>> {
66        &self.0
67    }
68
69    /// Mutably borrow the inner `BTreeMap`.
70    pub const fn get_mut(&mut self) -> &mut BTreeMap<Value<'a>, Value<'a>> {
71        &mut self.0
72    }
73
74    /// Unwrap into the inner `BTreeMap`.
75    #[must_use]
76    pub fn into_inner(self) -> BTreeMap<Value<'a>, Value<'a>> {
77        self.0
78    }
79
80    /// Build a map from a lazy iterator of key/value pairs.
81    ///
82    /// Duplicate keys silently overwrite (last write wins). Input order
83    /// does not matter; the returned map is sorted in CBOR canonical
84    /// order. For the strict variant that rejects duplicate keys, see
85    /// [`try_from_pairs`](Self::try_from_pairs).
86    ///
87    /// ```
88    /// # use cbor_core::Map;
89    /// let pairs = [("a", 1), ("b", 2), ("a", 3)];
90    /// let m = Map::from_pairs(pairs);
91    /// assert_eq!(m.get_ref().len(), 2);
92    /// ```
93    pub fn from_pairs<K, V, I>(pairs: I) -> Self
94    where
95        K: Into<Value<'a>>,
96        V: Into<Value<'a>>,
97        I: IntoIterator<Item = (K, V)>,
98    {
99        Self(pairs.into_iter().map(|(k, v)| (k.into(), v.into())).collect())
100    }
101
102    /// Build a map from a lazy iterator of key/value pairs, rejecting
103    /// duplicate keys.
104    ///
105    /// Returns [`Error::NonDeterministic`] on the first duplicate.
106    /// Input order does not matter; the returned map is sorted in CBOR
107    /// canonical order. For the lenient variant, see
108    /// [`from_pairs`](Self::from_pairs).
109    ///
110    /// ```
111    /// # use cbor_core::{Map, Error};
112    /// let ok = Map::try_from_pairs([("a", 1), ("b", 2)]).unwrap();
113    /// assert_eq!(ok.get_ref().len(), 2);
114    ///
115    /// let err = Map::try_from_pairs([("a", 1), ("a", 2)]).unwrap_err();
116    /// assert_eq!(err, Error::NonDeterministic);
117    /// ```
118    pub fn try_from_pairs<K, V, I>(pairs: I) -> Result<Self, Error>
119    where
120        K: Into<Value<'a>>,
121        V: Into<Value<'a>>,
122        I: IntoIterator<Item = (K, V)>,
123    {
124        let mut map = BTreeMap::new();
125        for (k, v) in pairs {
126            if map.insert(k.into(), v.into()).is_some() {
127                return Err(Error::NonDeterministic);
128            }
129        }
130        Ok(Self(map))
131    }
132
133    /// Build a map from a CBOR sequence of alternating key/value items.
134    ///
135    /// Applies the same determinism checks as the binary decoder:
136    ///
137    /// * An odd number of items returns [`Error::UnexpectedEof`]
138    ///   (a key with no following value).
139    /// * A duplicate key returns [`Error::NonDeterministic`].
140    /// * A key that is not strictly greater than the previous key
141    ///   returns [`Error::NonDeterministic`].
142    ///
143    /// For the fallible input produced by
144    /// [`SequenceDecoder`](crate::SequenceDecoder) and
145    /// [`SequenceReader`](crate::SequenceReader), use
146    /// [`try_from_sequence`](Self::try_from_sequence).
147    ///
148    /// ```
149    /// # use cbor_core::{Map, Value};
150    /// let items = [Value::from("a"), Value::from(1), Value::from("b"), Value::from(2)];
151    /// let m = Map::from_sequence(items).unwrap();
152    /// assert_eq!(m.get_ref().len(), 2);
153    /// ```
154    pub fn from_sequence<I>(items: I) -> Result<Self, Error>
155    where
156        I: IntoIterator<Item = Value<'a>>,
157    {
158        let mut iter = items.into_iter();
159        let mut map: BTreeMap<Value<'a>, Value<'a>> = BTreeMap::new();
160        while let Some(key) = iter.next() {
161            let value = iter.next().ok_or(Error::UnexpectedEof)?;
162            if let Some((last_key, _)) = map.last_key_value()
163                && *last_key >= key
164            {
165                return Err(Error::NonDeterministic);
166            }
167            map.insert(key, value);
168        }
169        Ok(Self(map))
170    }
171
172    /// Build a map from a fallible sequence of alternating key/value
173    /// items, stopping at the first error.
174    ///
175    /// Accepts any `IntoIterator<Item = Result<Value, E>>` whose error
176    /// type can carry a CBOR [`Error`] (via `E: From<Error>`). This
177    /// covers both [`SequenceDecoder`](crate::SequenceDecoder)
178    /// (`E = Error`) and [`SequenceReader`](crate::SequenceReader)
179    /// (`E = IoError`).
180    ///
181    /// Determinism checks are the same as
182    /// [`from_sequence`](Self::from_sequence) and are surfaced through
183    /// `E`'s `From<Error>` implementation.
184    ///
185    /// ```
186    /// # use cbor_core::{DecodeOptions, Format, Map};
187    /// // Diagnostic-notation sequence: "a": 1, "b": 2
188    /// let m = Map::try_from_sequence(
189    ///     DecodeOptions::new()
190    ///         .format(Format::Diagnostic)
191    ///         .sequence_decoder(br#""a", 1, "b", 2"#),
192    /// ).unwrap();
193    /// assert_eq!(m.get_ref().len(), 2);
194    /// ```
195    pub fn try_from_sequence<I, E>(items: I) -> Result<Self, E>
196    where
197        I: IntoIterator<Item = Result<Value<'a>, E>>,
198        E: From<Error>,
199    {
200        let mut iter = items.into_iter();
201        let mut map: BTreeMap<Value<'a>, Value<'a>> = BTreeMap::new();
202        while let Some(key) = iter.next() {
203            let key = key?;
204            let value = iter.next().ok_or(Error::UnexpectedEof)??;
205            if let Some((last_key, _)) = map.last_key_value()
206                && *last_key >= key
207            {
208                return Err(Error::NonDeterministic.into());
209            }
210            map.insert(key, value);
211        }
212        Ok(Self(map))
213    }
214}
215
216impl<'a> From<BTreeMap<Value<'a>, Value<'a>>> for Map<'a> {
217    fn from(map: BTreeMap<Value<'a>, Value<'a>>) -> Self {
218        Map(map)
219    }
220}
221
222impl<'a, K: Into<Value<'a>> + Copy, V: Into<Value<'a>> + Copy> From<&BTreeMap<K, V>> for Map<'a> {
223    fn from(map: &BTreeMap<K, V>) -> Self {
224        Map(map.iter().map(|(&k, &v)| (k.into(), v.into())).collect())
225    }
226}
227
228impl<'a, K: Into<Value<'a>> + Copy, V: Into<Value<'a>> + Copy> From<&HashMap<K, V>> for Map<'a> {
229    fn from(map: &HashMap<K, V>) -> Self {
230        Map(map.iter().map(|(&k, &v)| (k.into(), v.into())).collect())
231    }
232}
233
234impl<'a, K: Into<Value<'a>> + Copy, V: Into<Value<'a>> + Copy> From<&[(K, V)]> for Map<'a> {
235    fn from(slice: &[(K, V)]) -> Self {
236        Self(slice.iter().map(|&(k, v)| (k.into(), v.into())).collect())
237    }
238}
239
240impl<'a, const N: usize, K: Into<Value<'a>>, V: Into<Value<'a>>> From<[(K, V); N]> for Map<'a> {
241    fn from(array: [(K, V); N]) -> Self {
242        Self(array.into_iter().map(|(k, v)| (k.into(), v.into())).collect())
243    }
244}
245
246impl<'a, K: Into<Value<'a>>, V: Into<Value<'a>>> From<Vec<(K, V)>> for Map<'a> {
247    fn from(vec: Vec<(K, V)>) -> Self {
248        Self(vec.into_iter().map(|(k, v)| (k.into(), v.into())).collect())
249    }
250}
251
252impl<'a, K: Into<Value<'a>>, V: Into<Value<'a>>> From<Box<[(K, V)]>> for Map<'a> {
253    fn from(boxed: Box<[(K, V)]>) -> Self {
254        Self(
255            Vec::from(boxed)
256                .into_iter()
257                .map(|(k, v)| (k.into(), v.into()))
258                .collect(),
259        )
260    }
261}
262
263impl<'a> From<()> for Map<'a> {
264    fn from(_: ()) -> Self {
265        Self(BTreeMap::new())
266    }
267}