Skip to main content

matc/
tlv.rs

1//! Utilities to decode/encode matter tlv
2
3use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
4use core::fmt;
5use std::io::{Cursor, Read, Result, Write};
6
7/// Buffer to encode matter tlv. Create buffer, write elements then use data member which contains encoded tlv.
8/// Example how to commission device using certificates pre-created in pem directory:
9/// ```
10/// # use matc::tlv;
11/// # use anyhow::Result;
12/// # fn main() -> Result<()> {
13/// let mut tlv = tlv::TlvBuffer::new();
14/// tlv.write_struct(1)?;
15/// tlv.write_uint8(0, 100)?;
16/// tlv.write_string(0, "test")?;
17/// tlv.write_struct_end()?;
18/// // now tlv.data contains encoded tlv buffer
19/// # Ok(())
20/// # }
21/// ```
22pub struct TlvBuffer {
23    pub data: Vec<u8>,
24}
25
26const TYPE_INT_1: u8 = 0;
27const TYPE_INT_2: u8 = 1;
28const TYPE_INT_4: u8 = 2;
29const TYPE_INT_8: u8 = 3;
30const TYPE_UINT_1: u8 = 4;
31const TYPE_UINT_2: u8 = 5;
32const TYPE_UINT_4: u8 = 6;
33const TYPE_UINT_8: u8 = 7;
34const TYPE_BOOL_FALSE: u8 = 8;
35const TYPE_BOOL_TRUE: u8 = 9;
36const TYPE_FLOAT_4: u8 = 0xA;
37const TYPE_FLOAT_8: u8 = 0xB;
38const TYPE_UTF8_L1: u8 = 0xC;
39const TYPE_OCTET_STRING_L1: u8 = 0x10;
40const TYPE_OCTET_STRING_L2: u8 = 0x11;
41const TYPE_OCTET_STRING_L4: u8 = 0x12;
42const TYPE_OCTET_STRING_L8: u8 = 0x13;
43
44const TYPE_STRUCT: u8 = 0x15;
45const TYPE_ARRAY: u8 = 0x16;
46const TYPE_LIST: u8 = 0x17;
47const TYPE_END_CONTAINER: u8 = 0x18;
48
49const CTRL_CTX_L1: u8 = 1 << 5;
50
51impl TlvBuffer {
52    pub fn new() -> Self {
53        Self {
54            data: Vec::with_capacity(1024),
55        }
56    }
57    pub fn from_vec(v: Vec<u8>) -> Self {
58        Self { data: v }
59    }
60    pub fn write_raw(&mut self, data: &[u8]) -> Result<()> {
61        self.data.write_all(data)
62    }
63    pub fn write_anon_struct(&mut self) -> Result<()> {
64        self.data.write_u8(TYPE_STRUCT)?;
65        Ok(())
66    }
67    pub fn write_anon_list(&mut self) -> Result<()> {
68        self.data.write_u8(TYPE_LIST)?;
69        Ok(())
70    }
71    pub fn write_struct(&mut self, tag: u8) -> Result<()> {
72        self.data.write_u8(CTRL_CTX_L1 | TYPE_STRUCT)?;
73        self.data.write_u8(tag)?;
74        Ok(())
75    }
76    pub fn write_array(&mut self, tag: u8) -> Result<()> {
77        self.data.write_u8(CTRL_CTX_L1 | TYPE_ARRAY)?;
78        self.data.write_u8(tag)?;
79        Ok(())
80    }
81    pub fn write_list(&mut self, tag: u8) -> Result<()> {
82        self.data.write_u8(CTRL_CTX_L1 | TYPE_LIST)?;
83        self.data.write_u8(tag)?;
84        Ok(())
85    }
86    pub fn write_struct_end(&mut self) -> Result<()> {
87        self.data.write_u8(TYPE_END_CONTAINER)?;
88        Ok(())
89    }
90    pub fn write_string(&mut self, tag: u8, data: &str) -> Result<()> {
91        let ctrl = CTRL_CTX_L1 | TYPE_UTF8_L1;
92        let bytes = data.as_bytes();
93        self.data.write_u8(ctrl)?;
94        self.data.write_u8(tag)?;
95        self.data.write_u8(bytes.len() as u8)?;
96        self.data.write_all(bytes)?;
97        Ok(())
98    }
99    pub fn write_octetstring(&mut self, tag: u8, data: &[u8]) -> Result<()> {
100        if data.len() > 0xff {
101            self.data.write_u8(CTRL_CTX_L1 | TYPE_OCTET_STRING_L2)?;
102            self.data.write_u8(tag)?;
103            self.data.write_u16::<LittleEndian>(data.len() as u16)?;
104        } else {
105            self.data.write_u8(CTRL_CTX_L1 | TYPE_OCTET_STRING_L1)?;
106            self.data.write_u8(tag)?;
107            self.data.write_u8(data.len() as u8)?;
108        }
109        self.data.write_all(data)?;
110        Ok(())
111    }
112    pub fn write_int8(&mut self, tag: u8, value: i8) -> Result<()> {
113        self.data.write_u8(CTRL_CTX_L1 | TYPE_INT_1)?;
114        self.data.write_u8(tag)?;
115        self.data.write_i8(value)
116    }
117    pub fn write_int16(&mut self, tag: u8, value: i16) -> Result<()> {
118        self.data.write_u8(CTRL_CTX_L1 | TYPE_INT_2)?;
119        self.data.write_u8(tag)?;
120        self.data.write_i16::<LittleEndian>(value)
121    }
122    pub fn write_int32(&mut self, tag: u8, value: i32) -> Result<()> {
123        self.data.write_u8(CTRL_CTX_L1 | TYPE_INT_4)?;
124        self.data.write_u8(tag)?;
125        self.data.write_i32::<LittleEndian>(value)
126    }
127    pub fn write_int64(&mut self, tag: u8, value: i64) -> Result<()> {
128        self.data.write_u8(CTRL_CTX_L1 | TYPE_INT_8)?;
129        self.data.write_u8(tag)?;
130        self.data.write_i64::<LittleEndian>(value)
131    }
132    pub fn write_uint8(&mut self, tag: u8, value: u8) -> Result<()> {
133        self.data.write_u8(CTRL_CTX_L1 | TYPE_UINT_1)?;
134        self.data.write_u8(tag)?;
135        self.data.write_u8(value)
136    }
137    pub fn write_octetstring_notag(&mut self, data: &[u8]) -> Result<()> {
138        if data.len() > 0xff {
139            self.data.write_u8(TYPE_OCTET_STRING_L2)?;
140            self.data.write_u16::<LittleEndian>(data.len() as u16)?;
141        } else {
142            self.data.write_u8(TYPE_OCTET_STRING_L1)?;
143            self.data.write_u8(data.len() as u8)?;
144        }
145        self.data.write_all(data)
146    }
147    pub fn write_uint8_notag(&mut self, value: u8) -> Result<()> {
148        self.data.write_u8(TYPE_UINT_1)?;
149        self.data.write_u8(value)
150    }
151    pub fn write_uint16_notag(&mut self, value: u16) -> Result<()> {
152        self.data.write_u8(TYPE_UINT_2)?;
153        self.data.write_u16::<LittleEndian>(value)
154    }
155    pub fn write_uint32_notag(&mut self, value: u32) -> Result<()> {
156        self.data.write_u8(TYPE_UINT_4)?;
157        self.data.write_u32::<LittleEndian>(value)
158    }
159    pub fn write_uint16(&mut self, tag: u8, value: u16) -> Result<()> {
160        self.data.write_u8(CTRL_CTX_L1 | TYPE_UINT_2)?;
161        self.data.write_u8(tag)?;
162        self.data.write_u16::<LittleEndian>(value)
163    }
164    pub fn write_uint32(&mut self, tag: u8, value: u32) -> Result<()> {
165        self.data.write_u8(CTRL_CTX_L1 | TYPE_UINT_4)?;
166        self.data.write_u8(tag)?;
167        self.data.write_u32::<LittleEndian>(value)
168    }
169    pub fn write_uint64(&mut self, tag: u8, value: u64) -> Result<()> {
170        self.data.write_u8(CTRL_CTX_L1 | TYPE_UINT_8)?;
171        self.data.write_u8(tag)?;
172        self.data.write_u64::<LittleEndian>(value)
173    }
174    pub fn write_bool(&mut self, tag: u8, value: bool) -> Result<()> {
175        if value {
176            self.data.write_u8(CTRL_CTX_L1 | TYPE_BOOL_TRUE)?;
177        } else {
178            self.data.write_u8(CTRL_CTX_L1 | TYPE_BOOL_FALSE)?;
179        }
180        self.data.write_u8(tag)
181    }
182}
183
184impl Default for TlvBuffer {
185    fn default() -> Self {
186        Self::new()
187    }
188}
189
190/// Enum containing data of decoded tlv element
191#[derive(Clone, PartialEq)]
192pub enum TlvItemValue {
193    Int(u64),
194    Bool(bool),
195    String(String),
196    OctetString(Vec<u8>),
197    Float(f64),
198    List(Vec<TlvItem>),
199    Nil(),
200    Invalid(),
201}
202
203impl From<TlvItemValue> for bool {
204    fn from(value: TlvItemValue) -> Self {
205        match value {
206            TlvItemValue::Bool(b) => b,
207            _ => false,
208        }
209    }
210}
211impl From<TlvItemValue> for String {
212    fn from(value: TlvItemValue) -> Self {
213        match value {
214            TlvItemValue::String(s) => s,
215            _ => String::new(),
216        }
217    }
218}
219
220impl<'a> TryFrom<&'a TlvItemValue> for &'a [u8] {
221    type Error = &'static str;
222    fn try_from(value: &'a TlvItemValue) -> std::result::Result<Self, Self::Error> {
223        if let TlvItemValue::OctetString(ref s) = value {
224            Ok(s.as_slice())
225        } else {
226            Err("Not an octet string")
227        }
228    }
229}
230impl From<TlvItemValue> for Vec<u8> {
231    fn from(value: TlvItemValue) -> Self {
232        match value {
233            TlvItemValue::OctetString(s) => s,
234            _ => Vec::new(),
235        }
236    }
237}
238impl From<TlvItemValue> for u64 {
239    fn from(value: TlvItemValue) -> Self {
240        match value {
241            TlvItemValue::Int(i) => i,
242            _ => 0,
243        }
244    }
245}
246impl From<TlvItemValue> for Vec<TlvItem> {
247    fn from(value: TlvItemValue) -> Self {
248        match value {
249            TlvItemValue::List(lst) => lst,
250            _ => panic!("Cannot convert to Vec<TlvItem>"),
251        }
252    }
253}
254
255/// Decoded tlv element returned by [decode_tlv]
256#[derive(Debug, Clone, PartialEq)]
257pub struct TlvItem {
258    pub tag: u8,
259    pub value: TlvItemValue,
260}
261
262impl fmt::Debug for TlvItemValue {
263    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
264        match self {
265            Self::Int(arg0) => f.debug_tuple("Int").field(arg0).finish(),
266            Self::Bool(arg0) => f.debug_tuple("Bool").field(arg0).finish(),
267            Self::String(arg0) => f.debug_tuple("String").field(arg0).finish(),
268            Self::OctetString(arg0) => f
269                .debug_tuple("OctetString")
270                .field(&hex::encode(arg0))
271                .finish(),
272            Self::List(arg0) => f.debug_tuple("List").field(arg0).finish(),
273            Self::Nil() => f.debug_tuple("Nil").finish(),
274            Self::Invalid() => f.debug_tuple("Invalid").finish(),
275            Self::Float(arg0) => f.debug_tuple("Float").field(arg0).finish(),
276        }
277    }
278}
279
280impl TlvItem {
281    pub fn get(&self, tag: &[u8]) -> Option<&TlvItemValue> {
282        if !tag.is_empty() {
283            if let TlvItemValue::List(lst) = &self.value {
284                for l in lst {
285                    if l.tag == tag[0] {
286                        return l.get(&tag[1..]);
287                    };
288                }
289            }
290            None
291        } else {
292            Some(&self.value)
293        }
294    }
295    pub fn get_item(&self, tag: &[u8]) -> Option<&TlvItem> {
296        if !tag.is_empty() {
297            if let TlvItemValue::List(lst) = &self.value {
298                for l in lst {
299                    if l.tag == tag[0] {
300                        return l.get_item(&tag[1..]);
301                    };
302                }
303            }
304            None
305        } else {
306            Some(self)
307        }
308    }
309
310    pub fn get_int(&self, tag: &[u8]) -> Option<u64> {
311        let found = self.get(tag);
312        if let Some(TlvItemValue::Int(i)) = found {
313            Some(*i)
314        } else {
315            None
316        }
317    }
318
319    pub fn get_float(&self, tag: &[u8]) -> Option<f64> {
320        let found = self.get(tag);
321        if let Some(TlvItemValue::Float(f)) = found {
322            Some(*f)
323        } else {
324            None
325        }
326    }
327
328    pub fn get_t<T>(&self, tag: &[u8]) -> Option<T>
329    where
330        T: From<TlvItemValue>,
331    {
332        self.get(tag).map(|f| f.clone().into())
333    }
334
335    pub fn get_bool(&self, tag: &[u8]) -> Option<bool> {
336        self.get(tag).map(|f| f.clone().into())
337        /*let found = self.get(tag);
338        if let Some(TlvItemValue::Bool(i)) = found {
339            Some(*i)
340        } else {
341            None
342        }*/
343    }
344    pub fn get_u8(&self, tag: &[u8]) -> Option<u8> {
345        let found = self.get(tag);
346        if let Some(TlvItemValue::Int(i)) = found {
347            Some(*i as u8)
348        } else {
349            None
350        }
351    }
352    pub fn get_u16(&self, tag: &[u8]) -> Option<u16> {
353        let found = self.get(tag);
354        if let Some(TlvItemValue::Int(i)) = found {
355            Some(*i as u16)
356        } else {
357            None
358        }
359    }
360    pub fn get_u32(&self, tag: &[u8]) -> Option<u32> {
361        let found = self.get(tag);
362        if let Some(TlvItemValue::Int(i)) = found {
363            Some(*i as u32)
364        } else {
365            None
366        }
367    }
368    pub fn get_u64(&self, tag: &[u8]) -> Option<u64> {
369        let found = self.get(tag);
370        if let Some(TlvItemValue::Int(i)) = found {
371            Some(*i)
372        } else {
373            None
374        }
375    }
376    pub fn get_octet_string(&self, tag: &[u8]) -> Option<&[u8]> {
377        let found = self.get(tag);
378        if let Some(TlvItemValue::OctetString(o)) = found {
379            Some(o)
380        } else {
381            None
382        }
383    }
384    pub fn get_octet_string_owned(&self, tag: &[u8]) -> Option<Vec<u8>> {
385        let found = self.get(tag);
386        if let Some(TlvItemValue::OctetString(o)) = found {
387            Some(o.to_owned())
388        } else {
389            None
390        }
391    }
392    pub fn get_string_owned(&self, tag: &[u8]) -> Option<String> {
393        let found = self.get(tag);
394        if let Some(TlvItemValue::String(o)) = found {
395            Some(o.clone())
396        } else {
397            None
398        }
399    }
400    pub fn dump(&self, indent: usize) {
401        match &self.value {
402            TlvItemValue::List(vec) => {
403                println!("{} {}", " ".to_owned().repeat(indent), self.tag);
404                for v in vec {
405                    v.dump(indent + 1);
406                }
407            }
408            _ => {
409                println!(
410                    "{} {} {:?}",
411                    " ".to_owned().repeat(indent),
412                    self.tag,
413                    self.value
414                );
415            }
416        }
417    }
418}
419
420fn read_tag(tagctrl: u8, cursor: &mut Cursor<&[u8]>) -> Result<u8> {
421    if tagctrl == 1 {
422        cursor.read_u8()
423    } else {
424        Ok(0)
425    }
426}
427
428fn decode(cursor: &mut Cursor<&[u8]>, container: &mut Vec<TlvItem>) -> Result<()> {
429    while cursor.position() < cursor.get_ref().len() as u64 {
430        let fb = cursor.read_u8()?;
431        let tp = fb & 0x1f;
432        let tagctrl = fb >> 5;
433        let tag = read_tag(tagctrl, cursor)?;
434        match tp {
435            TYPE_INT_1 => {
436                let value = cursor.read_u8()?;
437                let item = TlvItem {
438                    tag,
439                    value: TlvItemValue::Int(value as u64),
440                };
441                container.push(item);
442            }
443            TYPE_INT_2 => {
444                let value = cursor.read_i16::<LittleEndian>()?;
445                let item = TlvItem {
446                    tag,
447                    value: TlvItemValue::Int(value as u64),
448                };
449                container.push(item);
450            }
451            TYPE_INT_4 => {
452                let value = cursor.read_i32::<LittleEndian>()?;
453                let item = TlvItem {
454                    tag,
455                    value: TlvItemValue::Int(value as u64),
456                };
457                container.push(item);
458            }
459            TYPE_INT_8 => {
460                let value = cursor.read_i64::<LittleEndian>()?;
461                let item = TlvItem {
462                    tag,
463                    value: TlvItemValue::Int(value as u64),
464                };
465                container.push(item);
466            }
467            TYPE_UINT_1 => {
468                let value = cursor.read_u8()?;
469                let item = TlvItem {
470                    tag,
471                    value: TlvItemValue::Int(value as u64),
472                };
473                container.push(item);
474            }
475            TYPE_UINT_2 => {
476                let value = cursor.read_u16::<LittleEndian>()?;
477                let item = TlvItem {
478                    tag,
479                    value: TlvItemValue::Int(value as u64),
480                };
481                container.push(item);
482            }
483            TYPE_UINT_4 => {
484                let value = cursor.read_u32::<LittleEndian>()?;
485                let item = TlvItem {
486                    tag,
487                    value: TlvItemValue::Int(value as u64),
488                };
489                container.push(item);
490            }
491            TYPE_UINT_8 => {
492                let value = cursor.read_u64::<LittleEndian>()?;
493                let item = TlvItem {
494                    tag,
495                    value: TlvItemValue::Int(value),
496                };
497                container.push(item);
498            }
499            TYPE_BOOL_FALSE => {
500                let item = TlvItem {
501                    tag,
502                    value: TlvItemValue::Bool(false),
503                };
504                container.push(item);
505            }
506            TYPE_BOOL_TRUE => {
507                let item = TlvItem {
508                    tag,
509                    value: TlvItemValue::Bool(true),
510                };
511                container.push(item);
512            }
513            TYPE_FLOAT_4 => {
514                let value = cursor.read_f32::<LittleEndian>()?;
515                let item = TlvItem {
516                    tag,
517                    value: TlvItemValue::Float(value as f64),
518                };
519                container.push(item);
520            }
521            TYPE_FLOAT_8 => {
522                let value = cursor.read_f64::<LittleEndian>()?;
523                let item = TlvItem {
524                    tag,
525                    value: TlvItemValue::Float(value),
526                };
527                container.push(item);
528            }
529            TYPE_UTF8_L1 => {
530                // utf8 string
531                let size = cursor.read_u8()?;
532                let mut value = vec![0; size as usize];
533                cursor.read_exact(&mut value)?;
534                let str = String::from_utf8(value);
535                let typ = match str {
536                    Ok(s) => TlvItemValue::String(s),
537                    Err(_) => TlvItemValue::Invalid(),
538                };
539                let item = TlvItem { tag, value: typ };
540                container.push(item);
541            }
542            TYPE_OCTET_STRING_L1 => {
543                // octet string
544                let size = cursor.read_u8()?;
545                let mut value = vec![0; size as usize];
546                cursor.read_exact(&mut value)?;
547                let item = TlvItem {
548                    tag,
549                    value: TlvItemValue::OctetString(value),
550                };
551                container.push(item);
552            }
553            TYPE_OCTET_STRING_L2 => {
554                // octet string large
555                let size = cursor.read_u16::<LittleEndian>()?;
556                let mut value = vec![0; size as usize];
557                cursor.read_exact(&mut value)?;
558                let item = TlvItem {
559                    tag,
560                    value: TlvItemValue::OctetString(value),
561                };
562                container.push(item);
563            }
564            TYPE_OCTET_STRING_L4 => {
565                // octet string very large
566                let size = cursor.read_u32::<LittleEndian>()?;
567                let mut value = vec![0; size as usize];
568                cursor.read_exact(&mut value)?;
569                let item = TlvItem {
570                    tag,
571                    value: TlvItemValue::OctetString(value),
572                };
573                container.push(item);
574            }
575            TYPE_OCTET_STRING_L8 => {
576                // octet string very very xtra large
577                let size = cursor.read_u64::<LittleEndian>()?;
578                let mut value = vec![0; size as usize];
579                cursor.read_exact(&mut value)?;
580                let item = TlvItem {
581                    tag,
582                    value: TlvItemValue::OctetString(value),
583                };
584                container.push(item);
585            }
586            TYPE_STRUCT => {
587                //list
588                let mut c2 = Vec::new();
589                decode(cursor, &mut c2)?;
590                let item = TlvItem {
591                    tag,
592                    value: TlvItemValue::List(c2),
593                };
594                container.push(item);
595            }
596            TYPE_ARRAY => {
597                //list
598                let mut c2 = Vec::new();
599                decode(cursor, &mut c2)?;
600                let item = TlvItem {
601                    tag,
602                    value: TlvItemValue::List(c2),
603                };
604                container.push(item);
605            }
606            TYPE_LIST => {
607                //list
608                let mut c2 = Vec::new();
609                decode(cursor, &mut c2)?;
610                let item = TlvItem {
611                    tag,
612                    value: TlvItemValue::List(c2),
613                };
614                container.push(item);
615            }
616            TYPE_END_CONTAINER => return Ok(()),
617            0x14 => {
618                let item = TlvItem {
619                    tag,
620                    value: TlvItemValue::Nil(),
621                };
622                container.push(item);
623            }
624            _ => {
625                return Err(std::io::Error::new(
626                    std::io::ErrorKind::InvalidData,
627                    format!("unknown tlv type 0x{:x}", tp),
628                ))
629            }
630        }
631    }
632    Ok(())
633}
634
635/// decode raw buffer with tlv data
636pub fn decode_tlv(data: &[u8]) -> Result<TlvItem> {
637    let mut container = Vec::new();
638    let mut cursor = std::io::Cursor::new(data);
639    decode(&mut cursor, &mut container)?;
640    if container.len() == 1 {
641        if let Some(i) = container.pop() {
642            Ok(i)
643        } else {
644            Err(std::io::Error::new(
645                std::io::ErrorKind::InvalidData,
646                "no data found",
647            ))
648        }
649    } else {
650        Ok(TlvItem {
651            tag: 0,
652            value: TlvItemValue::List(container),
653        })
654    }
655}
656
657#[derive(Debug)]
658pub enum TlvItemValueEnc {
659    Int8(i8),
660    Int16(i16),
661    Int32(i32),
662    Int64(i64),
663    UInt8(u8),
664    UInt8Anonymous(u8),
665    UInt16(u16),
666    UInt32(u32),
667    UInt64(u64),
668    Bool(bool),
669    String(String),
670    OctetString(Vec<u8>),
671    StructAnon(Vec<TlvItemEnc>),
672    StructInvisible(Vec<TlvItemEnc>),
673    Struct(Vec<TlvItemEnc>),
674    List(Vec<TlvItemEnc>),
675    Array(Vec<TlvItemEnc>),
676    Invalid(),
677}
678
679/// Structure used for document style encoding.
680///
681/// ```
682/// # use matc::tlv;
683/// let t1 = tlv::TlvItemEnc {
684///   tag: 0,
685///   value: tlv::TlvItemValueEnc::StructAnon(vec![
686///     tlv::TlvItemEnc { tag: 0, value: tlv::TlvItemValueEnc::UInt8(6) },
687///     tlv::TlvItemEnc { tag: 1, value: tlv::TlvItemValueEnc::UInt8(7) }
688///   ]),
689/// };
690/// let o = t1.encode().unwrap();
691/// ```
692#[derive(Debug)]
693pub struct TlvItemEnc {
694    pub tag: u8,
695    pub value: TlvItemValueEnc,
696}
697
698impl From<(u8, TlvItemValueEnc)> for TlvItemEnc {
699    fn from(item: (u8, TlvItemValueEnc)) -> Self {
700        TlvItemEnc {
701            tag: item.0,
702            value: item.1,
703        }
704    }
705}
706
707impl TlvItemEnc {
708    fn encode_internal(&self, buf: &mut TlvBuffer) -> Result<()> {
709        match &self.value {
710            TlvItemValueEnc::Int8(i) => {
711                buf.write_int8(self.tag, *i)?;
712            }
713            TlvItemValueEnc::Int16(i) => {
714                buf.write_int16(self.tag, *i)?;
715            }
716            TlvItemValueEnc::Int32(i) => {
717                buf.write_int32(self.tag, *i)?;
718            }
719            TlvItemValueEnc::Int64(i) => {
720                buf.write_int64(self.tag, *i)?;
721            }
722            TlvItemValueEnc::UInt8(i) => {
723                buf.write_uint8(self.tag, *i)?;
724            }
725            TlvItemValueEnc::UInt8Anonymous(i) => {
726                buf.write_uint8_notag(*i)?;
727            }
728            TlvItemValueEnc::UInt16(i) => {
729                buf.write_uint16(self.tag, *i)?;
730            }
731            TlvItemValueEnc::UInt32(i) => {
732                buf.write_uint32(self.tag, *i)?;
733            }
734            TlvItemValueEnc::UInt64(i) => {
735                buf.write_uint64(self.tag, *i)?;
736            }
737            TlvItemValueEnc::Bool(v) => {
738                buf.write_bool(self.tag, *v)?;
739            }
740            TlvItemValueEnc::String(s) => {
741                buf.write_string(self.tag, s)?;
742            }
743            TlvItemValueEnc::OctetString(vec) => {
744                buf.write_octetstring(self.tag, vec)?;
745            }
746            TlvItemValueEnc::StructAnon(vec) => {
747                buf.write_anon_struct()?;
748                for i in vec {
749                    i.encode_internal(buf)?;
750                }
751                buf.write_struct_end()?;
752            }
753            TlvItemValueEnc::Struct(vec) => {
754                buf.write_struct(self.tag)?;
755                for i in vec {
756                    i.encode_internal(buf)?;
757                }
758                buf.write_struct_end()?;
759            }
760            TlvItemValueEnc::List(vec) => {
761                buf.write_list(self.tag)?;
762                for i in vec {
763                    i.encode_internal(buf)?;
764                }
765                buf.write_struct_end()?;
766            }
767            TlvItemValueEnc::Array(vec) => {
768                buf.write_array(self.tag)?;
769                for i in vec {
770                    i.encode_internal(buf)?;
771                }
772                buf.write_struct_end()?;
773            }
774            TlvItemValueEnc::StructInvisible(vec) => {
775                for i in vec {
776                    i.encode_internal(buf)?;
777                }
778            }
779            TlvItemValueEnc::Invalid() => todo!(),
780        }
781        Ok(())
782    }
783
784    pub fn encode(&self) -> Result<Vec<u8>> {
785        let mut tlv = TlvBuffer::new();
786        self.encode_internal(&mut tlv)?;
787        Ok(tlv.data)
788    }
789}
790
791#[cfg(test)]
792mod tests {
793    use super::{decode_tlv, TlvBuffer, TlvItemEnc, TlvItemValue, TlvItemValueEnc};
794
795    #[test]
796    fn test_1() {
797        let t1 = TlvItemEnc {
798            tag: 0,
799            value: TlvItemValueEnc::StructAnon(vec![
800                TlvItemEnc {
801                    tag: 0,
802                    value: TlvItemValueEnc::UInt8(6),
803                },
804                TlvItemEnc {
805                    tag: 1,
806                    value: TlvItemValueEnc::UInt8(7),
807                },
808            ]),
809        };
810        let o = t1.encode().unwrap();
811        assert_eq!(hex::encode(o), "1524000624010718");
812
813        let mut tlv = TlvBuffer::new();
814        tlv.write_anon_struct().unwrap();
815        tlv.write_octetstring(0x1, &[1, 2, 3]).unwrap();
816        tlv.write_struct_end().unwrap();
817        assert_eq!(hex::encode(tlv.data), "1530010301020318");
818
819        let t1 = TlvItemEnc {
820            tag: 0,
821            value: TlvItemValueEnc::StructAnon(vec![TlvItemEnc {
822                tag: 1,
823                value: TlvItemValueEnc::OctetString(vec![1, 2, 3]),
824            }]),
825        }
826        .encode()
827        .unwrap();
828        assert_eq!(hex::encode(t1), "1530010301020318");
829    }
830
831    #[test]
832    fn test_decode_integers() {
833        // Test uint8
834        let mut tlv = TlvBuffer::new();
835        tlv.write_uint8(1, 42).unwrap();
836        let decoded = decode_tlv(&tlv.data).unwrap();
837        assert_eq!(decoded.get_u8(&[]), Some(42));
838
839        // Test uint16
840        let mut tlv = TlvBuffer::new();
841        tlv.write_uint16(2, 1000).unwrap();
842        let decoded = decode_tlv(&tlv.data).unwrap();
843        assert_eq!(decoded.get_u16(&[]), Some(1000));
844
845        // Test uint32
846        let mut tlv = TlvBuffer::new();
847        tlv.write_uint32(3, 100000).unwrap();
848        let decoded = decode_tlv(&tlv.data).unwrap();
849        assert_eq!(decoded.get_u32(&[]), Some(100000));
850
851        // Test uint64
852        let mut tlv = TlvBuffer::new();
853        tlv.write_uint64(4, 1000000000000).unwrap();
854        let decoded = decode_tlv(&tlv.data).unwrap();
855        assert_eq!(decoded.get_u64(&[]), Some(1000000000000));
856    }
857
858    #[test]
859    fn test_decode_booleans() {
860        // Test true
861        let mut tlv = TlvBuffer::new();
862        tlv.write_bool(1, true).unwrap();
863        let decoded = decode_tlv(&tlv.data).unwrap();
864        assert_eq!(decoded.get_bool(&[]), Some(true));
865
866        // Test false
867        let mut tlv = TlvBuffer::new();
868        tlv.write_bool(2, false).unwrap();
869        let decoded = decode_tlv(&tlv.data).unwrap();
870        assert_eq!(decoded.get_bool(&[]), Some(false));
871        assert_eq!(decoded.get_t(&[]), Some(false));
872    }
873
874    #[test]
875    fn test_decode_strings() {
876        let mut tlv = TlvBuffer::new();
877        tlv.write_string(1, "hello world").unwrap();
878        let decoded = decode_tlv(&tlv.data).unwrap();
879        assert_eq!(
880            decoded.get_string_owned(&[]),
881            Some("hello world".to_string())
882        );
883        assert_eq!(decoded.get_t(&[]), Some("hello world".to_string()));
884    }
885
886    #[test]
887    fn test_decode_octet_strings() {
888        // Test small octet string (L1)
889        let mut tlv = TlvBuffer::new();
890        let data = vec![1, 2, 3, 4, 5];
891        tlv.write_octetstring(1, &data).unwrap();
892        let decoded = decode_tlv(&tlv.data).unwrap();
893        assert_eq!(decoded.get_octet_string(&[]), Some(data.as_slice()));
894
895        // Test large octet string (L2)
896        let mut tlv = TlvBuffer::new();
897        let large_data = vec![0; 300]; // Larger than 255 bytes
898        tlv.write_octetstring(2, &large_data).unwrap();
899        let decoded = decode_tlv(&tlv.data).unwrap();
900        assert_eq!(decoded.get_octet_string(&[]), Some(large_data.as_slice()));
901        assert_eq!(
902            decoded.get_octet_string_owned(&[]),
903            Some(large_data.clone())
904        );
905    }
906
907    #[test]
908    fn test_decode_structures() {
909        let mut tlv = TlvBuffer::new();
910        tlv.write_struct(1).unwrap();
911        tlv.write_uint8(0, 100).unwrap();
912        tlv.write_string(1, "test").unwrap();
913        tlv.write_bool(2, true).unwrap();
914        tlv.write_struct_end().unwrap();
915
916        let decoded = decode_tlv(&tlv.data).unwrap();
917
918        // Test nested access
919        assert_eq!(decoded.get_u8(&[0]), Some(100));
920        assert_eq!(decoded.get_string_owned(&[1]), Some("test".to_string()));
921        assert_eq!(decoded.get_bool(&[2]), Some(true));
922
923        // Verify it's a list structure
924        if let TlvItemValue::List(items) = &decoded.value {
925            assert_eq!(items.len(), 3);
926        }
927    }
928
929    #[test]
930    fn test_decode_anonymous_structures() {
931        let mut tlv = TlvBuffer::new();
932        tlv.write_anon_struct().unwrap();
933        tlv.write_uint8_notag(42).unwrap();
934        tlv.write_uint8_notag(84).unwrap();
935        tlv.write_struct_end().unwrap();
936
937        let decoded = decode_tlv(&tlv.data).unwrap();
938
939        if let TlvItemValue::List(items) = &decoded.value {
940            assert_eq!(items.len(), 2);
941            assert_eq!(items[0].tag, 0);
942            assert_eq!(items[1].tag, 0);
943        }
944    }
945
946    #[test]
947    fn test_decode_arrays_and_lists() {
948        // Test array
949        let mut tlv = TlvBuffer::new();
950        tlv.write_array(1).unwrap();
951        tlv.write_uint8(0, 1).unwrap();
952        tlv.write_uint8(0, 2).unwrap();
953        tlv.write_uint8(0, 3).unwrap();
954        tlv.write_struct_end().unwrap();
955
956        let decoded = decode_tlv(&tlv.data).unwrap();
957        if let Some(TlvItemValue::List(items)) = decoded.get(&[]) {
958            assert_eq!(items.len(), 3);
959            assert_eq!(items[0].get_u8(&[]), Some(1));
960            assert_eq!(items[1].get_u8(&[]), Some(2));
961            assert_eq!(items[2].get_u8(&[]), Some(3));
962        } else {
963            panic!("Expected array structure");
964        }
965
966        // Test list
967        let mut tlv = TlvBuffer::new();
968        tlv.write_list(2).unwrap();
969        tlv.write_string(0, "item1").unwrap();
970        tlv.write_string(1, "item2").unwrap();
971        tlv.write_struct_end().unwrap();
972
973        let decoded = decode_tlv(&tlv.data).unwrap();
974        if let Some(TlvItemValue::List(items)) = decoded.get(&[]) {
975            assert_eq!(items.len(), 2);
976            assert_eq!(items[0].get_string_owned(&[]), Some("item1".to_string()));
977            assert_eq!(items[1].get_string_owned(&[]), Some("item2".to_string()));
978        } else {
979            panic!("Expected list structure");
980        }
981    }
982
983    #[test]
984    fn test_decode_mixed_container() {
985        let mut tlv = TlvBuffer::new();
986        tlv.write_uint8(0, 255).unwrap();
987        tlv.write_string(1, "mixed").unwrap();
988        tlv.write_bool(2, false).unwrap();
989
990        let decoded = decode_tlv(&tlv.data).unwrap();
991
992        // Should create a list with multiple items
993        if let TlvItemValue::List(items) = &decoded.value {
994            assert_eq!(items.len(), 3);
995            assert_eq!(items[0].get_u8(&[]), Some(255));
996            assert_eq!(items[1].get_string_owned(&[]), Some("mixed".to_string()));
997            assert_eq!(items[2].get_bool(&[]), Some(false));
998        } else {
999            panic!("Expected list of items");
1000        }
1001    }
1002
1003    #[test]
1004    fn test_decode_nested_structures() {
1005        let mut tlv = TlvBuffer::new();
1006        tlv.write_struct(1).unwrap();
1007        tlv.write_struct(2).unwrap();
1008        tlv.write_uint8(3, 42).unwrap();
1009        tlv.write_struct_end().unwrap(); // End inner struct
1010        tlv.write_string(4, "outer").unwrap();
1011        tlv.write_struct_end().unwrap(); // End outer struct
1012
1013        let decoded = decode_tlv(&tlv.data).unwrap();
1014
1015        // Test deep nested access
1016        assert_eq!(decoded.get_u8(&[2, 3]), Some(42));
1017        assert_eq!(decoded.get_string_owned(&[4]), Some("outer".to_string()));
1018    }
1019
1020    #[test]
1021    fn test_decode_getter_methods() {
1022        let mut tlv = TlvBuffer::new();
1023        tlv.write_struct(0).unwrap();
1024        tlv.write_uint64(1, 0xFFFFFFFFFFFFFFFF).unwrap();
1025        tlv.write_uint32(2, 0xFFFFFFFF).unwrap();
1026        tlv.write_uint16(3, 0xFFFF).unwrap();
1027        tlv.write_uint8(4, 0xFF).unwrap();
1028        tlv.write_struct_end().unwrap();
1029
1030        let decoded = decode_tlv(&tlv.data).unwrap();
1031
1032        // Test type conversions
1033        assert_eq!(decoded.get_u64(&[1]), Some(0xFFFFFFFFFFFFFFFF));
1034        assert_eq!(decoded.get_u32(&[2]), Some(0xFFFFFFFF));
1035        assert_eq!(decoded.get_u16(&[3]), Some(0xFFFF));
1036        assert_eq!(decoded.get_u8(&[4]), Some(0xFF));
1037
1038        // Test downcasting
1039        assert_eq!(decoded.get_u8(&[1]), Some(0xFF)); // u64 -> u8
1040        assert_eq!(decoded.get_u16(&[1]), Some(0xFFFF)); // u64 -> u16
1041    }
1042
1043    #[test]
1044    fn test_decode_invalid_access() {
1045        let mut tlv = TlvBuffer::new();
1046        tlv.write_uint8(1, 42).unwrap();
1047        let decoded = decode_tlv(&tlv.data).unwrap();
1048
1049        // Test accessing non-existent tags
1050        assert_eq!(decoded.get_u8(&[99]), None);
1051        assert_eq!(decoded.get_string_owned(&[1]), None); // Wrong type
1052        assert_eq!(decoded.get_bool(&[1]), None); // Wrong type
1053    }
1054
1055    #[test]
1056    fn test_decode_empty_structure() {
1057        let mut tlv = TlvBuffer::new();
1058        tlv.write_anon_struct().unwrap();
1059        tlv.write_struct_end().unwrap();
1060
1061        let decoded = decode_tlv(&tlv.data).unwrap();
1062
1063        if let TlvItemValue::List(items) = &decoded.value {
1064            assert_eq!(items.len(), 0);
1065        } else {
1066            panic!("Expected empty list");
1067        }
1068    }
1069
1070    #[test]
1071    fn test_get_item_method() {
1072        let mut tlv = TlvBuffer::new();
1073        tlv.write_struct(1).unwrap();
1074        tlv.write_uint8(2, 100).unwrap();
1075        tlv.write_string(3, "test").unwrap();
1076        tlv.write_bool(4, true).unwrap();
1077        tlv.write_struct(5).unwrap();
1078        tlv.write_string(1, "inner").unwrap();
1079        tlv.write_struct_end().unwrap();
1080        tlv.write_struct_end().unwrap();
1081
1082        let decoded = decode_tlv(&tlv.data).unwrap();
1083
1084        // Test get_item returns the actual item
1085        let item = decoded.get_item(&[2]).unwrap();
1086        assert_eq!(item.tag, 2);
1087        if let TlvItemValue::Int(val) = &item.value {
1088            assert_eq!(*val, 100);
1089        } else {
1090            panic!("Expected Int value");
1091        }
1092        let item = decoded.get_item(&[3]).unwrap();
1093        assert_eq!(item.tag, 3);
1094        if let TlvItemValue::String(val) = &item.value {
1095            assert_eq!(*val, "test");
1096        } else {
1097            panic!("Expected String value");
1098        }
1099        let item = decoded.get_item(&[4]).unwrap();
1100        assert_eq!(item.tag, 4);
1101        if let TlvItemValue::Bool(val) = &item.value {
1102            assert!(*val);
1103        } else {
1104            panic!("Expected Bool value");
1105        }
1106        let item = decoded.get_item(&[5]).unwrap();
1107        assert_eq!(item.tag, 5);
1108        if let TlvItemValue::List(items) = &item.value {
1109            assert_eq!(items.len(), 1);
1110            let inner_item = &items[0];
1111            assert_eq!(inner_item.tag, 1);
1112            if let TlvItemValue::String(val) = &inner_item.value {
1113                assert_eq!(*val, "inner");
1114            } else {
1115                panic!("Expected String value");
1116            }
1117        } else {
1118            panic!("Expected List value");
1119        }
1120        let item = decoded.get_item(&[99]);
1121        assert!(item.is_none());
1122    }
1123}