Skip to main content

rs_matter/tlv/
toiter.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
18use core::iter::{Chain, Once};
19
20use crate::error::{Error, ErrorCode};
21
22use super::{OnceTLVIter, TLVTag, TLVValue, TLVValueType, TLV};
23
24type TLVResult<'a> = Result<TLV<'a>, Error>;
25type ChainedTLVIter<'a, C> = Chain<C, OnceTLVIter<'a>>;
26
27/// A decorator trait for serializing data as TLV in the form of an
28/// `Iterator` of `Result<TLV<'a>, Error>` bytes.
29///
30/// The trait provides additional combinators on top of the standard `Iterator`
31/// trait combinators (e.g. `map`, `filter`, `flat_map`, etc.) that allow for serializing TLV elements.
32///
33/// The trait is already implemented for any `Iterator` that yields items of type `Result<TLV<'a>, Error>`,
34/// so users are not expected to provide implementations of it.
35///
36/// Using an Iterator approach to TLV serialization is useful when the data is not serialized to its
37/// final location (be it in the storage or in an outgoing network packet) - but rather - is serialized
38/// so that it is afterwards consumed as a stream of bytes by another component - say - a hash signature
39/// algorithm that operates on the TLV representation of the data.
40///
41/// This way, the need for an interim buffer for the serialized TLV data might be avoided.
42///
43/// NOTE:
44/// Keep in mind that the resulting iterator might quickly become rather large if the serialized
45/// TLV data contains many small TLV elements, as each TLV element is represented as multiple compositions
46/// of the Rust `Iterator` combinators (e.g. `chain`, `map`, `flat_map`, etc.), and - moreover -
47/// the size of each `TLV` itself is rather large (~ 32 bytes on 32bit archs).
48///
49/// Therefore, the iterator TLV serialization is only useful when the serialized TLV data contains few but
50/// large non-container TLV elements, like octet strings or utf8 strings
51/// (which is typical for e.g. TLV-encoded certificates).
52///
53/// For other cases, allocating a temporary memory buffer and serializing into it with `TLVWrite` might result
54/// in less memory overhead (and better performance when reading the raw serialized TLV data) by the code that
55/// operates on it.
56pub trait TLVIter<'a>: Iterator<Item = TLVResult<'a>> + Sized {
57    fn flatten(value: Result<Self, Error>) -> EitherIter<Self, Once<TLVResult<'a>>> {
58        match value {
59            Ok(value) => EitherIter::First(value),
60            Err(err) => EitherIter::Second(core::iter::once(Err(err))),
61        }
62    }
63
64    /// Serialize a TLV tag and value.
65    fn tlv(self, tag: TLVTag, value: TLVValue<'a>) -> ChainedTLVIter<'a, Self>
66    where
67        Self: 'a,
68    {
69        self.chain(TLV::new(tag, value).into_tlv_iter())
70    }
71
72    /// Serialize the given tag and the provided value as an S8 TLV value.
73    fn i8(self, tag: TLVTag, data: i8) -> ChainedTLVIter<'a, Self>
74    where
75        Self: 'a,
76    {
77        self.chain(TLV::i8(tag, data).into_tlv_iter())
78    }
79
80    /// Serialize the given tag and the provided value as a U8 TLV value.
81    fn u8(self, tag: TLVTag, data: u8) -> ChainedTLVIter<'a, Self>
82    where
83        Self: 'a,
84    {
85        self.chain(TLV::u8(tag, data).into_tlv_iter())
86    }
87
88    /// Serialize the given tag and the provided value as an S16 TLV value,
89    /// or as an S8 TLV value if the provided data can fit in the S8 domain range.
90    fn i16(self, tag: TLVTag, data: i16) -> ChainedTLVIter<'a, Self>
91    where
92        Self: 'a,
93    {
94        self.chain(TLV::i16(tag, data).into_tlv_iter())
95    }
96
97    /// Serialize the given tag and the provided value as a U16 TLV value,
98    /// or as a U8 TLV value if the provided data can fit in the U8 domain range.
99    fn u16(self, tag: TLVTag, data: u16) -> ChainedTLVIter<'a, Self>
100    where
101        Self: 'a,
102    {
103        self.chain(TLV::u16(tag, data).into_tlv_iter())
104    }
105
106    /// Serialize the given tag and the provided value as an S32 TLV value,
107    /// or as an S16 / S8 TLV value if the provided data can fit in a smaller domain range.
108    fn i32(self, tag: TLVTag, data: i32) -> ChainedTLVIter<'a, Self>
109    where
110        Self: 'a,
111    {
112        self.chain(TLV::i32(tag, data).into_tlv_iter())
113    }
114
115    /// Serialize the given tag and the provided value as a U32 TLV value,
116    /// or as a U16 / U8 TLV value if the provided data can fit in a smaller domain range.
117    fn u32(self, tag: TLVTag, data: u32) -> ChainedTLVIter<'a, Self>
118    where
119        Self: 'a,
120    {
121        self.chain(TLV::u32(tag, data).into_tlv_iter())
122    }
123
124    /// Serialize the given tag and the provided value as an S64 TLV value,
125    /// or as an S32 / S16 / S8 TLV value if the provided data can fit in a smaller domain range.
126    fn i64(self, tag: TLVTag, data: i64) -> ChainedTLVIter<'a, Self>
127    where
128        Self: 'a,
129    {
130        self.chain(TLV::i64(tag, data).into_tlv_iter())
131    }
132
133    /// Serialize the given tag and the provided value as a U64 TLV value,
134    /// or as a U32 / U16 / U8 TLV value if the provided data can fit in a smaller domain range.
135    fn u64(self, tag: TLVTag, data: u64) -> ChainedTLVIter<'a, Self>
136    where
137        Self: 'a,
138    {
139        self.chain(TLV::u64(tag, data).into_tlv_iter())
140    }
141
142    /// Serialize the given tag and the provided value as an F32 TLV value.
143    fn f32(self, tag: TLVTag, data: f32) -> ChainedTLVIter<'a, Self>
144    where
145        Self: 'a,
146    {
147        self.chain(TLV::f32(tag, data).into_tlv_iter())
148    }
149
150    /// Serialize the given tag and the provided value as an F64 TLV value.
151    fn f64(self, tag: TLVTag, data: f64) -> ChainedTLVIter<'a, Self>
152    where
153        Self: 'a,
154    {
155        self.chain(TLV::f64(tag, data).into_tlv_iter())
156    }
157
158    /// Serialize the given tag and the provided value as a TLV Octet String.
159    ///
160    /// The exact octet string type (Str8l, Str16l, Str32l, or Str64l) is chosen based on the length of the data,
161    /// whereas the smallest type filling the provided data length is chosen.
162    fn str(self, tag: TLVTag, data: &'a [u8]) -> ChainedTLVIter<'a, Self>
163    where
164        Self: 'a,
165    {
166        self.chain(TLV::str(tag, data).into_tlv_iter())
167    }
168
169    /// Serialize the given tag and the provided value as a TLV UTF-8 String.
170    ///
171    /// The exact UTF-8 string type (Utf8l, Utf16l, Utf32l, or Utf64l) is chosen based on the length of the data,
172    /// whereas the smallest type filling the provided data length is chosen.
173    fn utf8(self, tag: TLVTag, data: &'a str) -> ChainedTLVIter<'a, Self>
174    where
175        Self: 'a,
176    {
177        self.chain(TLV::utf8(tag, data).into_tlv_iter())
178    }
179
180    /// Serialize the given tag and a value indicating the start of a Struct TLV container.
181    ///
182    /// NOTE: The user must call `end_container` after serializing all the Struct fields
183    /// to close the Struct container or else the generated TLV stream will be invalid.
184    fn start_struct(self, tag: TLVTag) -> ChainedTLVIter<'a, Self>
185    where
186        Self: 'a,
187    {
188        self.chain(TLV::structure(tag).into_tlv_iter())
189    }
190
191    /// Serialize the given tag and a value indicating the start of an Array TLV container.
192    ///
193    /// NOTE: The user must call `end_container` after serializing all the Array elements
194    /// to close the Array container or else the generated TLV stream will be invalid.
195    fn start_array(self, tag: TLVTag) -> ChainedTLVIter<'a, Self>
196    where
197        Self: 'a,
198    {
199        self.chain(TLV::array(tag).into_tlv_iter())
200    }
201
202    /// Serialize the given tag and a value indicating the start of a List TLV container.
203    ///
204    /// NOTE: The user must call `end_container` after serializing all the List elements
205    /// to close the List container or else the generated TLV stream will be invalid.
206    fn start_list(self, tag: TLVTag) -> ChainedTLVIter<'a, Self>
207    where
208        Self: 'a,
209    {
210        self.chain(TLV::list(tag).into_tlv_iter())
211    }
212
213    /// Serialize the given tag and a value indicating the start of a TLV container.
214    ///
215    /// NOTE: The user must call `end_container` after serializing all the container fields
216    /// to close the Struct container or else the generated TLV stream will be invalid.
217    fn start_container(self, tag: TLVTag, container_type: TLVValueType) -> ChainedTLVIter<'a, Self>
218    where
219        Self: 'a,
220    {
221        match container_type {
222            TLVValueType::Struct => self.start_struct(tag),
223            TLVValueType::Array => self.start_array(tag),
224            TLVValueType::List => self.start_list(tag),
225            _ => self.chain(core::iter::once(Err(ErrorCode::TLVTypeMismatch.into()))),
226        }
227    }
228
229    /// Serialize a value indicating the end of a Struct, Array, or List TLV container.
230    ///
231    /// NOTE: This method must be called only when the corresponding container has been opened
232    /// using `start_struct`, `start_array`, or `start_list`, or else the generated TLV stream will be invalid.
233    fn end_container(self) -> ChainedTLVIter<'a, Self>
234    where
235        Self: 'a,
236    {
237        self.chain(TLV::end_container().into_tlv_iter())
238    }
239
240    /// Serialize the given tag and a value indicating a Null TLV value.
241    fn null(self, tag: TLVTag) -> ChainedTLVIter<'a, Self>
242    where
243        Self: 'a,
244    {
245        self.chain(TLV::null(tag).into_tlv_iter())
246    }
247
248    /// Serialize the given tag and a value indicating a True or False TLV value.
249    fn bool(self, tag: TLVTag, data: bool) -> ChainedTLVIter<'a, Self>
250    where
251        Self: 'a,
252    {
253        self.chain(TLV::bool(tag, data).into_tlv_iter())
254    }
255}
256
257impl<'a, T> TLVIter<'a> for T where T: Iterator<Item = TLVResult<'a>> {}
258
259/// A decorator enum type wrapping two iterators and implementing
260/// the `Iterator` trait.
261///
262/// Useful when the "to-tlv-iter" implementation needs to return
263/// one of two iterators based on some condition.
264#[derive(Clone)]
265pub enum EitherIter<F, S> {
266    First(F),
267    Second(S),
268}
269
270impl<F, S> Iterator for EitherIter<F, S>
271where
272    F: Iterator,
273    S: Iterator<Item = F::Item>,
274{
275    type Item = <F as Iterator>::Item;
276
277    fn next(&mut self) -> Option<Self::Item> {
278        match self {
279            Self::First(i) => i.next(),
280            Self::Second(i) => i.next(),
281        }
282    }
283}
284
285/// A decorator enum type wrapping three iterators and implementing
286/// the `Iterator` trait.
287///
288/// Useful when the "to-tlv-iter" implementation needs to return
289/// one of three iterators based on some condition.
290#[derive(Clone)]
291pub enum Either3Iter<F, S, T> {
292    First(F),
293    Second(S),
294    Third(T),
295}
296
297impl<F, S, T> Iterator for Either3Iter<F, S, T>
298where
299    F: Iterator,
300    S: Iterator<Item = F::Item>,
301    T: Iterator<Item = F::Item>,
302{
303    type Item = <F as Iterator>::Item;
304
305    fn next(&mut self) -> Option<Self::Item> {
306        match self {
307            Self::First(i) => i.next(),
308            Self::Second(i) => i.next(),
309            Self::Third(i) => i.next(),
310        }
311    }
312}
313
314/// A decorator enum type wrapping four iterators and implementing
315/// the `Iterator` trait.
316///
317/// Useful when the "to-tlv-iter" implementation needs to return
318/// one of four iterators based on some condition.
319#[derive(Clone)]
320pub enum Either4Iter<F, S, T, U> {
321    First(F),
322    Second(S),
323    Third(T),
324    Fourth(U),
325}
326
327impl<F, S, T, U> Iterator for Either4Iter<F, S, T, U>
328where
329    F: Iterator,
330    S: Iterator<Item = F::Item>,
331    T: Iterator<Item = F::Item>,
332    U: Iterator<Item = F::Item>,
333{
334    type Item = <F as Iterator>::Item;
335
336    fn next(&mut self) -> Option<Self::Item> {
337        match self {
338            Self::First(i) => i.next(),
339            Self::Second(i) => i.next(),
340            Self::Third(i) => i.next(),
341            Self::Fourth(i) => i.next(),
342        }
343    }
344}
345
346/// A decorator enum type wrapping five iterators and implementing
347/// the `Iterator` trait.
348///
349/// Useful when the "to-tlv-iter" implementation needs to return
350/// one of five iterators based on some condition.
351#[derive(Clone)]
352pub enum Either5Iter<F, S, T, U, I> {
353    First(F),
354    Second(S),
355    Third(T),
356    Fourth(U),
357    Fifth(I),
358}
359
360impl<F, S, T, U, I> Iterator for Either5Iter<F, S, T, U, I>
361where
362    F: Iterator,
363    S: Iterator<Item = F::Item>,
364    T: Iterator<Item = F::Item>,
365    U: Iterator<Item = F::Item>,
366    I: Iterator<Item = F::Item>,
367{
368    type Item = <F as Iterator>::Item;
369
370    fn next(&mut self) -> Option<Self::Item> {
371        match self {
372            Self::First(i) => i.next(),
373            Self::Second(i) => i.next(),
374            Self::Third(i) => i.next(),
375            Self::Fourth(i) => i.next(),
376            Self::Fifth(i) => i.next(),
377        }
378    }
379}
380
381/// A decorator enum type wrapping six iterators and implementing
382/// the `Iterator` trait.
383///
384/// Useful when the "to-tlv-iter" implementation needs to return
385/// one of six iterators based on some condition.
386#[derive(Clone)]
387pub enum Either6Iter<F, S, T, U, I, X> {
388    First(F),
389    Second(S),
390    Third(T),
391    Fourth(U),
392    Fifth(I),
393    Sixth(X),
394}
395
396impl<F, S, T, U, I, X> Iterator for Either6Iter<F, S, T, U, I, X>
397where
398    F: Iterator,
399    S: Iterator<Item = F::Item>,
400    T: Iterator<Item = F::Item>,
401    U: Iterator<Item = F::Item>,
402    I: Iterator<Item = F::Item>,
403    X: Iterator<Item = F::Item>,
404{
405    type Item = <F as Iterator>::Item;
406
407    fn next(&mut self) -> Option<Self::Item> {
408        match self {
409            Self::First(i) => i.next(),
410            Self::Second(i) => i.next(),
411            Self::Third(i) => i.next(),
412            Self::Fourth(i) => i.next(),
413            Self::Fifth(i) => i.next(),
414            Self::Sixth(i) => i.next(),
415        }
416    }
417}
418
419#[cfg(test)]
420mod tests {
421    use core::{f32, iter::empty};
422
423    use crate::tlv::TLV;
424
425    use super::{TLVIter, TLVResult, TLVTag};
426
427    fn expect<'a, I>(iter: I, expected: &[u8])
428    where
429        I: Iterator<Item = TLVResult<'a>>,
430    {
431        let mut iter = iter.map(|r| r.unwrap()).flat_map(TLV::into_bytes_iter);
432        let mut expected = expected.iter().copied();
433
434        loop {
435            match (iter.next(), expected.next()) {
436                (Some(a), Some(b)) => assert_eq!(a, b),
437                (None, None) => break,
438                (Some(_), None) => panic!("Iterator has more bytes than expected"),
439                (None, Some(_)) => panic!("Iterator has fewer bytes than expected"),
440            }
441        }
442    }
443
444    #[test]
445    fn test_write_success() {
446        expect(
447            empty()
448                .start_struct(TLVTag::Anonymous)
449                .u8(TLVTag::Anonymous, 12)
450                .u8(TLVTag::Context(1), 13)
451                .u16(TLVTag::Anonymous, 0x1212)
452                .u16(TLVTag::Context(2), 0x1313)
453                .start_array(TLVTag::Context(3))
454                .bool(TLVTag::Anonymous, true)
455                .end_container()
456                .end_container(),
457            &[
458                21, 4, 12, 36, 1, 13, 5, 0x12, 0x012, 37, 2, 0x13, 0x13, 54, 3, 9, 24, 24,
459            ],
460        );
461    }
462
463    #[test]
464    fn test_put_str8() {
465        expect(
466            empty()
467                .u8(TLVTag::Context(1), 13)
468                .str(TLVTag::Anonymous, &[10, 11, 12, 13, 14])
469                .u16(TLVTag::Context(2), 0x1313)
470                .str(TLVTag::Context(3), &[20, 21, 22]),
471            &[
472                36, 1, 13, 16, 5, 10, 11, 12, 13, 14, 37, 2, 0x13, 0x13, 48, 3, 3, 20, 21, 22,
473            ],
474        );
475    }
476
477    #[test]
478    fn test_matter_spec_examples() {
479        // Boolean false
480
481        expect(empty().bool(TLVTag::Anonymous, false), &[0x08]);
482
483        // Boolean true
484
485        expect(empty().bool(TLVTag::Anonymous, true), &[0x09]);
486
487        // Signed Integer, 1-octet, value 42
488
489        expect(empty().i8(TLVTag::Anonymous, 42), &[0x00, 0x2a]);
490
491        // Signed Integer, 1-octet, value -17
492
493        expect(empty().i8(TLVTag::Anonymous, -17), &[0x00, 0xef]);
494
495        // Unsigned Integer, 1-octet, value 42U
496
497        expect(empty().u8(TLVTag::Anonymous, 42), &[0x04, 0x2a]);
498
499        // Signed Integer, 2-octet, value 422
500
501        expect(empty().i16(TLVTag::Anonymous, 422), &[0x01, 0xa6, 0x01]);
502
503        // Signed Integer, 4-octet, value -170000
504
505        expect(
506            empty().i64(TLVTag::Anonymous, -170000),
507            &[0x02, 0xf0, 0x67, 0xfd, 0xff],
508        );
509
510        // Signed Integer, 8-octet, value 40000000000
511
512        expect(
513            empty().i64(TLVTag::Anonymous, 40000000000),
514            &[0x03, 0x00, 0x90, 0x2f, 0x50, 0x09, 0x00, 0x00, 0x00],
515        );
516
517        // UTF-8 String, 1-octet length, "Hello!"
518
519        expect(
520            empty().utf8(TLVTag::Anonymous, "Hello!"),
521            &[0x0c, 0x06, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x21],
522        );
523
524        // UTF-8 String, 1-octet length, "Tschüs"
525
526        expect(
527            empty().utf8(TLVTag::Anonymous, "Tschüs"),
528            &[0x0c, 0x07, 0x54, 0x73, 0x63, 0x68, 0xc3, 0xbc, 0x73],
529        );
530
531        // Octet String, 1-octet length, octets 00 01 02 03 04
532
533        expect(
534            empty().str(TLVTag::Anonymous, &[0x00, 0x01, 0x02, 0x03, 0x04]),
535            &[0x10, 0x05, 0x00, 0x01, 0x02, 0x03, 0x04],
536        );
537
538        // Null
539
540        expect(empty().null(TLVTag::Anonymous), &[0x14]);
541
542        // Single precision floating point 0.0
543
544        expect(
545            empty().f32(TLVTag::Anonymous, 0.0),
546            &[0x0a, 0x00, 0x00, 0x00, 0x00],
547        );
548
549        // Single precision floating point (1.0 / 3.0)
550
551        expect(
552            empty().f32(TLVTag::Anonymous, 1.0 / 3.0),
553            &[0x0a, 0xab, 0xaa, 0xaa, 0x3e],
554        );
555
556        // Single precision floating point 17.9
557
558        expect(
559            empty().f32(TLVTag::Anonymous, 17.9),
560            &[0x0a, 0x33, 0x33, 0x8f, 0x41],
561        );
562
563        // Single precision floating point infinity
564
565        expect(
566            empty().f32(TLVTag::Anonymous, f32::INFINITY),
567            &[0x0a, 0x00, 0x00, 0x80, 0x7f],
568        );
569
570        // Single precision floating point negative infinity
571
572        expect(
573            empty().f32(TLVTag::Anonymous, f32::NEG_INFINITY),
574            &[0x0a, 0x00, 0x00, 0x80, 0xff],
575        );
576
577        // Double precision floating point 0.0
578
579        expect(
580            empty().f64(TLVTag::Anonymous, 0.0),
581            &[0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
582        );
583
584        // Double precision floating point (1.0 / 3.0)
585
586        expect(
587            empty().f64(TLVTag::Anonymous, 1.0 / 3.0),
588            &[0x0b, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x3f],
589        );
590
591        // Double precision floating point 17.9
592
593        expect(
594            empty().f64(TLVTag::Anonymous, 17.9),
595            &[0x0b, 0x66, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x31, 0x40],
596        );
597
598        // Double precision floating point infinity (∞)
599
600        expect(
601            empty().f64(TLVTag::Anonymous, f64::INFINITY),
602            &[0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f],
603        );
604
605        // Double precision floating point negative infinity
606
607        expect(
608            empty().f64(TLVTag::Anonymous, f64::NEG_INFINITY),
609            &[0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff],
610        );
611
612        // Empty Structure, {}
613
614        expect(
615            empty().start_struct(TLVTag::Anonymous).end_container(),
616            &[0x15, 0x18],
617        );
618
619        // Empty Array, []
620
621        expect(
622            empty().start_array(TLVTag::Anonymous).end_container(),
623            &[0x16, 0x18],
624        );
625
626        // Empty List, []
627
628        expect(
629            empty().start_list(TLVTag::Anonymous).end_container(),
630            &[0x17, 0x18],
631        );
632
633        // Structure, two context specific tags, Signed Integer, 1 octet values, {0 = 42, 1 = -17}
634
635        expect(
636            empty()
637                .start_struct(TLVTag::Anonymous)
638                .i8(TLVTag::Context(0), 42)
639                .i32(TLVTag::Context(1), -17)
640                .end_container(),
641            &[0x15, 0x20, 0x00, 0x2a, 0x20, 0x01, 0xef, 0x18],
642        );
643
644        // Array, Signed Integer, 1-octet values, [0, 1, 2, 3, 4]
645
646        expect(
647            empty()
648                .start_array(TLVTag::Anonymous)
649                .i8(TLVTag::Anonymous, 0)
650                .i8(TLVTag::Anonymous, 1)
651                .i8(TLVTag::Anonymous, 2)
652                .i8(TLVTag::Anonymous, 3)
653                .i8(TLVTag::Anonymous, 4)
654                .end_container(),
655            &[
656                0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x18,
657            ],
658        );
659
660        // List, mix of anonymous and context tags, Signed Integer, 1 octet values, [[1, 0 = 42, 2, 3, 0 = -17]]
661
662        expect(
663            empty()
664                .start_list(TLVTag::Anonymous)
665                .i64(TLVTag::Anonymous, 1)
666                .i16(TLVTag::Context(0), 42)
667                .i8(TLVTag::Anonymous, 2)
668                .i8(TLVTag::Anonymous, 3)
669                .i32(TLVTag::Context(0), -17)
670                .end_container(),
671            &[
672                0x17, 0x00, 0x01, 0x20, 0x00, 0x2a, 0x00, 0x02, 0x00, 0x03, 0x20, 0x00, 0xef, 0x18,
673            ],
674        );
675
676        // Array, mix of element types, [42, -170000, {}, 17.9, "Hello!"]
677
678        expect(
679            empty()
680                .start_array(TLVTag::Anonymous)
681                .i64(TLVTag::Anonymous, 42)
682                .i64(TLVTag::Anonymous, -170000)
683                .start_struct(TLVTag::Anonymous)
684                .end_container()
685                .f32(TLVTag::Anonymous, 17.9)
686                .utf8(TLVTag::Anonymous, "Hello!")
687                .end_container(),
688            &[
689                0x16, 0x00, 0x2a, 0x02, 0xf0, 0x67, 0xfd, 0xff, 0x15, 0x18, 0x0a, 0x33, 0x33, 0x8f,
690                0x41, 0x0c, 0x06, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x21, 0x18,
691            ],
692        );
693
694        // Anonymous tag, Unsigned Integer, 1-octet value, 42U
695
696        expect(empty().u64(TLVTag::Anonymous, 42), &[0x04, 0x2a]);
697
698        // Context tag 1, Unsigned Integer, 1-octet value, 1 = 42U
699
700        expect(empty().u16(TLVTag::Context(1), 42), &[0x24, 0x01, 0x2a]);
701
702        // Common profile tag 1, Unsigned Integer, 1-octet value, Matter::1 = 42U
703
704        expect(
705            empty().u16(TLVTag::CommonPrf16(1), 42),
706            &[0x44, 0x01, 0x00, 0x2a],
707        );
708
709        // Common profile tag 100000, Unsigned Integer, 1-octet value, Matter::100000 = 42U
710
711        expect(
712            empty().u16(TLVTag::CommonPrf32(100000), 42),
713            &[0x64, 0xa0, 0x86, 0x01, 0x00, 0x2a],
714        );
715
716        // Fully qualified tag, Vendor ID 0xFFF1/65521, pro­file number 0xDEED/57069,
717        // 2-octet tag 1, Unsigned Integer, 1-octet value 42, 65521::57069:1 = 42U
718
719        expect(
720            empty().u16(
721                TLVTag::FullQual48 {
722                    vendor_id: 65521,
723                    profile: 57069,
724                    tag: 1,
725                },
726                42,
727            ),
728            &[0xc4, 0xf1, 0xff, 0xed, 0xde, 0x01, 0x00, 0x2a],
729        );
730
731        // Fully qualified tag, Vendor ID 0xFFF1/65521, pro­file number 0xDEED/57069,
732        // 4-octet tag 0xAA55FEED/2857762541, Unsigned Integer, 1-octet value 42, 65521::57069:2857762541 = 42U
733
734        expect(
735            empty().u16(
736                TLVTag::FullQual64 {
737                    vendor_id: 65521,
738                    profile: 57069,
739                    tag: 2857762541,
740                },
741                42,
742            ),
743            &[0xe4, 0xf1, 0xff, 0xed, 0xde, 0xed, 0xfe, 0x55, 0xaa, 0x2a],
744        );
745
746        // Structure with the fully qualified tag, Vendor ID 0xFFF1/65521, profile number 0xDEED/57069,
747        // 2-octet tag 1. The structure contains a single ele­ment labeled using a fully qualified tag under
748        // the same profile, with 2-octet tag 0xAA55/43605. 65521::57069:1 = {65521::57069:43605 = 42U}
749
750        expect(
751            empty()
752                .start_struct(TLVTag::FullQual48 {
753                    vendor_id: 65521,
754                    profile: 57069,
755                    tag: 1,
756                })
757                .u64(
758                    TLVTag::FullQual48 {
759                        vendor_id: 65521,
760                        profile: 57069,
761                        tag: 43605,
762                    },
763                    42,
764                )
765                .end_container(),
766            &[
767                0xd5, 0xf1, 0xff, 0xed, 0xde, 0x01, 0x00, 0xc4, 0xf1, 0xff, 0xed, 0xde, 0x55, 0xaa,
768                0x2a, 0x18,
769            ],
770        );
771    }
772}