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}