Skip to main content

rs_matter/tlv/traits/
container.rs

1/*
2 *
3 *    Copyright (c) 2024-2025 Project CHIP Authors
4 *
5 *    Licensed under the Apache License, Version 2.0 (the "License");
6 *    you may not use this file except in compliance with the License.
7 *    You may obtain a copy of the License at
8 *
9 *        http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *    Unless required by applicable law or agreed to in writing, software
12 *    distributed under the License is distributed on an "AS IS" BASIS,
13 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *    See the License for the specific language governing permissions and
15 *    limitations under the License.
16 */
17
18//! A container type (`TLVContainer`) and an iterator type (`TLVContainerIter`) that represent and iterate directly over serialized TLV containers.
19//! As such, the memory prepresentation of `TLVContainer` and `TLVContainerIter` is just a byte slice (`&[u8]`),
20//! and the container elements are materialized (with `FromTLV`) only when the container is iterated over.
21//!
22//! The difference between `TLVContainer` and `TLVContainerIter` on one side, and `TLVElement`, `TLVSequence` and `TLVSequenceIter` on the other
23//! is that the former are generified by type `T: FromTLV<'_>` and can directly yield values of type `T` when iterated over,
24//! while iterating over a `TLVSequence` with a `TLVSequenceIter` always yields elements of type `TLVElement`.
25//!
26//! Thus, a `TLVContainer<TLVElement<'_>, ()`> is equivalent to a `TLVElement` which represents a container and
27//! `TLVContainerIter<TLVElement<'_>>` is equivalent to a `TLVSequenceIter<'_>` that is obtained by `element.container()?.iter()`.
28
29use core::fmt;
30use core::marker::PhantomData;
31
32use crate::error::Error;
33use crate::utils::init;
34
35use super::{EitherIter, FromTLV, TLVElement, TLVSequenceIter, TLVTag, TLVWrite, ToTLV, TLV};
36
37/// A type-state that indicates that the container can be any type of container (array, list or struct).
38pub type AnyContainer = ();
39
40/// A type-state that indicates that the container should be an array.
41#[derive(Debug, Clone, PartialEq, Eq, Hash)]
42#[cfg_attr(feature = "defmt", derive(defmt::Format))]
43pub struct ArrayContainer;
44
45/// A type-state that indicates that the container should be a list.
46#[derive(Debug, Clone, PartialEq, Eq, Hash)]
47#[cfg_attr(feature = "defmt", derive(defmt::Format))]
48pub struct ListContainer;
49
50/// A type-state that indicates that the container should be a struct.
51#[derive(Debug, Clone, PartialEq, Eq, Hash)]
52#[cfg_attr(feature = "defmt", derive(defmt::Format))]
53pub struct StructContainer;
54
55/// A type alias for an array TLV container.
56pub type TLVArray<'a, T> = TLVContainer<'a, T, ArrayContainer>;
57/// A type alias for a list TLV container.
58pub type TLVList<'a, T> = TLVContainer<'a, T, ListContainer>;
59/// A type alias for a struct TLV container.
60pub type TLVStruct<'a, T> = TLVContainer<'a, T, StructContainer>;
61
62/// `TLVContainer` is an efficient (memory-wise) way to represent a serialized TLV container, in that
63/// it does not materialize the container elements until the container is iterated over.
64///
65/// Therefore, `TLVContainer` is just a wrapper (newtype) of the serialized TLV container `&[u8]` slice.
66#[derive(Clone, PartialEq, Eq, Hash)]
67#[repr(transparent)]
68pub struct TLVContainer<'a, T, C = AnyContainer> {
69    element: TLVElement<'a>,
70    _type: PhantomData<fn() -> T>,
71    _container_type: PhantomData<C>,
72}
73
74impl<'a, T, C> TLVContainer<'a, T, C>
75where
76    T: FromTLV<'a>,
77{
78    /// Creates a new `TLVContainer` from a TLV element.
79    /// The constructor does not check whether the passed slice is a valid TLV container.
80    pub const fn new_unchecked(element: TLVElement<'a>) -> Self {
81        Self {
82            element,
83            _type: PhantomData,
84            _container_type: PhantomData,
85        }
86    }
87
88    pub fn element(&self) -> &TLVElement<'a> {
89        &self.element
90    }
91
92    /// Returns an iterator over the elements of the container.
93    pub fn iter(&self) -> TLVContainerIter<'a, T> {
94        TLVContainerIter::new(unwrap!(self.element.container()).iter())
95    }
96}
97
98impl<'a, T> TLVContainer<'a, T, AnyContainer>
99where
100    T: FromTLV<'a>,
101{
102    /// Creates a new `TLVContainer` from a TLV element that can be any container.
103    pub fn new(element: TLVElement<'a>) -> Result<Self, Error> {
104        if !element.is_empty() {
105            element.container()?;
106        }
107
108        Ok(Self::new_unchecked(element))
109    }
110}
111
112impl<'a, T> TLVContainer<'a, T, ArrayContainer>
113where
114    T: FromTLV<'a>,
115{
116    /// Creates a new `TLVContainer` from a TLV element that is expected to be of type array.
117    pub fn new(element: TLVElement<'a>) -> Result<Self, Error> {
118        if !element.is_empty() {
119            element.array()?;
120        }
121
122        Ok(Self::new_unchecked(element))
123    }
124}
125
126impl<'a, T> TLVContainer<'a, T, ListContainer>
127where
128    T: FromTLV<'a>,
129{
130    /// Creates a new `TLVContainer` from a TLV element that is expected to be of type list.
131    pub fn new(element: TLVElement<'a>) -> Result<Self, Error> {
132        if !element.is_empty() {
133            element.list()?;
134        }
135
136        Ok(Self::new_unchecked(element))
137    }
138}
139
140impl<'a, T> TLVContainer<'a, T, StructContainer>
141where
142    T: FromTLV<'a>,
143{
144    /// Creates a new `TLVContainer` from a TLV element that is expected to be of type struct.
145    pub fn new(element: TLVElement<'a>) -> Result<Self, Error> {
146        if !element.is_empty() {
147            element.structure()?;
148        }
149
150        Ok(Self::new_unchecked(element))
151    }
152}
153
154impl<'a, T, C> IntoIterator for TLVContainer<'a, T, C>
155where
156    T: FromTLV<'a>,
157{
158    type Item = Result<T, Error>;
159    type IntoIter = TLVContainerIter<'a, T>;
160
161    fn into_iter(self) -> Self::IntoIter {
162        self.iter()
163    }
164}
165
166impl<'a, T, C> IntoIterator for &TLVContainer<'a, T, C>
167where
168    T: FromTLV<'a>,
169{
170    type Item = Result<T, Error>;
171    type IntoIter = TLVContainerIter<'a, T>;
172
173    fn into_iter(self) -> Self::IntoIter {
174        self.iter()
175    }
176}
177
178impl<'a, T, C> fmt::Debug for TLVContainer<'a, T, C>
179where
180    T: FromTLV<'a> + fmt::Debug,
181{
182    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183        write!(f, "[")?;
184
185        let mut first = true;
186
187        for elem in self.iter() {
188            if first {
189                first = false;
190                write!(f, "{elem:?}")?;
191            } else {
192                write!(f, ", {elem:?}")?;
193            }
194        }
195
196        write!(f, "]")
197    }
198}
199
200#[cfg(feature = "defmt")]
201impl<'a, T, C> defmt::Format for TLVContainer<'a, T, C>
202where
203    T: FromTLV<'a> + defmt::Format,
204{
205    fn format(&self, f: defmt::Formatter<'_>) {
206        defmt::write!(f, "[");
207
208        let mut first = true;
209
210        for elem in self.iter() {
211            if first {
212                first = false;
213                defmt::write!(f, "{:?}", elem);
214            } else {
215                defmt::write!(f, ", {:?}", elem);
216            }
217        }
218
219        defmt::write!(f, "]")
220    }
221}
222
223impl<'a, T, C> FromTLV<'a> for TLVContainer<'a, T, C>
224where
225    T: FromTLV<'a>,
226    C: 'a,
227{
228    fn from_tlv(element: &TLVElement<'a>) -> Result<Self, Error> {
229        Ok(Self::new_unchecked(element.clone()))
230    }
231}
232
233impl<T, C> ToTLV for TLVContainer<'_, T, C> {
234    fn to_tlv<W: TLVWrite>(&self, tag: &TLVTag, tw: W) -> Result<(), Error> {
235        self.element.to_tlv(tag, tw)
236    }
237
238    fn tlv_iter(&self, tag: TLVTag) -> impl Iterator<Item = Result<TLV<'_>, Error>> {
239        self.element.tlv_iter(tag)
240    }
241}
242
243/// An iterator over a serialized TLV container.
244#[repr(transparent)]
245pub struct TLVContainerIter<'a, T> {
246    iter: TLVSequenceIter<'a>,
247    _type: PhantomData<fn() -> T>,
248}
249
250impl<'a, T> TLVContainerIter<'a, T>
251where
252    T: FromTLV<'a>,
253{
254    /// Create a new `TLVContainerIter` from a TLV sequence iterator.
255    pub const fn new(iter: TLVSequenceIter<'a>) -> Self {
256        Self {
257            iter,
258            _type: PhantomData,
259        }
260    }
261
262    pub fn try_next(&mut self) -> Option<Result<T, Error>> {
263        let tlv = self.iter.next()?;
264
265        Some(tlv.and_then(|tlv| T::from_tlv(&tlv)))
266    }
267
268    pub fn try_next_init(&mut self) -> Option<Result<impl init::Init<T, Error> + 'a, Error>> {
269        let tlv = self.iter.next()?;
270
271        Some(tlv.map(|tlv| T::init_from_tlv(tlv)))
272    }
273}
274
275impl<'a, T> Iterator for TLVContainerIter<'a, T>
276where
277    T: FromTLV<'a>,
278{
279    type Item = Result<T, Error>;
280
281    fn next(&mut self) -> Option<Self::Item> {
282        self.try_next()
283    }
284}
285
286/// A container type that can represent either a serialized TLV array or a slice of elements.
287///
288/// Necessary for the few cases in the code where deserialized TLV structures are mutated -
289/// post deserialization - with custom array data.
290#[derive(Debug, Clone)]
291#[cfg_attr(feature = "defmt", derive(defmt::Format))]
292pub enum TLVArrayOrSlice<'a, T>
293where
294    T: FromTLV<'a>,
295{
296    Array(TLVArray<'a, T>),
297    Slice(&'a [T]),
298}
299
300impl<'a, T> TLVArrayOrSlice<'a, T>
301where
302    T: FromTLV<'a>,
303{
304    /// Creates a new `TLVArrayOrSlice` from a TLV slice.
305    pub const fn new_array(array: TLVArray<'a, T>) -> Self {
306        Self::Array(array)
307    }
308
309    /// Creates a new `TLVArrayOrSlice` from a slice.
310    pub const fn new_slice(slice: &'a [T]) -> Self {
311        Self::Slice(slice)
312    }
313
314    /// Returns an iterator over the elements of the array.
315    pub fn iter(&self) -> Result<TLVArrayOrSliceIter<'a, T>, Error> {
316        match self {
317            Self::Array(array) => Ok(TLVArrayOrSliceIter::Array(array.iter())),
318            Self::Slice(slice) => Ok(TLVArrayOrSliceIter::Slice(slice.iter())),
319        }
320    }
321}
322
323impl<'a, T> FromTLV<'a> for TLVArrayOrSlice<'a, T>
324where
325    T: FromTLV<'a>,
326{
327    fn from_tlv(element: &TLVElement<'a>) -> Result<Self, Error> {
328        Ok(Self::new_array(TLVArray::new(element.clone())?))
329    }
330}
331
332impl<'a, T> ToTLV for TLVArrayOrSlice<'a, T>
333where
334    T: FromTLV<'a>,
335    T: ToTLV,
336{
337    fn to_tlv<W: TLVWrite>(&self, tag: &TLVTag, tw: W) -> Result<(), Error> {
338        match self {
339            Self::Array(array) => array.to_tlv(tag, tw),
340            Self::Slice(slice) => slice.to_tlv(tag, tw),
341        }
342    }
343
344    fn tlv_iter(&self, tag: TLVTag) -> impl Iterator<Item = Result<TLV<'_>, Error>> {
345        match self {
346            Self::Array(array) => EitherIter::First(array.tlv_iter(tag)),
347            Self::Slice(slice) => EitherIter::Second(slice.tlv_iter(tag)),
348        }
349    }
350}
351
352/// An iterator over the `TLVArrayOrSlice` elements.
353pub enum TLVArrayOrSliceIter<'a, T> {
354    Array(TLVContainerIter<'a, T>),
355    Slice(core::slice::Iter<'a, T>),
356}
357
358impl<'a, T> Iterator for TLVArrayOrSliceIter<'a, T>
359where
360    T: FromTLV<'a> + Clone,
361{
362    type Item = Result<T, Error>;
363
364    fn next(&mut self) -> Option<Self::Item> {
365        match self {
366            Self::Array(array) => array.next(),
367            Self::Slice(slice) => slice.next().cloned().map(|t| Ok(t)),
368        }
369    }
370}
371
372// impl<'a, T: ToTLV + FromTLV<'a> + Clone> TLVArray<'a, T> {
373//     pub fn get_index(&self, index: usize) -> T {
374//         for (curr, element) in self.iter().enumerate() {
375//             if curr == index {
376//                 return element;
377//             }
378//         }
379//         panic!("Out of bounds");
380//     }
381// }
382
383// // impl<'a, 'b, T> PartialEq<TLVArray<'b, T>> for TLVArray<'a, T>
384// // where
385// //     T: ToTLV + FromTLV<'a> + Clone + PartialEq,
386// //     'b: 'a,
387// // {
388// //     fn eq(&self, other: &TLVArray<'b, T>) -> bool {
389// //         let mut iter1 = self.iter();
390// //         let mut iter2 = other.iter();
391// //         loop {
392// //             match (iter1.next(), iter2.next()) {
393// //                 (None, None) => return true,
394// //                 (Some(x), Some(y)) => {
395// //                     if x != y {
396// //                         return false;
397// //                     }
398// //                 }
399// //                 _ => return false,
400// //             }
401// //         }
402// //     }
403// // }
404
405// // impl<'a, T> PartialEq<&[T]> for TLVArray<'a, T>
406// // where
407// //     T: ToTLV + FromTLV<'a> + Clone + PartialEq,
408// // {
409// //     fn eq(&self, other: &&[T]) -> bool {
410// //         let mut iter1 = self.iter();
411// //         let mut iter2 = other.iter();
412// //         loop {
413// //             match (iter1.next(), iter2.next()) {
414// //                 (None, None) => return true,
415// //                 (Some(x), Some(y)) => {
416// //                     if x != *y {
417// //                         return false;
418// //                     }
419// //                 }
420// //                 _ => return false,
421// //             }
422// //         }
423// //     }
424// // }
425
426// impl<'a, T> FromTLV<'a> for TLVArray<'a, T> {
427//     fn from_tlv(t: TLVElement<'a>) -> Result<Self, Error> {
428//         TLVArray::new(t)
429//     }
430// }
431
432// impl<'a, T> ToTLV for TLVArray<'a, T> {
433//     fn to_tlv(&self, tw: &mut TLVWriter, tag_type: TagType) -> Result<(), Error> {
434//         tw.start_array(tag_type)?;
435//         for a in self.iter() {
436//             a.to_tlv(tw, TagType::Anonymous)?;
437//         }
438//         tw.end_container()
439//         // match *self {
440//         //     Self::Slice(s) => {
441//         //         tw.start_array(tag_type)?;
442//         //         for a in s {
443//         //             a.to_tlv(tw, TagType::Anonymous)?;
444//         //         }
445//         //         tw.end_container()
446//         //     }
447//         //     Self::Ptr(t) => t.to_tlv(tw, tag_type), <-- TODO: this fails the unit tests of Cert from/to TLV
448//         // }
449//     }
450
451//     fn tlv_iter(&self, tag: TagType) -> impl Iterator<Item = u8> + '_ {
452//         empty()
453//             .start_array(tag)
454//             .chain(self.iter().flat_map(move |i| i.into_tlv_iter(TagType::Anonymous)))
455//             .end_container()
456//     }
457
458//     fn into_tlv_iter(self, tag: TagType) -> impl Iterator<Item = u8> where Self: Sized {
459//         empty()
460//             .start_array(tag)
461//             .chain(self.into_iter().flat_map(move |i| i.into_tlv_iter(TagType::Anonymous)))
462//             .end_container()
463//     }
464// }
465
466// impl<'a, T: Debug + ToTLV + FromTLV<'a> + Clone> Debug for TLVArray<'a, T> { // TODO: defmt
467//     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
468//         write!(f, "TLVArray [")?;
469//         let mut first = true;
470//         for i in self.iter() {
471//             if !first {
472//                 write!(f, ", ")?;
473//             }
474
475//             write!(f, "{:?}", i)?;
476//             first = false;
477//         }
478//         write!(f, "]")
479//     }
480// }