rs_matter/tlv/traits/vec.rs
1/*
2 *
3 * Copyright (c) 2024-2026 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//! TLV support for the `Vec<T, N>` type.
19//! `Vec<T, N>` is serialized and deserialized as a TLV array.
20//!
21//! Unlike Rust `[T; N]` arrays, the `Vec` type can be efficiently deserialized in-place, so use it
22//! when the array holds large structures (like fabrics, certificates, sessions and so on).
23//!
24//! Of course, the `Vec` type is always owned (even if the deserialized elements `T` do borrow from the
25//! deserializer), so it might consume more memory than necessary, as its memory is statically allocated
26//! to be N * size_of(T) bytes.
27//!
28//! For cases where the array does not need to be owned and instantiating `T` elements on the fly when
29//! traversing the array is tolerable (i.e. `T` is small enough), prefer `TLVArray`, which operates
30//! directly on the borrowed, encoded TLV representation of the whole array.
31
32use crate::error::{Error, ErrorCode};
33use crate::utils::init::{self, IntoFallibleInit};
34use crate::utils::storage::Vec;
35
36use super::{slice::tlv_array_iter, FromTLV, TLVArray, TLVElement, TLVTag, TLVWrite, ToTLV, TLV};
37
38impl<'a, T, const N: usize> FromTLV<'a> for Vec<T, N>
39where
40 T: FromTLV<'a> + 'a,
41{
42 fn from_tlv(element: &TLVElement<'a>) -> Result<Self, Error> {
43 let mut vec = Vec::<T, N>::new();
44
45 for item in TLVArray::new(element.clone())? {
46 vec.push(item?).map_err(|_| ErrorCode::ConstraintError)?;
47 }
48
49 Ok(vec)
50 }
51
52 fn init_from_tlv(tlv: TLVElement<'a>) -> impl init::Init<Self, Error> {
53 init::Init::chain(Vec::<T, N>::init().into_fallible(), move |vec| {
54 let mut iter = TLVArray::new(tlv)?.iter();
55
56 while let Some(item) = iter.try_next_init() {
57 vec.push_init(item?, || ErrorCode::ConstraintError.into())?;
58 }
59
60 Ok(())
61 })
62 }
63}
64
65impl<T, const N: usize> ToTLV for Vec<T, N>
66where
67 T: ToTLV,
68{
69 fn to_tlv<W: TLVWrite>(&self, tag: &TLVTag, tw: W) -> Result<(), Error> {
70 self.as_slice().to_tlv(tag, tw)
71 }
72
73 fn tlv_iter(&self, tag: TLVTag) -> impl Iterator<Item = Result<TLV<'_>, Error>> {
74 tlv_array_iter(tag, self.iter())
75 }
76}
77
78/// TLV support for the heap-allocated `alloc::vec::Vec<T>` (unbounded, no `N`).
79/// Serialized/deserialized as a TLV array, like the bounded `Vec<T, N>` above.
80#[cfg(feature = "alloc")]
81impl<'a, T> FromTLV<'a> for alloc::vec::Vec<T>
82where
83 T: FromTLV<'a> + 'a,
84{
85 fn from_tlv(element: &TLVElement<'a>) -> Result<Self, Error> {
86 let mut vec = alloc::vec::Vec::new();
87
88 for item in TLVArray::new(element.clone())? {
89 vec.push(item?);
90 }
91
92 Ok(vec)
93 }
94}
95
96#[cfg(feature = "alloc")]
97impl<T> ToTLV for alloc::vec::Vec<T>
98where
99 T: ToTLV,
100{
101 fn to_tlv<W: TLVWrite>(&self, tag: &TLVTag, tw: W) -> Result<(), Error> {
102 self.as_slice().to_tlv(tag, tw)
103 }
104
105 fn tlv_iter(&self, tag: TLVTag) -> impl Iterator<Item = Result<TLV<'_>, Error>> {
106 tlv_array_iter(tag, self.iter())
107 }
108}