1use crate::error::Error;
19use crate::utils::init;
20
21use super::{
22 EitherIter, TLVElement, TLVSequenceIter, TLVSequenceTLVIter, TLVTag, TLVValue, TLVValueType,
23 TLVWrite, TLV,
24};
25
26pub use builder::*;
27pub use container::*;
28pub use maybe::*;
29pub use octets::*;
30pub use skippable::*;
31pub use slice::*;
32pub use str::*;
33
34mod array;
35mod bitflags;
36mod builder;
37mod container;
38mod maybe;
39mod octets;
40mod primitive;
41mod skippable;
42mod slice;
43mod str;
44mod vec;
45
46pub trait FromTLV<'a>: Sized + 'a {
49 fn from_tlv(element: &TLVElement<'a>) -> Result<Self, Error>;
51
52 fn init_from_tlv(element: TLVElement<'a>) -> impl init::Init<Self, Error> {
55 unsafe {
56 init::init_from_closure(move |slot| {
57 core::ptr::write(slot, Self::from_tlv(&element)?);
58
59 Ok(())
60 })
61 }
62 }
63
64 fn nullable_from_tlv(element: &TLVElement<'a>) -> Result<Self, Error> {
70 Self::from_tlv(element)
71 }
72
73 fn init_nullable_from_tlv(element: TLVElement<'a>) -> impl init::Init<Self, Error> {
80 unsafe {
81 init::init_from_closure(move |slot| {
82 core::ptr::write(slot, Self::nullable_from_tlv(&element)?);
83
84 Ok(())
85 })
86 }
87 }
88}
89
90pub trait ToTLV {
93 fn to_tlv<W: TLVWrite>(&self, tag: &TLVTag, tw: W) -> Result<(), Error>;
95
96 fn tlv_iter(&self, tag: TLVTag) -> impl Iterator<Item = Result<TLV<'_>, Error>>;
99
100 fn nullable_to_tlv<W: TLVWrite>(&self, tag: &TLVTag, tw: W) -> Result<(), Error> {
106 self.to_tlv(tag, tw)
107 }
108
109 fn nullable_tlv_iter(&self, tag: TLVTag) -> impl Iterator<Item = Result<TLV<'_>, Error>> {
116 self.tlv_iter(tag)
117 }
118}
119
120impl<T> ToTLV for &T
121where
122 T: ToTLV,
123{
124 fn to_tlv<W: TLVWrite>(&self, tag: &TLVTag, tw: W) -> Result<(), Error> {
125 (*self).to_tlv(tag, tw)
126 }
127
128 fn tlv_iter(&self, tag: TLVTag) -> impl Iterator<Item = Result<TLV<'_>, Error>> {
129 (*self).tlv_iter(tag)
130 }
131
132 fn nullable_to_tlv<W: TLVWrite>(&self, tag: &TLVTag, tw: W) -> Result<(), Error> {
133 (*self).nullable_to_tlv(tag, tw)
134 }
135
136 fn nullable_tlv_iter(&self, tag: TLVTag) -> impl Iterator<Item = Result<TLV<'_>, Error>> {
137 (*self).nullable_tlv_iter(tag)
138 }
139}
140
141impl<'a> FromTLV<'a> for TLVElement<'a> {
142 fn from_tlv(element: &TLVElement<'a>) -> Result<Self, Error> {
143 Ok(element.clone())
144 }
145}
146
147impl ToTLV for TLVElement<'_> {
148 fn to_tlv<W: TLVWrite>(&self, tag: &TLVTag, mut tw: W) -> Result<(), Error> {
149 if self.is_empty() {
150 Ok(())
153 } else {
154 let value_type = self.control()?.value_type;
155 let payload = self.raw_value()?;
156
157 let size_len = value_type.variable_size_len();
163 if size_len > 0 {
164 let len_bytes = (payload.len() as u64).to_le_bytes();
165 tw.raw_value(tag, value_type, &len_bytes[..size_len])?;
166 tw.write_raw_data(payload.iter().copied())
167 } else {
168 tw.raw_value(tag, value_type, payload)
169 }
170 }
171 }
172
173 fn tlv_iter(&self, tag: TLVTag) -> impl Iterator<Item = Result<TLV<'_>, Error>> {
174 TLVElementTLVIter::Start(tag, self.clone())
175 }
176}
177
178enum TLVElementTLVIter<'a> {
179 Start(TLVTag, TLVElement<'a>),
180 Seq(TLVSequenceTLVIter<'a>),
181 Finished,
182}
183
184impl<'a> Iterator for TLVElementTLVIter<'a> {
185 type Item = Result<TLV<'a>, Error>;
186
187 fn next(&mut self) -> Option<Self::Item> {
188 match core::mem::replace(self, Self::Finished) {
189 TLVElementTLVIter::Start(tag, elem) => {
190 if elem.is_empty() {
191 None
194 } else {
195 let value = elem.value().map(|value| TLV::new(tag, value));
196
197 if let Ok(seq) = elem.container() {
198 *self = Self::Seq(seq.tlv_iter());
199 } else {
200 *self = TLVElementTLVIter::Finished;
201 }
202
203 Some(value)
204 }
205 }
206 TLVElementTLVIter::Seq(mut iter) => {
207 if let Some(value) = iter.next() {
208 *self = TLVElementTLVIter::Seq(iter);
209 Some(value)
210 } else {
211 Some(Ok(TLV::end_container()))
212 }
213 }
214 TLVElementTLVIter::Finished => None,
215 }
216 }
217}
218
219impl<'a> FromTLV<'a> for TLVValue<'a> {
220 fn from_tlv(element: &TLVElement<'a>) -> Result<Self, Error> {
221 element.value()
222 }
223}
224
225impl ToTLV for TLVValue<'_> {
226 fn to_tlv<W: TLVWrite>(&self, tag: &TLVTag, mut tw: W) -> Result<(), Error> {
227 tw.tlv(tag, self)
228 }
229
230 fn tlv_iter(&self, tag: TLVTag) -> impl Iterator<Item = Result<TLV<'_>, Error>> {
231 TLV::new(tag, self.clone()).into_tlv_iter()
232 }
233}
234
235#[cfg(test)]
236mod tests {
237 use core::fmt::Debug;
238 use core::mem::MaybeUninit;
239
240 use rs_matter_macros::{FromTLV, ToTLV};
241
242 use crate::tlv::{Octets, TLVElement, TLV};
243 use crate::utils::init::InitMaybeUninit;
244 use crate::utils::storage::WriteBuf;
245
246 use super::{FromTLV, OctetStr, TLVTag, ToTLV};
247
248 fn test_from_tlv<'a, T: FromTLV<'a> + PartialEq + Debug>(data: &'a [u8], expected: T) {
249 let root = TLVElement::new(data);
250 let test = T::from_tlv(&root).unwrap();
251 ::core::assert_eq!(test, expected);
252
253 let test_init = T::init_from_tlv(root);
254
255 let mut test = MaybeUninit::<T>::uninit();
256
257 let test = test.try_init_with(test_init).unwrap();
258
259 ::core::assert_eq!(*test, expected);
260 }
261
262 fn test_to_tlv<T: ToTLV>(t: T, expected: &[u8]) {
263 let mut buf = [0; 20];
264 let mut tw = WriteBuf::new(&mut buf);
265
266 t.to_tlv(&TLVTag::Anonymous, &mut tw).unwrap();
267
268 assert_eq!(tw.as_slice(), expected);
269
270 tw.reset();
271
272 let mut iter = t
273 .tlv_iter(TLVTag::Anonymous)
274 .flat_map(TLV::result_into_bytes_iter);
275 loop {
276 match iter.next() {
277 Some(Ok(byte)) => tw.append(&[byte]).unwrap(),
278 None => break,
279 _ => panic!("Error in iterator"),
280 }
281 }
282
283 ::core::assert_eq!(tw.as_slice(), expected);
284 }
285
286 #[derive(ToTLV, Debug)]
287 struct TestDerive {
288 a: u16,
289 b: u32,
290 }
291
292 #[test]
293 fn test_derive_totlv() {
294 test_to_tlv(
295 TestDerive {
296 a: 0x1010,
297 b: 0x20202020,
298 },
299 &[21, 37, 0, 0x10, 0x10, 38, 1, 0x20, 0x20, 0x20, 0x20, 24],
300 );
301 }
302
303 #[derive(FromTLV, Debug, PartialEq)]
304 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
305 struct TestDeriveSimple {
306 a: u16,
307 b: u32,
308 }
309
310 #[test]
311 fn test_derive_fromtlv() {
312 test_from_tlv(
313 &[21, 37, 0, 10, 0, 38, 1, 20, 0, 0, 0, 24],
314 TestDeriveSimple { a: 10, b: 20 },
315 );
316 }
317
318 #[derive(FromTLV, Debug, PartialEq)]
319 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
320 #[tlvargs(lifetime = "'a")]
321 struct TestDeriveStr<'a> {
322 a: u16,
323 b: OctetStr<'a>,
324 }
325
326 #[test]
327 fn test_derive_fromtlv_str() {
328 test_from_tlv(
329 &[21, 37, 0, 10, 0, 0x30, 0x01, 0x03, 10, 11, 12, 0],
330 TestDeriveStr {
331 a: 10,
332 b: Octets(&[10, 11, 12]),
333 },
334 );
335 }
336
337 #[derive(FromTLV, Debug, PartialEq)]
338 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
339 struct TestDeriveOption {
340 a: u16,
341 b: Option<u16>,
342 c: Option<u16>,
343 }
344
345 #[test]
346 fn test_derive_fromtlv_option() {
347 test_from_tlv(
348 &[21, 37, 0, 10, 0, 37, 2, 11, 0],
349 TestDeriveOption {
350 a: 10,
351 b: None,
352 c: Some(11),
353 },
354 );
355 }
356
357 #[derive(FromTLV, ToTLV, Debug, PartialEq)]
358 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
359 struct TestDeriveFabScoped {
360 a: u16,
361 #[tagval(0xFE)]
362 fab_idx: u16,
363 }
364
365 #[test]
366 fn test_derive_fromtlv_fab_scoped() {
367 test_from_tlv(
368 &[21, 37, 0, 10, 0, 37, 0xFE, 11, 0],
369 TestDeriveFabScoped { a: 10, fab_idx: 11 },
370 );
371 }
372
373 #[test]
374 fn test_derive_totlv_fab_scoped() {
375 test_to_tlv(
376 TestDeriveFabScoped { a: 20, fab_idx: 3 },
377 &[21, 36, 0, 20, 36, 0xFE, 3, 24],
378 );
379 }
380
381 #[derive(ToTLV, FromTLV, PartialEq, Debug)]
382 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
383 enum TestDeriveEnum {
384 ValueA(u32),
385 ValueB(u32),
386 }
387
388 #[test]
389 fn test_derive_from_to_tlv_enum() {
390 test_from_tlv(&[21, 36, 0, 100, 24, 0], TestDeriveEnum::ValueA(100));
392
393 test_to_tlv(TestDeriveEnum::ValueB(10), &[21, 36, 1, 10, 24]);
395 }
396}