Skip to main content

rs_matter/
tlv.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
18use core::borrow::Borrow;
19use core::fmt;
20use core::iter::Once;
21use core::marker::PhantomData;
22
23use num::FromPrimitive;
24use num_traits::ToBytes;
25
26use crate::error::{Error, ErrorCode};
27
28pub use rs_matter_macros::{FromTLV, ToTLV};
29
30pub use read::*;
31pub use toiter::*;
32pub use traits::*;
33pub use write::*;
34
35mod read;
36mod toiter;
37mod traits;
38mod write;
39
40/// Represents the TLV tag type encoded in the control byte of each TLV element.
41#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, num_derive::FromPrimitive)]
42#[cfg_attr(feature = "defmt", derive(defmt::Format))]
43#[repr(u8)]
44pub enum TLVTagType {
45    Anonymous = 0,
46    Context = 1,
47    CommonPrf16 = 2,
48    CommonPrf32 = 3,
49    ImplPrf16 = 4,
50    ImplPrf32 = 5,
51    FullQual48 = 6,
52    FullQual64 = 7,
53}
54
55impl TLVTagType {
56    /// Return the size of the tag data following the control byte
57    /// in the TLV element representation.
58    pub const fn size(&self) -> usize {
59        match self {
60            Self::Anonymous => 0,
61            Self::Context => 1,
62            Self::CommonPrf16 => 2,
63            Self::CommonPrf32 => 4,
64            Self::ImplPrf16 => 2,
65            Self::ImplPrf32 => 4,
66            Self::FullQual48 => 6,
67            Self::FullQual64 => 8,
68        }
69    }
70}
71
72impl fmt::Display for TLVTagType {
73    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74        match self {
75            Self::Anonymous => write!(f, "Anonymous"),
76            Self::Context => write!(f, "Context"),
77            Self::CommonPrf16 => write!(f, "CommonPrf16"),
78            Self::CommonPrf32 => write!(f, "CommonPrf32"),
79            Self::ImplPrf16 => write!(f, "ImplPrf16"),
80            Self::ImplPrf32 => write!(f, "ImplPrf32"),
81            Self::FullQual48 => write!(f, "FullQual48"),
82            Self::FullQual64 => write!(f, "FullQual64"),
83        }
84    }
85}
86
87/// Represents the TLV value type encoded in the control byte of each TLV element.
88#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, num_derive::FromPrimitive)]
89#[cfg_attr(feature = "defmt", derive(defmt::Format))]
90#[repr(u8)]
91pub enum TLVValueType {
92    S8 = 0,
93    S16 = 1,
94    S32 = 2,
95    S64 = 3,
96    U8 = 4,
97    U16 = 5,
98    U32 = 6,
99    U64 = 7,
100    False = 8,
101    True = 9,
102    F32 = 10,
103    F64 = 11,
104    Utf8l = 12,
105    Utf16l = 13,
106    Utf32l = 14,
107    Utf64l = 15,
108    Str8l = 16,
109    Str16l = 17,
110    Str32l = 18,
111    Str64l = 19,
112    Null = 20,
113    Struct = 21,
114    Array = 22,
115    List = 23,
116    EndCnt = 24,
117}
118
119impl TLVValueType {
120    /// Return the size of the value corresponding to this value type.
121    ///
122    /// If the value type has a variable size (i.e. octet and Utf8 strings), this function returns `None`.
123    pub const fn fixed_size(&self) -> Option<usize> {
124        match self {
125            Self::S8 => Some(1),
126            Self::S16 => Some(2),
127            Self::S32 => Some(4),
128            Self::S64 => Some(8),
129            Self::U8 => Some(1),
130            Self::U16 => Some(2),
131            Self::U32 => Some(4),
132            Self::U64 => Some(8),
133            Self::F32 => Some(4),
134            Self::F64 => Some(8),
135            Self::Utf8l
136            | Self::Utf16l
137            | Self::Utf32l
138            | Self::Utf64l
139            | Self::Str8l
140            | Self::Str16l
141            | Self::Str32l
142            | Self::Str64l => None,
143            _ => Some(0),
144        }
145    }
146
147    /// Return the size of the length field for variable size value types.
148    ///
149    /// if the value type has a fixed size, this function returns 0.
150    /// Variable size types are only octet strings and utf8 strings.
151    pub const fn variable_size_len(&self) -> usize {
152        match self {
153            Self::Utf8l | Self::Str8l => 1,
154            Self::Utf16l | Self::Str16l => 2,
155            Self::Utf32l | Self::Str32l => 4,
156            Self::Utf64l | Self::Str64l => 8,
157            _ => 0,
158        }
159    }
160
161    /// Convenience method to check if the value type is a container type
162    /// (container start or end).
163    pub const fn is_container(&self) -> bool {
164        self.is_container_start() || self.is_container_end()
165    }
166
167    /// Convenience method to check if the value type is a container start type.
168    pub const fn is_container_start(&self) -> bool {
169        matches!(self, Self::Struct | Self::Array | Self::List)
170    }
171
172    /// Convenience method to check if the value type is a container end type.
173    pub const fn is_container_end(&self) -> bool {
174        matches!(self, Self::EndCnt)
175    }
176
177    /// Convenience method to check if the value type is an Octet String type.
178    pub const fn is_str(&self) -> bool {
179        matches!(
180            self,
181            Self::Str8l | Self::Str16l | Self::Str32l | Self::Str64l
182        )
183    }
184
185    /// Convenience method to check if the value type is a UTF-8 String type.
186    pub const fn is_utf8(&self) -> bool {
187        matches!(
188            self,
189            Self::Utf8l | Self::Utf16l | Self::Utf32l | Self::Utf64l
190        )
191    }
192
193    pub fn container_value<'a>(&self) -> Result<TLVValue<'a>, Error> {
194        Ok(match self {
195            Self::Struct => TLVValue::Struct,
196            Self::Array => TLVValue::Array,
197            Self::List => TLVValue::List,
198            Self::EndCnt => TLVValue::EndCnt,
199            _ => Err(ErrorCode::TLVTypeMismatch)?,
200        })
201    }
202}
203
204impl fmt::Display for TLVValueType {
205    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206        match self {
207            Self::S8 => write!(f, "S8"),
208            Self::S16 => write!(f, "S16"),
209            Self::S32 => write!(f, "S32"),
210            Self::S64 => write!(f, "S64"),
211            Self::U8 => write!(f, "U8"),
212            Self::U16 => write!(f, "U16"),
213            Self::U32 => write!(f, "U32"),
214            Self::U64 => write!(f, "U64"),
215            Self::False => write!(f, "False"),
216            Self::True => write!(f, "True"),
217            Self::F32 => write!(f, "F32"),
218            Self::F64 => write!(f, "F64"),
219            Self::Utf8l => write!(f, "Utf8l"),
220            Self::Utf16l => write!(f, "Utf16l"),
221            Self::Utf32l => write!(f, "Utf32l"),
222            Self::Utf64l => write!(f, "Utf64l"),
223            Self::Str8l => write!(f, "Str8l"),
224            Self::Str16l => write!(f, "Str16l"),
225            Self::Str32l => write!(f, "Str32l"),
226            Self::Str64l => write!(f, "Str64l"),
227            Self::Null => write!(f, "Null"),
228            Self::Struct => write!(f, "Struct"),
229            Self::Array => write!(f, "Array"),
230            Self::List => write!(f, "List"),
231            Self::EndCnt => write!(f, "EndCnt"),
232        }
233    }
234}
235
236/// Represents the control byte of a TLV element (i.e. the tag type and the value type).
237#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
238#[cfg_attr(feature = "defmt", derive(defmt::Format))]
239pub struct TLVControl {
240    pub tag_type: TLVTagType,
241    pub value_type: TLVValueType,
242}
243
244impl TLVControl {
245    const TAG_SHIFT_BITS: u8 = 5;
246    const TAG_MASK: u8 = 0xe0;
247    const TYPE_MASK: u8 = 0x1f;
248
249    /// Create a new TLV control byte by parsing the provided tag type and value type.
250    #[inline(always)]
251    pub const fn new(tag_type: TLVTagType, value_type: TLVValueType) -> Self {
252        Self {
253            tag_type,
254            value_type,
255        }
256    }
257
258    /// Create a new TLV control byte by parsing the provided control byte
259    /// into a tag type and a value type.
260    ///
261    /// The function will return an error if the provided control byte is invalid.
262    #[inline(always)]
263    pub fn parse(control: u8) -> Result<Self, Error> {
264        let tag_type = FromPrimitive::from_u8((control & Self::TAG_MASK) >> Self::TAG_SHIFT_BITS)
265            .ok_or(ErrorCode::TLVTypeMismatch)?;
266        let value_type =
267            FromPrimitive::from_u8(control & Self::TYPE_MASK).ok_or(ErrorCode::TLVTypeMismatch)?;
268
269        Ok(Self::new(tag_type, value_type))
270    }
271
272    /// Return the raw control byte.
273    #[inline(always)]
274    pub const fn as_raw(&self) -> u8 {
275        ((self.tag_type as u8) << Self::TAG_SHIFT_BITS) | (self.value_type as u8)
276    }
277
278    /// Return `true` if the control byte represents a container start (struct, array or list).
279    #[inline(always)]
280    pub fn is_container_start(&self) -> bool {
281        self.value_type.is_container_start()
282    }
283
284    /// Return `true` if the control byte represents a container end.
285    #[inline(always)]
286    pub fn is_container_end(&self) -> bool {
287        matches!(self.tag_type, TLVTagType::Anonymous) && self.value_type.is_container_end()
288    }
289
290    /// Return an error if the control byte does not represent a container start.
291    #[inline(always)]
292    pub fn confirm_container_end(&self) -> Result<(), Error> {
293        if !self.is_container_end() {
294            return Err(ErrorCode::InvalidData.into());
295        }
296
297        Ok(())
298    }
299}
300
301impl fmt::Display for TLVControl {
302    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
303        write!(f, "Control({} {})", self.tag_type, self.value_type)
304    }
305}
306
307/// A high-level representation of a TLV tag + value.
308///
309/// Amongsat other things, it is a convenient way to emit TLV byte sequences.
310///
311/// A `TLV` can be constructed programmatically, or returned from a `TLVElement`.
312///
313/// Unlike a `TLVElement` however, a `TLV` does not represent a complete container,
314/// but rather, its beginning or end.
315///
316/// I.e.
317/// ```ignore
318/// use rs_matter::tlv::{TLV, TLVTag, TLVValue};
319///
320/// let tlvs = &[
321///     TLV::new(TLVTag::Anonymous, TLVValue::Struct),
322///     TLV::new(TLVTag::Context(0), TLVValue::Utf8l("Hello, World!")),
323///     TLV::new(TLVTag::Anonymous, TLVValue::EndCnt),
324/// ];
325///
326/// let bytes_iter = tlvs.iter().flat_map(|tlv| tlv.bytes_iter());
327/// for byte in bytes_iter {
328///    println!("{:02X}", byte);
329/// }
330/// ```
331#[derive(Debug, Clone, PartialEq)]
332#[cfg_attr(feature = "defmt", derive(defmt::Format))]
333pub struct TLV<'a> {
334    pub tag: TLVTag,
335    pub value: TLVValue<'a>,
336}
337
338impl<'a> TLV<'a> {
339    /// Create a new TLV instance with the provided tag and value.
340    pub const fn new(tag: TLVTag, value: TLVValue<'a>) -> Self {
341        Self { tag, value }
342    }
343
344    /// Create a TLV with the given tag and the provided value as an S8 TLV.
345    pub const fn i8(tag: TLVTag, value: i8) -> Self {
346        Self::new(tag, TLVValue::i8(value))
347    }
348
349    /// Create a TLV with the given tag and the provided value as an S8 or S16 TLV,
350    /// depending on whether the value is small enough to fit in an S8 TLV.
351    pub const fn i16(tag: TLVTag, value: i16) -> Self {
352        Self::new(tag, TLVValue::i16(value))
353    }
354
355    /// Create a TLV with the given tag and the provided value as an S8, S16, or S32 TLV,
356    /// depending on whether the value is small enough to fit in an S8 or S16 TLV.
357    pub const fn i32(tag: TLVTag, value: i32) -> Self {
358        Self::new(tag, TLVValue::i32(value))
359    }
360
361    /// Create a TLV with the given tag and the provided value as an S8, S16, S32, or S64 TLV,
362    /// depending on whether the value is small enough to fit in an S8, S16, or S32 TLV.
363    pub const fn i64(tag: TLVTag, value: i64) -> Self {
364        Self::new(tag, TLVValue::i64(value))
365    }
366
367    /// Create a TLV with the given tag and the provided value as a U8 TLV.
368    pub const fn u8(tag: TLVTag, value: u8) -> Self {
369        Self::new(tag, TLVValue::u8(value))
370    }
371
372    /// Create a TLV with the given tag and the provided value as a U8 or U16 TLV,
373    /// depending on whether the value is small enough to fit in a U8 TLV.
374    pub const fn u16(tag: TLVTag, value: u16) -> Self {
375        Self::new(tag, TLVValue::u16(value))
376    }
377
378    /// Create a TLV with the given tag and the provided value as a U8, U16, or U32 TLV,
379    /// depending on whether the value is small enough to fit in a U8 or U16 TLV.
380    pub const fn u32(tag: TLVTag, value: u32) -> Self {
381        Self::new(tag, TLVValue::u32(value))
382    }
383
384    /// Create a TLV with the given tag and the provided value as a U8, U16, U32, or U64 TLV,
385    /// depending on whether the value is small enough to fit in a U8, U16, or U32 TLV.
386    pub const fn u64(tag: TLVTag, value: u64) -> Self {
387        Self::new(tag, TLVValue::u64(value))
388    }
389
390    /// Create a TLV with the given tag and the provided value as a F32 TLV.
391    pub const fn f32(tag: TLVTag, value: f32) -> Self {
392        Self::new(tag, TLVValue::f32(value))
393    }
394
395    /// Create a TLV with the given tag and the provided value as a F64 TLV.
396    pub const fn f64(tag: TLVTag, value: f64) -> Self {
397        Self::new(tag, TLVValue::f64(value))
398    }
399
400    /// Create a TLV with the given tag and the provided value as a UTF-8 TLV.
401    /// The length of the string is encoded as 1, 2, 4 or 8 octets,
402    /// depending on the length of the string.
403    pub const fn utf8(tag: TLVTag, value: &'a str) -> Self {
404        Self::new(tag, TLVValue::utf8(value))
405    }
406
407    /// Create a TLV with the given tag and the provided value as an octet string TLV.
408    /// The length of the string is encoded as 1, 2, 4 or 8 octets,
409    /// depending on the length of the string.
410    pub const fn str(tag: TLVTag, value: &'a [u8]) -> Self {
411        Self::new(tag, TLVValue::str(value))
412    }
413
414    /// Create a TLV with the given tag which will have a value of type Struct (start).
415    pub const fn r#struct(tag: TLVTag) -> Self {
416        Self::new(tag, TLVValue::r#struct())
417    }
418
419    /// Create a TLV with the given tag which will have a value of type Struct (start).
420    pub const fn structure(tag: TLVTag) -> Self {
421        Self::new(tag, TLVValue::structure())
422    }
423
424    /// Create a TLV with the given tag which will have a value of type Array (start).
425    pub const fn array(tag: TLVTag) -> Self {
426        Self::new(tag, TLVValue::array())
427    }
428
429    /// Create a TLV with the given tag which will have a value of type List (start).
430    pub const fn list(tag: TLVTag) -> Self {
431        Self::new(tag, TLVValue::list())
432    }
433
434    /// Create a TLV with the given tag which will have a value of type EndCnt (container end).
435    pub const fn end_container() -> Self {
436        Self::new(TLVTag::Anonymous, TLVValue::end_container())
437    }
438
439    /// Create a TLV with the given tag which will have a value of type Null.
440    pub const fn null(tag: TLVTag) -> Self {
441        Self::new(tag, TLVValue::null())
442    }
443
444    /// Create a TLV with the given tag which will have a value of type True.
445    pub const fn bool(tag: TLVTag, value: bool) -> Self {
446        Self::new(tag, TLVValue::bool(value))
447    }
448
449    /// Converts the TLV into an iterator with a single item - the TLV.
450    pub fn into_tlv_iter(self) -> OnceTLVIter<'a> {
451        core::iter::once(Ok(self))
452    }
453
454    /// Returns an iterator over the bytes of the TLV.
455    pub fn bytes_iter(&self) -> TLVBytesIter<'a, &TLVTag, &TLVValue<'a>> {
456        TLVBytesIter {
457            control: core::iter::once(
458                TLVControl::new(self.tag.tag_type(), self.value.value_type()).as_raw(),
459            ),
460            tag: self.tag.iter(),
461            value: self.value.iter(),
462        }
463    }
464
465    /// Converts the TLV into an iterator over its bytes.
466    pub fn into_bytes_iter(self) -> TLVBytesIter<'a, TLVTag, TLVValue<'a>> {
467        TLVBytesIter {
468            control: core::iter::once(
469                TLVControl::new(self.tag.tag_type(), self.value.value_type()).as_raw(),
470            ),
471            tag: self.tag.into_iterator(),
472            value: self.value.into_iterator(),
473        }
474    }
475
476    /// Converts the provided result into an iterator over the bytes of the TLV.
477    pub fn result_into_bytes_iter(
478        result: Result<Self, Error>,
479    ) -> TLVResultBytesIter<'a, TLVTag, TLVValue<'a>> {
480        TLVResultBytesIter::new(result)
481    }
482}
483
484impl<'a> IntoIterator for TLV<'a> {
485    type Item = u8;
486    type IntoIter = TLVBytesIter<'a, TLVTag, TLVValue<'a>>;
487
488    fn into_iter(self) -> Self::IntoIter {
489        TLV::into_bytes_iter(self)
490    }
491}
492
493impl<'s, 'a> IntoIterator for &'s TLV<'a> {
494    type Item = u8;
495    type IntoIter = TLVBytesIter<'a, &'s TLVTag, &'s TLVValue<'a>>;
496
497    fn into_iter(self) -> Self::IntoIter {
498        TLV::bytes_iter(self)
499    }
500}
501
502/// An iterator over the bytes of a TLV that might return an error.
503pub enum TLVResultBytesIter<'a, T, V>
504where
505    T: Borrow<TLVTag>,
506    V: Borrow<TLVValue<'a>>,
507{
508    Ok(TLVBytesIter<'a, T, V>),
509    Err(core::iter::Once<Result<u8, Error>>),
510}
511
512impl<'a> TLVResultBytesIter<'a, TLVTag, TLVValue<'a>> {
513    pub fn new(result: Result<TLV<'a>, Error>) -> Self {
514        match result {
515            Ok(tlv) => Self::Ok(tlv.into_bytes_iter()),
516            Err(err) => Self::Err(core::iter::once(Err(err))),
517        }
518    }
519}
520
521impl<'a, T, V> Iterator for TLVResultBytesIter<'a, T, V>
522where
523    T: Borrow<TLVTag>,
524    V: Borrow<TLVValue<'a>>,
525{
526    type Item = Result<u8, Error>;
527
528    fn next(&mut self) -> Option<Self::Item> {
529        match self {
530            Self::Ok(iter) => iter.next().map(Ok),
531            Self::Err(iter) => iter.next(),
532        }
533    }
534}
535
536/// An iterator over the bytes of a TLV.
537pub struct TLVBytesIter<'a, T, V>
538where
539    T: Borrow<TLVTag>,
540    V: Borrow<TLVValue<'a>>,
541{
542    control: Once<u8>,
543    tag: TLVTagIter<T>,
544    value: TLVValueIter<'a, V>,
545}
546
547impl<'a, T, V> Iterator for TLVBytesIter<'a, T, V>
548where
549    T: Borrow<TLVTag>,
550    V: Borrow<TLVValue<'a>>,
551{
552    type Item = u8;
553
554    fn next(&mut self) -> Option<Self::Item> {
555        self.control
556            .next()
557            .or_else(|| self.tag.next())
558            .or_else(|| self.value.next())
559    }
560}
561
562/// The iterator type for a TLV that returns the TLV itself.
563pub type OnceTLVIter<'s> = core::iter::Once<Result<TLV<'s>, Error>>;
564
565/// For backwards compatibility
566pub type TagType = TLVTag;
567
568/// A high-level representation of a TLV tag (tag type and tag value).
569///
570/// A `TLVTag` can be constructed programmatically, or returned from a `TLVElement`.
571#[derive(Clone, Debug, PartialEq, Eq, Hash)]
572#[cfg_attr(feature = "defmt", derive(defmt::Format))]
573pub enum TLVTag {
574    Anonymous,
575    Context(u8),
576    CommonPrf16(u16),
577    CommonPrf32(u32),
578    ImplPrf16(u16),
579    ImplPrf32(u32),
580    FullQual48 {
581        vendor_id: u16,
582        profile: u16,
583        tag: u16,
584    },
585    FullQual64 {
586        vendor_id: u16,
587        profile: u16,
588        tag: u32,
589    },
590}
591
592impl TLVTag {
593    /// Return the tag type of the TLV tag.
594    pub const fn tag_type(&self) -> TLVTagType {
595        match self {
596            Self::Anonymous => TLVTagType::Anonymous,
597            Self::Context(_) => TLVTagType::Context,
598            Self::CommonPrf16(_) => TLVTagType::CommonPrf16,
599            Self::CommonPrf32(_) => TLVTagType::CommonPrf32,
600            Self::ImplPrf16(_) => TLVTagType::ImplPrf16,
601            Self::ImplPrf32(_) => TLVTagType::ImplPrf32,
602            Self::FullQual48 { .. } => TLVTagType::FullQual48,
603            Self::FullQual64 { .. } => TLVTagType::FullQual64,
604        }
605    }
606
607    /// Return an iterator over the bytes of the TLV tag.
608    pub fn iter(&self) -> TLVTagIter<&Self> {
609        TLVTagIter {
610            value: self,
611            index: 0,
612        }
613    }
614
615    /// Converts itself into an iterator over the bytes of the TLV tag.
616    pub fn into_iterator(self) -> TLVTagIter<Self> {
617        TLVTagIter {
618            value: self,
619            index: 0,
620        }
621    }
622
623    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
624        match self {
625            TLVTag::Anonymous => Ok(()),
626            TLVTag::Context(tag) => write!(f, "{tag}"),
627            TLVTag::CommonPrf16(tag) => write!(f, "CommonPrf16({tag})"),
628            TLVTag::CommonPrf32(tag) => write!(f, "CommonPrf32({tag})"),
629            TLVTag::ImplPrf16(tag) => write!(f, "ImplPrf16({tag})"),
630            TLVTag::ImplPrf32(tag) => write!(f, "ImplPrf32({tag})"),
631            TLVTag::FullQual48 {
632                vendor_id,
633                profile,
634                tag,
635            } => write!(f, "FullQual48(VID:{vendor_id} PRF:{profile} {tag})"),
636            TLVTag::FullQual64 {
637                vendor_id,
638                profile,
639                tag,
640            } => write!(f, "FullQual64(VID:{vendor_id} PRF:{profile} {tag})"),
641        }
642    }
643}
644
645impl IntoIterator for TLVTag {
646    type Item = u8;
647    type IntoIter = TLVTagIter<Self>;
648
649    fn into_iter(self) -> Self::IntoIter {
650        TLVTag::into_iterator(self)
651    }
652}
653
654impl IntoIterator for &TLVTag {
655    type Item = u8;
656    type IntoIter = TLVTagIter<Self>;
657
658    fn into_iter(self) -> Self::IntoIter {
659        TLVTag::iter(self)
660    }
661}
662
663/// An iterator over the bytes of a TLV tag.
664pub struct TLVTagIter<T>
665where
666    T: Borrow<TLVTag>,
667{
668    value: T,
669    index: usize,
670}
671
672impl<T> TLVTagIter<T>
673where
674    T: Borrow<TLVTag>,
675{
676    fn next_byte(&mut self, bytes: &[u8]) -> Option<u8> {
677        self.next_byte_offset(0, bytes)
678    }
679
680    fn next_byte_offset(&mut self, offset: usize, bytes: &[u8]) -> Option<u8> {
681        if self.index - offset < bytes.len() {
682            let byte = bytes[self.index - offset];
683
684            self.index += 1;
685
686            Some(byte)
687        } else {
688            None
689        }
690    }
691}
692
693impl<T> Iterator for TLVTagIter<T>
694where
695    T: Borrow<TLVTag>,
696{
697    type Item = u8;
698
699    fn next(&mut self) -> Option<Self::Item> {
700        match self.value.borrow() {
701            TLVTag::Anonymous => None,
702            TLVTag::Context(tag) => self.next_byte(&tag.to_le_bytes()),
703            TLVTag::CommonPrf16(tag) => self.next_byte(&tag.to_le_bytes()),
704            TLVTag::CommonPrf32(tag) => self.next_byte(&tag.to_le_bytes()),
705            TLVTag::ImplPrf16(tag) => self.next_byte(&tag.to_le_bytes()),
706            TLVTag::ImplPrf32(tag) => self.next_byte(&tag.to_le_bytes()),
707            TLVTag::FullQual48 {
708                vendor_id,
709                profile,
710                tag,
711            } => {
712                if self.index < 2 {
713                    self.next_byte(&vendor_id.to_le_bytes())
714                } else if self.index < 4 {
715                    self.next_byte_offset(2, &profile.to_le_bytes())
716                } else {
717                    self.next_byte_offset(4, &tag.to_le_bytes())
718                }
719            }
720            TLVTag::FullQual64 {
721                vendor_id,
722                profile,
723                tag,
724            } => {
725                if self.index < 2 {
726                    self.next_byte(&vendor_id.to_le_bytes())
727                } else if self.index < 4 {
728                    self.next_byte_offset(2, &profile.to_le_bytes())
729                } else {
730                    self.next_byte_offset(4, &tag.to_le_bytes())
731                }
732            }
733        }
734    }
735}
736
737impl fmt::Display for TLVTag {
738    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
739        match self {
740            TLVTag::Anonymous => write!(f, "Anonymous"),
741            TLVTag::Context(tag) => write!(f, "Context({})", tag),
742            _ => self.fmt(f),
743        }
744    }
745}
746
747/// For backwards compatibility
748pub type ElementType<'a> = TLVValue<'a>;
749
750/// A high-level representation of a TLV value.
751///
752/// Combined with `TLVTag` into a `TLV` struct it is a convenient way
753/// to emit TLV byte sequences.
754///
755/// A `TLVValue` can be constructed programmatically, or returned from a `TLVElement`.
756///
757/// Unlike a `TLVElement` however, a `TLVValue` does not represent a complete container,
758/// but rather, its beginning or end.
759#[derive(Debug, Clone, PartialEq)]
760#[cfg_attr(feature = "defmt", derive(defmt::Format))]
761pub enum TLVValue<'a> {
762    S8(i8),
763    S16(i16),
764    S32(i32),
765    S64(i64),
766    U8(u8),
767    U16(u16),
768    U32(u32),
769    U64(u64),
770    False,
771    True,
772    F32(f32),
773    F64(f64),
774    Utf8l(&'a str),
775    Utf16l(&'a str),
776    Utf32l(&'a str),
777    Utf64l(&'a str),
778    Str8l(&'a [u8]),
779    Str16l(&'a [u8]),
780    Str32l(&'a [u8]),
781    Str64l(&'a [u8]),
782    Null,
783    Struct,
784    Array,
785    List,
786    EndCnt,
787}
788
789impl<'a> TLVValue<'a> {
790    /// Return the value type of the TLV value.
791    pub const fn value_type(&self) -> TLVValueType {
792        match self {
793            Self::S8(_) => TLVValueType::S8,
794            Self::S16(_) => TLVValueType::S16,
795            Self::S32(_) => TLVValueType::S32,
796            Self::S64(_) => TLVValueType::S64,
797            Self::U8(_) => TLVValueType::U8,
798            Self::U16(_) => TLVValueType::U16,
799            Self::U32(_) => TLVValueType::U32,
800            Self::U64(_) => TLVValueType::U64,
801            Self::False => TLVValueType::False,
802            Self::True => TLVValueType::True,
803            Self::F32(_) => TLVValueType::F32,
804            Self::F64(_) => TLVValueType::F64,
805            Self::Utf8l(_) => TLVValueType::Utf8l,
806            Self::Utf16l(_) => TLVValueType::Utf16l,
807            Self::Utf32l(_) => TLVValueType::Utf32l,
808            Self::Utf64l(_) => TLVValueType::Utf64l,
809            Self::Str8l(_) => TLVValueType::Str8l,
810            Self::Str16l(_) => TLVValueType::Str16l,
811            Self::Str32l(_) => TLVValueType::Str32l,
812            Self::Str64l(_) => TLVValueType::Str64l,
813            Self::Null => TLVValueType::Null,
814            Self::Struct => TLVValueType::Struct,
815            Self::Array => TLVValueType::Array,
816            Self::List => TLVValueType::List,
817            Self::EndCnt => TLVValueType::EndCnt,
818        }
819    }
820
821    /// Create a TLV value as an S8 TLV value.
822    pub const fn i8(value: i8) -> Self {
823        Self::S8(value)
824    }
825
826    /// Create a TLV value as an S8 or S16 TLV value,
827    /// depending on whether the value is small enough to fit in an S8 TLV value.
828    pub const fn i16(value: i16) -> Self {
829        if value >= i8::MIN as i16 && value <= i8::MAX as i16 {
830            Self::i8(value as i8)
831        } else {
832            Self::S16(value)
833        }
834    }
835
836    /// Create a TLV value as an S8, S16, or S32 TLV value,
837    /// depending on whether the value is small enough to fit in an S8 or S16 TLV value.
838    pub const fn i32(value: i32) -> Self {
839        if value >= i16::MIN as i32 && value <= i16::MAX as i32 {
840            Self::i16(value as i16)
841        } else {
842            Self::S32(value)
843        }
844    }
845
846    /// Create a TLV value as an S8, S16, S32, or S64 TLV value,
847    /// depending on whether the value is small enough to fit in an S8, S16, or S32 TLV value.
848    pub const fn i64(value: i64) -> Self {
849        if value >= i32::MIN as i64 && value <= i32::MAX as i64 {
850            Self::i32(value as i32)
851        } else {
852            Self::S64(value)
853        }
854    }
855
856    /// Create a TLV value as a U8 TLV value.
857    pub const fn u8(value: u8) -> Self {
858        Self::U8(value)
859    }
860
861    /// Create a TLV value as a U8 or U16 TLV value,
862    /// depending on whether the value is small enough to fit in a U8 TLV value.
863    pub const fn u16(value: u16) -> Self {
864        if value <= u8::MAX as u16 {
865            Self::u8(value as u8)
866        } else {
867            Self::U16(value)
868        }
869    }
870
871    /// Create a TLV value as a U8, U16, or U32 TLV value,
872    /// depending on whether the value is small enough to fit in a U8 or U16 TLV value.
873    pub const fn u32(value: u32) -> Self {
874        if value <= u16::MAX as u32 {
875            Self::u16(value as u16)
876        } else {
877            Self::U32(value)
878        }
879    }
880
881    /// Create a TLV value as a U8, U16, U32, or U64 TLV value,
882    /// depending on whether the value is small enough to fit in a U8, U16, or U32 TLV value.
883    pub const fn u64(value: u64) -> Self {
884        if value <= u32::MAX as u64 {
885            Self::u32(value as u32)
886        } else {
887            Self::U64(value)
888        }
889    }
890
891    /// Create a TLV value as an F32 TLV value.
892    pub const fn f32(value: f32) -> Self {
893        Self::F32(value)
894    }
895
896    /// Create a TLV value as an F64 TLV value.
897    pub const fn f64(value: f64) -> Self {
898        Self::F64(value)
899    }
900
901    /// Create a TLV value as a UTF-8 TLV value.
902    /// The length of the string is encoded as 1, 2, 4 or 8 octets,
903    /// depending on the length of the string.
904    pub const fn utf8(value: &'a str) -> Self {
905        let len = value.len();
906
907        if len <= u8::MAX as usize {
908            Self::Utf8l(value)
909        } else if len <= u16::MAX as usize {
910            Self::Utf16l(value)
911        } else if len <= u32::MAX as usize {
912            Self::Utf32l(value)
913        } else {
914            Self::Utf64l(value)
915        }
916    }
917
918    /// Create a TLV value as an octet string TLV value.
919    /// The length of the string is encoded as 1, 2, 4 or 8 octets,
920    /// depending on the length of the string.
921    pub const fn str(value: &'a [u8]) -> Self {
922        let len = value.len();
923
924        if len <= u8::MAX as usize {
925            Self::Str8l(value)
926        } else if len <= u16::MAX as usize {
927            Self::Str16l(value)
928        } else if len <= u32::MAX as usize {
929            Self::Str32l(value)
930        } else {
931            Self::Str64l(value)
932        }
933    }
934
935    /// Create a TLV value of type Struct (start).
936    pub const fn r#struct() -> Self {
937        Self::Struct
938    }
939
940    /// Create a TLV value of type Struct (start).
941    pub const fn structure() -> Self {
942        Self::Struct
943    }
944
945    /// Create a TLV value of type Array (start).
946    pub const fn array() -> Self {
947        Self::Array
948    }
949
950    /// Create a TLV value of type List (start).
951    pub const fn list() -> Self {
952        Self::List
953    }
954
955    /// Create a TLV value of type EndCnt (container end).
956    pub const fn end_container() -> Self {
957        Self::EndCnt
958    }
959
960    /// Create a TLV value of type Null.
961    pub const fn null() -> Self {
962        Self::Null
963    }
964
965    /// Create a TLV value of type boolean (True or False).
966    pub const fn bool(value: bool) -> Self {
967        if value {
968            Self::True
969        } else {
970            Self::False
971        }
972    }
973
974    /// Return an iterator over the bytes of the TLV value.
975    pub fn iter(&self) -> TLVValueIter<'a, &Self> {
976        TLVValueIter {
977            value: self,
978            _p: PhantomData,
979            index: 0,
980        }
981    }
982
983    /// Converts itself into an iterator over the bytes of the TLV value.
984    pub fn into_iterator(self) -> TLVValueIter<'a, Self> {
985        TLVValueIter {
986            value: self,
987            _p: PhantomData,
988            index: 0,
989        }
990    }
991
992    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
993        match self {
994            Self::S8(a) => write!(f, "S8({a})"),
995            Self::S16(a) => write!(f, "S16({a})"),
996            Self::S32(a) => write!(f, "S32({a})"),
997            Self::S64(a) => write!(f, "S64({a})"),
998            Self::U8(a) => write!(f, "U8(0x{a:02x})"),
999            Self::U16(a) => write!(f, "U16(0x{a:04x})"),
1000            Self::U32(a) => write!(f, "U32(0x{a:08x})"),
1001            Self::U64(a) => write!(f, "U64(0x{a:016x})"),
1002            Self::F32(a) => write!(f, "F32({a})"),
1003            Self::F64(a) => write!(f, "F64({a})"),
1004            Self::Null => write!(f, "Null"),
1005            Self::Struct => write!(f, "{{"),
1006            Self::Array => write!(f, "["),
1007            Self::List => write!(f, "("),
1008            Self::True => write!(f, "True"),
1009            Self::False => write!(f, "False"),
1010            Self::Utf8l(a) | Self::Utf16l(a) | Self::Utf32l(a) | Self::Utf64l(a) => {
1011                write!(f, "\"{a}\"")
1012            }
1013            Self::Str8l(a) | Self::Str16l(a) | Self::Str32l(a) | Self::Str64l(a) => {
1014                write!(f, "({}){a:02X?}", a.len())
1015            }
1016            Self::EndCnt => write!(f, ">"),
1017        }
1018    }
1019}
1020
1021impl<'a> IntoIterator for TLVValue<'a> {
1022    type Item = u8;
1023    type IntoIter = TLVValueIter<'a, Self>;
1024
1025    fn into_iter(self) -> Self::IntoIter {
1026        TLVValue::into_iterator(self)
1027    }
1028}
1029
1030impl<'a> IntoIterator for &TLVValue<'a> {
1031    type Item = u8;
1032    type IntoIter = TLVValueIter<'a, Self>;
1033
1034    fn into_iter(self) -> Self::IntoIter {
1035        TLVValue::iter(self)
1036    }
1037}
1038
1039/// An iterator over the bytes of a TLV value.
1040pub struct TLVValueIter<'a, T>
1041where
1042    T: Borrow<TLVValue<'a>>,
1043{
1044    value: T,
1045    _p: PhantomData<&'a ()>,
1046    index: usize,
1047}
1048
1049impl<'a, T> TLVValueIter<'a, T>
1050where
1051    T: Borrow<TLVValue<'a>>,
1052{
1053    fn variable_len_len(&self) -> usize {
1054        match self.value.borrow() {
1055            TLVValue::Utf8l(_) | TLVValue::Str8l(_) => 1,
1056            TLVValue::Utf16l(_) | TLVValue::Str16l(_) => 2,
1057            TLVValue::Utf32l(_) | TLVValue::Str32l(_) => 4,
1058            TLVValue::Utf64l(_) | TLVValue::Str64l(_) => 8,
1059            _ => 0,
1060        }
1061    }
1062
1063    fn next_byte(&mut self, bytes: &[u8]) -> Option<u8> {
1064        self.next_byte_offset(0, bytes)
1065    }
1066
1067    fn next_byte_offset(&mut self, offset: usize, bytes: &[u8]) -> Option<u8> {
1068        if self.index - offset < bytes.len() {
1069            let byte = bytes[self.index - offset];
1070
1071            self.index += 1;
1072
1073            Some(byte)
1074        } else {
1075            None
1076        }
1077    }
1078}
1079
1080impl<'a, T> Iterator for TLVValueIter<'a, T>
1081where
1082    T: Borrow<TLVValue<'a>>,
1083{
1084    type Item = u8;
1085
1086    fn next(&mut self) -> Option<Self::Item> {
1087        match self.value.borrow() {
1088            TLVValue::S8(a) => self.next_byte(&a.to_le_bytes()),
1089            TLVValue::S16(a) => self.next_byte(&a.to_le_bytes()),
1090            TLVValue::S32(a) => self.next_byte(&a.to_le_bytes()),
1091            TLVValue::S64(a) => self.next_byte(&a.to_le_bytes()),
1092            TLVValue::U8(a) => self.next_byte(&a.to_le_bytes()),
1093            TLVValue::U16(a) => self.next_byte(&a.to_le_bytes()),
1094            TLVValue::U32(a) => self.next_byte(&a.to_le_bytes()),
1095            TLVValue::U64(a) => self.next_byte(&a.to_le_bytes()),
1096            TLVValue::F32(a) => self.next_byte(&a.to_le_bytes()),
1097            TLVValue::F64(a) => self.next_byte(&a.to_le_bytes()),
1098            TLVValue::Utf8l(a) | TLVValue::Utf16l(a) | TLVValue::Utf32l(a) => {
1099                let len_len = self.variable_len_len();
1100                if self.index < len_len {
1101                    self.next_byte(&a.len().to_le_bytes())
1102                } else {
1103                    self.next_byte_offset(len_len, a.as_bytes())
1104                }
1105            }
1106            TLVValue::Str8l(a) | TLVValue::Str16l(a) | TLVValue::Str32l(a) => {
1107                let len_len = self.variable_len_len();
1108                if self.index < len_len {
1109                    self.next_byte(&a.len().to_le_bytes())
1110                } else {
1111                    self.next_byte_offset(len_len, a)
1112                }
1113            }
1114            _ => None,
1115        }
1116    }
1117}
1118
1119impl fmt::Display for TLVValue<'_> {
1120    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1121        self.fmt(f)
1122    }
1123}
1124
1125pub(crate) fn pad(ident: usize, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1126    for _ in 0..ident {
1127        write!(f, "  ")?;
1128    }
1129
1130    Ok(())
1131}
1132
1133/// For backwards compatibility
1134pub fn get_root_node_struct(data: &[u8]) -> Result<TLVElement<'_>, Error> {
1135    // TODO: Check for trailing data
1136    let element = TLVElement::new(data);
1137
1138    element.structure()?;
1139
1140    Ok(element)
1141}