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