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