cbor_data/validated/
iterators.rs

1use super::CborIter;
2use crate::Cbor;
3use std::{
4    borrow::Cow,
5    fmt::{Debug, Display, Formatter, Write},
6    io::Read,
7};
8
9/// Iterator yielding the fragments of a text string item
10///
11/// Parsing an item can in general not return a contiguous string due to
12/// [indefinite-length encoding](https://www.rfc-editor.org/rfc/rfc8949.html#section-3.2.3).
13/// This Iterator gives you the choice whether you want to inspect the fragments or build
14/// a contiguous string by allocating the necessary memory.
15#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
16pub struct StringIter<'a>(CborIter<'a>);
17
18impl<'a> StringIter<'a> {
19    pub(crate) fn new(bytes: &'a [u8], len: Option<u64>) -> Self {
20        Self(CborIter::new(bytes, len))
21    }
22
23    /// Indicates whether the underlying encoding was definite or indefinite
24    ///
25    /// If you want to check whether the string is available as contiguous slice, see
26    /// [`as_str`](#method.as_str), which will also work for 0- and 1-fragment strings
27    /// using indefinite-length encoding.
28    pub fn is_indefinite(&self) -> bool {
29        self.0.size().is_none()
30    }
31
32    /// Returns true if the string consists of zero fragments
33    ///
34    /// **A return value of `false` does not indicate that the string contains characters!**
35    pub fn is_empty(&self) -> bool {
36        let mut this = *self;
37        this.next().is_none()
38    }
39
40    /// Try to borrow the string as a single slice
41    ///
42    /// This will only succeed for definite length encoding or strings with 0 or 1 fragments.
43    pub fn as_str(&self) -> Option<&'a str> {
44        let mut this = *self;
45        if let Some(first) = this.next() {
46            if this.next().is_none() {
47                Some(first)
48            } else {
49                None
50            }
51        } else {
52            Some("")
53        }
54    }
55
56    /// Extract the full string, borrowing if possible and allocating if necessary
57    pub fn as_cow(&self) -> Cow<'a, str> {
58        if let Some(s) = self.as_str() {
59            Cow::Borrowed(s)
60        } else {
61            Cow::Owned(self.collect())
62        }
63    }
64
65    /// compute the total length of all contained slices
66    pub fn len(&self) -> usize {
67        self.map(|v| v.len()).sum()
68    }
69}
70
71impl<'a> Debug for StringIter<'a> {
72    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
73        f.write_str("StringIter")
74    }
75}
76
77impl<'a> Display for StringIter<'a> {
78    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
79        for s in *self {
80            f.write_str(s)?;
81        }
82        Ok(())
83    }
84}
85
86impl<'a> Iterator for StringIter<'a> {
87    type Item = &'a str;
88
89    fn next(&mut self) -> Option<Self::Item> {
90        let v = self
91            .0
92            .next()?
93            .0
94            .expect("string fragments must be in definite size encoding");
95        Some(unsafe { std::str::from_utf8_unchecked(v) })
96    }
97}
98
99impl<'a, S: AsRef<str>> PartialEq<S> for StringIter<'a> {
100    fn eq(&self, other: &S) -> bool {
101        let this = *self;
102        let mut other = other.as_ref();
103        for prefix in this {
104            if other.starts_with(prefix) {
105                other = &other[prefix.len()..];
106            } else {
107                return false;
108            }
109        }
110        other.is_empty()
111    }
112}
113
114/// Iterator yielding the fragments of a byte string item
115///
116/// Parsing an item can in general not return a contiguous string due to
117/// [indefinite-length encoding](https://www.rfc-editor.org/rfc/rfc8949.html#section-3.2.3).
118/// This Iterator gives you the choice whether you want to inspect the fragments or build
119/// a contiguous string by allocating the necessary memory.
120#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
121pub struct BytesIter<'a>(CborIter<'a>, &'a [u8]);
122
123impl<'a> BytesIter<'a> {
124    pub(crate) fn new(bytes: &'a [u8], len: Option<u64>) -> Self {
125        Self(CborIter::new(bytes, len), b"")
126    }
127
128    /// Indicates whether the underlying encoding was definite or indefinite
129    ///
130    /// If you want to check whether the string is available as contiguous slice, see
131    /// [`as_slice`](#method.as_slice), which will also work for 0- and 1-fragment strings
132    /// using indefinite-length encoding.
133    pub fn is_indefinite(&self) -> bool {
134        self.0.size().is_none()
135    }
136
137    /// Returns true if the string consists of zero fragments
138    ///
139    /// **A return value of `false` does not indicate that the string contains bytes!**
140    pub fn is_empty(&self) -> bool {
141        let mut this = *self;
142        this.next().is_none()
143    }
144
145    /// Try to borrow the string as a single slice
146    ///
147    /// This will only succeed for definite length encoding or strings with 0 or 1 fragments.
148    pub fn as_slice(&self) -> Option<&'a [u8]> {
149        let mut this = *self;
150        if let Some(first) = this.next() {
151            if this.next().is_none() {
152                Some(first)
153            } else {
154                None
155            }
156        } else {
157            Some(b"")
158        }
159    }
160
161    /// Extract the full string, borrowing if possible and allocating if necessary
162    pub fn as_cow(&self) -> Cow<'a, [u8]> {
163        if let Some(s) = self.as_slice() {
164            Cow::Borrowed(s)
165        } else {
166            let mut v = Vec::new();
167            for b in *self {
168                v.extend_from_slice(b);
169            }
170            Cow::Owned(v)
171        }
172    }
173
174    /// Extract the full string by allocating a fresh Vec
175    pub fn to_vec(self) -> Vec<u8> {
176        let mut ret = Vec::new();
177        for v in self {
178            ret.extend_from_slice(v);
179        }
180        ret
181    }
182
183    /// compute the total length of all contained slices
184    pub fn len(&self) -> usize {
185        self.map(|v| v.len()).sum()
186    }
187}
188
189impl<'a> Debug for BytesIter<'a> {
190    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
191        f.write_str("BytesIter")
192    }
193}
194
195impl<'a> Display for BytesIter<'a> {
196    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
197        let mut first = true;
198        for b in *self {
199            if first {
200                first = false;
201            } else {
202                f.write_char(' ')?;
203            }
204            for byte in b {
205                write!(f, "{:02x}", byte)?;
206            }
207        }
208        Ok(())
209    }
210}
211
212impl<'a> Iterator for BytesIter<'a> {
213    type Item = &'a [u8];
214
215    fn next(&mut self) -> Option<Self::Item> {
216        Some(
217            self.0
218                .next()?
219                .0
220                .expect("byte string fragments must be in definite size encoding"),
221        )
222    }
223}
224
225impl<'a> Read for BytesIter<'a> {
226    fn read(&mut self, mut buf: &mut [u8]) -> std::io::Result<usize> {
227        let mut in_hand = self.1;
228        let mut read = 0;
229        loop {
230            let transfer = in_hand.len().min(buf.len());
231            let (left, right) = buf.split_at_mut(transfer);
232            left.copy_from_slice(&in_hand[..transfer]);
233            in_hand = &in_hand[transfer..];
234            buf = right;
235            read += transfer;
236            if buf.is_empty() {
237                break;
238            }
239            // in_hand must be empty
240            if let Some(bytes) = self.next() {
241                in_hand = bytes;
242            } else {
243                break;
244            }
245        }
246        self.1 = in_hand;
247        Ok(read)
248    }
249}
250
251impl<'a, S: AsRef<[u8]>> PartialEq<S> for BytesIter<'a> {
252    fn eq(&self, other: &S) -> bool {
253        let this = *self;
254        let mut other = other.as_ref();
255        for prefix in this {
256            if other.starts_with(prefix) {
257                other = &other[prefix.len()..];
258            } else {
259                return false;
260            }
261        }
262        other.is_empty()
263    }
264}
265
266/// Iterator over the CBOR items within an array
267#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
268pub struct ArrayIter<'a>(CborIter<'a>);
269
270impl<'a> ArrayIter<'a> {
271    pub(crate) fn new(bytes: &'a [u8], len: Option<u64>) -> Self {
272        Self(CborIter::new(bytes, len))
273    }
274
275    /// Number of items still remaining, or `None` in case of
276    /// [indefinite-length encoding](https://www.rfc-editor.org/rfc/rfc8949.html#section-3.2.2)
277    pub fn size(&self) -> Option<u64> {
278        self.0.size()
279    }
280}
281
282impl<'a> Debug for ArrayIter<'a> {
283    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
284        f.write_str("ArrayIter")
285    }
286}
287impl<'a> Iterator for ArrayIter<'a> {
288    type Item = &'a Cbor;
289
290    fn next(&mut self) -> Option<Self::Item> {
291        Some(self.0.next()?.1)
292    }
293}
294
295/// Iterator over the key–value mappings within a dictionary
296#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
297pub struct DictIter<'a>(CborIter<'a>);
298
299impl<'a> DictIter<'a> {
300    pub(crate) fn new(bytes: &'a [u8], len: Option<u64>) -> Self {
301        Self(CborIter::new(bytes, len.map(|x| x * 2)))
302    }
303
304    /// Number of items still remaining, or `None` in case of
305    /// [indefinite-length encoding](https://www.rfc-editor.org/rfc/rfc8949.html#section-3.2.2)
306    pub fn size(&self) -> Option<u64> {
307        self.0.size().map(|x| x / 2)
308    }
309}
310
311impl<'a> Debug for DictIter<'a> {
312    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
313        f.write_str("DictIter")
314    }
315}
316impl<'a> Iterator for DictIter<'a> {
317    type Item = (&'a Cbor, &'a Cbor);
318
319    fn next(&mut self) -> Option<Self::Item> {
320        Some((self.0.next()?.1, self.0.next()?.1))
321    }
322}