tinycbor/
collections.rs

1//! `alloc` and `std` collection support.
2
3use crate::{CborLen, Encode, Encoder, primitive};
4#[cfg(feature = "alloc")]
5use crate::{Decode, Decoder};
6
7pub mod fixed;
8pub mod map;
9
10/// Error that can occur when decoding dynamic containers.
11#[derive(#[automatically_derived]
impl<E: ::core::fmt::Debug> ::core::fmt::Debug for Error<E> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            Error::Malformed(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "Malformed", &__self_0),
            Error::Element(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "Element", &__self_0),
        }
    }
}Debug, #[automatically_derived]
impl<E: ::core::clone::Clone> ::core::clone::Clone for Error<E> {
    #[inline]
    fn clone(&self) -> Error<E> {
        match self {
            Error::Malformed(__self_0) =>
                Error::Malformed(::core::clone::Clone::clone(__self_0)),
            Error::Element(__self_0) =>
                Error::Element(::core::clone::Clone::clone(__self_0)),
        }
    }
}Clone, #[automatically_derived]
impl<E: ::core::marker::Copy> ::core::marker::Copy for Error<E> { }Copy, #[automatically_derived]
impl<E: ::core::cmp::PartialEq> ::core::cmp::PartialEq for Error<E> {
    #[inline]
    fn eq(&self, other: &Error<E>) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (Error::Malformed(__self_0), Error::Malformed(__arg1_0)) =>
                    __self_0 == __arg1_0,
                (Error::Element(__self_0), Error::Element(__arg1_0)) =>
                    __self_0 == __arg1_0,
                _ => unsafe { ::core::intrinsics::unreachable() }
            }
    }
}PartialEq, #[automatically_derived]
impl<E: ::core::cmp::Eq> ::core::cmp::Eq for Error<E> {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_receiver_is_total_eq(&self) -> () {
        let _: ::core::cmp::AssertParamIsEq<primitive::Error>;
        let _: ::core::cmp::AssertParamIsEq<E>;
    }
}Eq, #[automatically_derived]
impl<E: ::core::hash::Hash> ::core::hash::Hash for Error<E> {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        ::core::hash::Hash::hash(&__self_discr, state);
        match self {
            Error::Malformed(__self_0) =>
                ::core::hash::Hash::hash(__self_0, state),
            Error::Element(__self_0) =>
                ::core::hash::Hash::hash(__self_0, state),
        }
    }
}Hash)]
12pub enum Error<E> {
13    /// The container header is malformed.
14    Malformed(primitive::Error),
15    /// While decoding an element within the container.
16    Element(E),
17}
18
19impl<E> Error<E> {
20    /// Map a function on the inner error.
21    pub fn map<O>(self, f: impl FnOnce(E) -> O) -> Error<O> {
22        match self {
23            Error::Malformed(e) => Error::Malformed(e),
24            Error::Element(e) => Error::Element(f(e)),
25        }
26    }
27}
28
29impl<E: core::fmt::Display> core::fmt::Display for Error<E> {
30    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
31        match self {
32            Error::Malformed(e) => f.write_fmt(format_args!("{0}", e))write!(f, "{e}"),
33            Error::Element(e) => f.write_fmt(format_args!("container element: {0}", e))write!(f, "container element: {e}"),
34        }
35    }
36}
37
38impl<E> From<primitive::Error> for Error<E> {
39    fn from(e: primitive::Error) -> Self {
40        Error::Malformed(e)
41    }
42}
43
44impl<E> From<crate::EndOfInput> for Error<E> {
45    fn from(e: crate::EndOfInput) -> Self {
46        Error::Malformed(primitive::Error::EndOfInput(e))
47    }
48}
49
50impl<E: core::error::Error + 'static> core::error::Error for Error<E> {
51    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
52        match self {
53            Error::Malformed(e) => Some(e),
54            Error::Element(e) => Some(e),
55        }
56    }
57}
58
59#[cfg(feature = "alloc")]
60impl<'b, T> Decode<'b> for alloc::collections::BinaryHeap<T>
61where
62    T: Decode<'b> + Ord,
63{
64    type Error = Error<T::Error>;
65
66    fn decode(d: &mut Decoder<'b>) -> Result<Self, Self::Error> {
67        let mut visitor = d.array_visitor()?;
68        let mut v = Self::new();
69        while let Some(elem) = visitor.visit() {
70            v.push(elem.map_err(Error::Element)?);
71        }
72
73        Ok(v)
74    }
75}
76
77#[cfg(feature = "std")]
78impl<'b, T, S> Decode<'b> for std::collections::HashSet<T, S>
79where
80    T: Decode<'b> + Eq + std::hash::Hash,
81    S: std::hash::BuildHasher + std::default::Default,
82{
83    type Error = Error<T::Error>;
84
85    fn decode(d: &mut Decoder<'b>) -> Result<Self, Self::Error> {
86        let mut visitor = d.array_visitor()?;
87        let mut v = Self::default();
88        while let Some(elem) = visitor.visit() {
89            v.insert(elem.map_err(Error::Element)?);
90        }
91
92        Ok(v)
93    }
94}
95
96#[cfg(feature = "alloc")]
97impl<'b, T> Decode<'b> for alloc::collections::BTreeSet<T>
98where
99    T: Decode<'b> + Ord,
100{
101    type Error = Error<T::Error>;
102
103    fn decode(d: &mut Decoder<'b>) -> Result<Self, Self::Error> {
104        let mut visitor = d.array_visitor()?;
105        let mut v = Self::new();
106        while let Some(elem) = visitor.visit() {
107            v.insert(elem.map_err(Error::Element)?);
108        }
109        Ok(v)
110    }
111}
112
113#[cfg(feature = "alloc")]
114macro_rules! decode_sequential {
115    ($($t:ty, $push:ident)*) => {
116        $(
117            impl<'b, T: Decode<'b>> Decode<'b> for $t {
118                type Error = Error<T::Error>;
119
120                fn decode(d: &mut Decoder<'b>) -> Result<Self, Self::Error> {
121                    let mut visitor = d.array_visitor()?;
122                    let mut v = Self::new();
123                    while let Some(x) = visitor.visit() {
124                        v.$push(x.map_err(Error::Element)?)
125                    }
126                    Ok(v)
127                }
128            }
129        )*
130    }
131}
132
133#[cfg(feature = "alloc")]
134impl<'b, T: Decode<'b>> Decode<'b> for alloc::collections::LinkedList<T> {
    type Error = Error<T::Error>;
    fn decode(d: &mut Decoder<'b>) -> Result<Self, Self::Error> {
        let mut visitor = d.array_visitor()?;
        let mut v = Self::new();
        while let Some(x) = visitor.visit() {
            v.push_back(x.map_err(Error::Element)?)
        }
        Ok(v)
    }
}decode_sequential! {
135    alloc::vec::Vec<T>, push
136    alloc::collections::VecDeque<T>, push_back
137    alloc::collections::LinkedList<T>, push_back
138}
139
140macro_rules! encode_sequential {
141    ($($t:ty)*) => {
142        $(
143            impl<T: Encode> Encode for $t {
144                fn encode<W: embedded_io::Write>(&self, e: &mut Encoder<W>) -> Result<(), W::Error> {
145                    e.array(self.len())?;
146                    for x in self {
147                        x.encode(e)?
148                    }
149                    Ok(())
150                }
151            }
152
153            impl<T: CborLen> CborLen for $t {
154                fn cbor_len(&self) -> usize {
155                    let n = self.len();
156                    n.cbor_len() + self.iter().map(|x| x.cbor_len()).sum::<usize>()
157                }
158            }
159        )*
160    }
161}
162
163#[cfg(feature = "alloc")]
164impl<T: Encode> Encode for alloc::collections::BTreeSet<T> {
    fn encode<W: embedded_io::Write>(&self, e: &mut Encoder<W>)
        -> Result<(), W::Error> {
        e.array(self.len())?;
        for x in self { x.encode(e)? }
        Ok(())
    }
}
impl<T: CborLen> CborLen for alloc::collections::BTreeSet<T> {
    fn cbor_len(&self) -> usize {
        let n = self.len();
        n.cbor_len() + self.iter().map(|x| x.cbor_len()).sum::<usize>()
    }
}encode_sequential! {
165    alloc::vec::Vec<T>
166    alloc::collections::VecDeque<T>
167    alloc::collections::LinkedList<T>
168    alloc::collections::BinaryHeap<T>
169    alloc::collections::BTreeSet<T>
170}
171
172#[cfg(feature = "std")]
173impl<T: Encode> Encode for std::collections::HashSet<T> {
    fn encode<W: embedded_io::Write>(&self, e: &mut Encoder<W>)
        -> Result<(), W::Error> {
        e.array(self.len())?;
        for x in self { x.encode(e)? }
        Ok(())
    }
}
impl<T: CborLen> CborLen for std::collections::HashSet<T> {
    fn cbor_len(&self) -> usize {
        let n = self.len();
        n.cbor_len() + self.iter().map(|x| x.cbor_len()).sum::<usize>()
    }
}encode_sequential! {
174    std::collections::HashSet<T>
175}
176
177impl<T: Encode> Encode for [T] {
    fn encode<W: embedded_io::Write>(&self, e: &mut Encoder<W>)
        -> Result<(), W::Error> {
        e.array(self.len())?;
        for x in self { x.encode(e)? }
        Ok(())
    }
}
impl<T: CborLen> CborLen for [T] {
    fn cbor_len(&self) -> usize {
        let n = self.len();
        n.cbor_len() + self.iter().map(|x| x.cbor_len()).sum::<usize>()
    }
}encode_sequential!([T]);
178
179#[cfg(all(test, feature = "alloc"))]
180mod tests {
181    use crate::{CborLen, Decode, Decoder, Encode, Encoder, test};
182
183    const EMPTY_ARRAY: &[u8] = &[0x80];
184    const EMPTY_INDEF: &[u8] = &[0x9f, 0xff];
185
186    #[cfg(feature = "alloc")]
187    fn test_binary_heap<'a, T>(cbor: &'a [u8], expected: &[T])
188    where
189        T: Decode<'a> + Encode + CborLen + Ord + PartialEq + core::fmt::Debug,
190    {
191        use alloc::collections::BinaryHeap;
192
193        let heap = BinaryHeap::<T>::decode(&mut Decoder(cbor)).unwrap();
194        let mut buf = Vec::new();
195        heap.encode(&mut Encoder(&mut buf)).unwrap();
196        assert_eq!(heap.cbor_len(), buf.len());
197        assert_eq!(heap.into_sorted_vec(), expected);
198    }
199
200    #[test]
201    fn definite() {
202        #[cfg(feature = "alloc")]
203        {
204            use alloc::{collections::*, string::String, vec::Vec};
205
206            assert!(test::<Vec<&str>>(Vec::new(), EMPTY_ARRAY).unwrap());
207            assert!(
208                test(
209                    vec!["a", "b", "c"],
210                    &[0x83, 0x61, 0x61, 0x61, 0x62, 0x61, 0x63]
211                )
212                .unwrap()
213            );
214
215            assert!(test::<VecDeque<String>>(VecDeque::new(), EMPTY_ARRAY).unwrap());
216            assert!(
217                test(
218                    VecDeque::from([String::from("hi"), String::from("yo")]),
219                    &[0x82, 0x62, 0x68, 0x69, 0x62, 0x79, 0x6f]
220                )
221                .unwrap()
222            );
223
224            assert!(test::<LinkedList<Option<i32>>>(LinkedList::new(), EMPTY_ARRAY).unwrap());
225            assert!(
226                test(
227                    LinkedList::from([Some(-5), None, Some(10)]),
228                    &[0x83, 0x24, 0xf6, 0x0a]
229                )
230                .unwrap()
231            );
232
233            test_binary_heap::<usize>(EMPTY_ARRAY, &[]);
234            test_binary_heap::<usize>(
235                &[0x83, 0x18, 0x64, 0x18, 0xc8, 0x18, 0x96],
236                &[100, 150, 200],
237            );
238
239            assert!(test::<BTreeSet<i32>>(BTreeSet::new(), EMPTY_ARRAY).unwrap());
240            assert!(
241                test(
242                    BTreeSet::from([-10, 0, 10, 20]),
243                    &[0x84, 0x29, 0x00, 0x0a, 0x14]
244                )
245                .unwrap()
246            );
247        }
248
249        #[cfg(feature = "std")]
250        {
251            use std::collections::HashSet;
252            assert!(test::<HashSet<&str>>(HashSet::new(), EMPTY_ARRAY).unwrap());
253            test(
254                HashSet::from(["foo", "bar"]),
255                &[0x82, 0x63, 0x66, 0x6f, 0x6f, 0x63, 0x62, 0x61, 0x72],
256            )
257            .unwrap();
258        }
259    }
260
261    #[cfg(feature = "alloc")]
262    #[test]
263    fn indefinite() {
264        use alloc::{collections::*, string::String, vec::Vec};
265
266        assert!(!test::<Vec<&str>>(Vec::new(), EMPTY_INDEF).unwrap());
267        assert!(!test(vec!["x", "y"], &[0x9f, 0x61, 0x78, 0x61, 0x79, 0xff]).unwrap());
268
269        assert!(!test::<VecDeque<String>>(VecDeque::new(), EMPTY_INDEF).unwrap());
270        assert!(
271            !test(
272                VecDeque::from([String::from("a")]),
273                &[0x9f, 0x61, 0x61, 0xff]
274            )
275            .unwrap()
276        );
277
278        assert!(!test::<LinkedList<Option<i32>>>(LinkedList::new(), EMPTY_INDEF).unwrap());
279        assert!(!test(LinkedList::from([Some(1), None]), &[0x9f, 0x01, 0xf6, 0xff]).unwrap());
280
281        test_binary_heap::<usize>(EMPTY_INDEF, &[]);
282        test_binary_heap::<usize>(&[0x9f, 0x18, 0x32, 0x18, 0x64, 0xff], &[50, 100]);
283
284        assert!(!test::<BTreeSet<i32>>(BTreeSet::new(), EMPTY_INDEF).unwrap());
285        assert!(!test(BTreeSet::from([5, 10]), &[0x9f, 0x05, 0x0a, 0xff]).unwrap());
286
287        #[cfg(feature = "std")]
288        {
289            use std::collections::HashSet;
290            assert!(!test::<HashSet<&str>>(HashSet::new(), EMPTY_INDEF).unwrap());
291            assert!(
292                !test(
293                    HashSet::from(["test"]),
294                    &[0x9f, 0x64, 0x74, 0x65, 0x73, 0x74, 0xff]
295                )
296                .unwrap()
297            );
298        }
299    }
300
301    #[cfg(feature = "alloc")]
302    #[test]
303    fn nested() {
304        use alloc::{string::String, vec};
305        assert!(
306            test(
307                vec![
308                    vec![String::from("a")],
309                    vec![String::from("b"), String::from("c")]
310                ],
311                &[0x82, 0x81, 0x61, 0x61, 0x82, 0x61, 0x62, 0x61, 0x63]
312            )
313            .unwrap()
314        );
315    }
316
317    #[cfg(feature = "alloc")]
318    #[test]
319    fn long() {
320        use alloc::vec::Vec;
321        let mut cbor = vec![0x98, 25];
322        for i in 0..25 {
323            cbor.push(0x18);
324            cbor.push(i);
325        }
326        assert!(!test((0..25).map(|i| i as usize).collect::<Vec<usize>>(), &cbor).unwrap());
327    }
328}