tps_minicbor/
array.rs

1/***************************************************************************************************
2 * Copyright (c) 2021, 2022 Qualcomm Innovation Center, Inc. All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 * and associated documentation files (the “Software”), to deal in the Software without
6 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
7 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice (including the next
11 * paragraph) shall be included in all copies or substantial portions of the
12 * Software.
13 *
14 * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
15 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
17 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 **************************************************************************************************/
20/***************************************************************************************************
21 * rs_minicbor CBOR Array deserialser API
22 *
23 * A fairly comprehensive, memory efficient, deserializer and serializer for CBOR (RFC7049).
24 * This implementation is designed for use in constrained systems and requires neither the Rust
25 * standard library nor an allocator.
26 **************************************************************************************************/
27use std::convert::TryFrom;
28use crate::ast::CBOR;
29use crate::decode::{DecodeBufIterator, DecodeBufIteratorSource};
30
31#[cfg(feature = "trace")]
32use func_trace::trace;
33use crate::encode::{EncodeBuffer, EncodeContext, EncodeItem};
34use crate::error::CBORError;
35
36#[cfg(feature = "trace")]
37func_trace::init_depth_var!();
38
39/***************************************************************************************************
40 * Decoding Arrays
41 **************************************************************************************************/
42/// A buffer which contains a CBOR Array to be decoded. The buffer has lifetime `'buf`,
43/// which must be longer than any borrow from the buffer itself. This is generally used to represent
44/// a CBOR array with an exposed slice-like API.
45///
46/// This CBOR buffer implementation does not support indefinite length items.
47#[derive(PartialEq, Debug, Copy, Clone)]
48pub struct ArrayBuf<'buf> {
49    bytes: &'buf [u8],
50    n_items: usize,
51}
52
53impl<'buf> ArrayBuf<'buf> {
54    /// Construct a new instance of `ArrayBuf` with all context initialized.
55    #[cfg_attr(feature = "trace", trace)]
56    pub fn new(init: &'buf [u8], n_items: usize) -> ArrayBuf<'buf> {
57        ArrayBuf {
58            bytes: init,
59            n_items,
60        }
61    }
62
63    /// Return the number of items in the `ArrayBuf`.
64    #[cfg_attr(feature = "trace", trace)]
65    #[inline]
66    pub fn len(&self) -> usize {
67        self.n_items
68    }
69
70    /// Return `true` if `ArrayBuf` is empty.
71    #[cfg_attr(feature = "trace", trace)]
72    #[inline]
73    pub fn is_empty(&self) -> bool {
74        self.n_items == 0 && self.bytes.len() == 0
75    }
76
77    /// Return the `n`th value (zero indexed) in the `ArrayBuf` as a CBOR item.
78    ///
79    /// Worst case performance of this function is O(n) in standalone form, but performance is
80    /// likely to be O(n^2) if used for random access in general.
81    #[cfg_attr(feature = "trace", trace)]
82    pub fn index(&self, n: usize) -> Option<CBOR> {
83        let mut count = 0;
84        let mut it = self.into_iter();
85        let mut item = it.next();
86        while count < n && Option::is_some(&item) {
87            item = it.next();
88            count += 1;
89        }
90        item
91    }
92
93    /// Return the `n`th value (zero indexed) in the `ArrayBuf`, converted (fallibly) from CBOR.
94    ///
95    /// Worst case performance of this function is O(n) in standalone form, but performance is
96    /// likely to be O(n^2) if used for random access in general.
97    pub fn item<V>(&'buf self, idx: usize) -> Result<V, CBORError>
98    where V: TryFrom<CBOR<'buf>> + Clone
99    {
100        match self.index(idx) {
101            Some(cbor) => match V::try_from(cbor) {
102                Ok(v) => Ok(v.clone()),
103                Err(_) => Err(CBORError::IncompatibleType)
104            },
105            None => Err(CBORError::IndexOutOfBounds)
106        }
107    }
108}
109
110impl<'buf> IntoIterator for ArrayBuf<'buf> {
111    type Item = CBOR<'buf>;
112    type IntoIter = DecodeBufIterator<'buf>;
113
114    /// Construct an Iterator adapter from a `DecodeBuf`.
115    #[cfg_attr(feature = "trace", trace)]
116    fn into_iter(self) -> Self::IntoIter {
117        DecodeBufIterator {
118            buf: self.bytes,
119            index: 0,
120            source: DecodeBufIteratorSource::Array,
121        }
122    }
123}
124
125/***************************************************************************************************
126 * Encoding Arrays
127 **************************************************************************************************/
128
129/// A container structure for the closure used to manage encoding of CBOR arrays, and in particular
130/// to ensure that the correct lifetime bounds are specified.
131///
132/// The user is able to encode members of the array within a closure, and the array length will
133/// automatically be correctly constructed. Arbitrary nesting of arrays and maps is supported.
134///
135/// Users should never need to directly instantiate `Array`. Instead, see [`array`].
136pub struct Array<F>
137where F: for<'f, 'buf> Fn(&'f mut EncodeBuffer<'buf>) -> Result<&'f mut EncodeBuffer<'buf>, CBORError> {
138    f: F
139}
140
141/// `Array` provides a constructor to contain the closure that constructs it
142impl<F> Array<F> where
143    F: for<'f, 'buf> Fn(&'f mut EncodeBuffer<'buf>) -> Result<&'f mut EncodeBuffer<'buf>, CBORError> {
144    pub fn new(f: F) -> Array<F> { Array { f } }
145}
146
147/// The [`EncodeItem`] instance for `Array` performs the required manipulations to correctly
148/// calculate the size of the array.
149impl<F> EncodeItem for Array<F>
150where F: for<'f, 'buf> Fn(&'f mut EncodeBuffer<'buf>) -> Result<&'f mut EncodeBuffer<'buf>, CBORError>
151{
152    fn encode<'f, 'buf>(&self, buf: &'f mut EncodeBuffer<'buf>) -> Result<&'f mut EncodeBuffer<'buf>, CBORError> {
153        let mut array_ctx = EncodeContext::new();
154        buf.array_start(&mut array_ctx)?;
155        let _ = (self.f)(buf)?;
156        buf.array_finalize(&array_ctx)?;
157        Ok(buf)
158    }
159}
160
161/// A convenience function for the user to create an instance of a CBOR array. The user provides a
162/// closure which constructs the array contents.
163///
164/// ```
165///# use tps_minicbor::encoder::CBORBuilder;
166///# use tps_minicbor::error::CBORError;
167///# use tps_minicbor::types::array;
168///
169///# fn main() -> Result<(), CBORError> {
170///    let mut buffer = [0u8; 16];
171///    let expected : &[u8] = &[132, 1, 2, 3, 4];
172///
173///    let mut encoder = CBORBuilder::new(&mut buffer);
174///    let _ = encoder.insert(&array(|buff| {
175///        buff.insert(&1)?.insert(&2)?.insert(&3)?.insert(&4)
176///    }));
177///    assert_eq!(encoder.encoded()?, expected);
178///#    Ok(())
179///# }
180/// ```
181pub fn array<F>(f: F) -> Array<F>
182    where F: for<'f, 'buf> Fn(&'f mut EncodeBuffer<'buf>) -> Result<&'f mut EncodeBuffer<'buf>, CBORError>
183{
184    Array::new(f)
185}