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    pub fn get_int(&self, tag: &[u8]) -> Option<u64> {
310        let found = self.get(tag);
311        if let Some(TlvItemValue::Int(i)) = found {
312            Some(*i)
313        } else {
314            None
315        }
316    }
317    pub fn get_t<T>(&self, tag: &[u8]) -> Option<T>
318    where
319        T: From<TlvItemValue>,
320    {
321        self.get(tag).map(|f| f.clone().into())
322    }
323
324    pub fn get_bool(&self, tag: &[u8]) -> Option<bool> {
325        self.get(tag).map(|f| f.clone().into())
326        /*let found = self.get(tag);
327        if let Some(TlvItemValue::Bool(i)) = found {
328            Some(*i)
329        } else {
330            None
331        }*/
332    }
333    pub fn get_u8(&self, tag: &[u8]) -> Option<u8> {
334        let found = self.get(tag);
335        if let Some(TlvItemValue::Int(i)) = found {
336            Some(*i as u8)
337        } else {
338            None
339        }
340    }
341    pub fn get_u16(&self, tag: &[u8]) -> Option<u16> {
342        let found = self.get(tag);
343        if let Some(TlvItemValue::Int(i)) = found {
344            Some(*i as u16)
345        } else {
346            None
347        }
348    }
349    pub fn get_u32(&self, tag: &[u8]) -> Option<u32> {
350        let found = self.get(tag);
351        if let Some(TlvItemValue::Int(i)) = found {
352            Some(*i as u32)
353        } else {
354            None
355        }
356    }
357    pub fn get_u64(&self, tag: &[u8]) -> Option<u64> {
358        let found = self.get(tag);
359        if let Some(TlvItemValue::Int(i)) = found {
360            Some(*i)
361        } else {
362            None
363        }
364    }
365    pub fn get_octet_string(&self, tag: &[u8]) -> Option<&[u8]> {
366        let found = self.get(tag);
367        if let Some(TlvItemValue::OctetString(o)) = found {
368            Some(o)
369        } else {
370            None
371        }
372    }
373    pub fn get_octet_string_owned(&self, tag: &[u8]) -> Option<Vec<u8>> {
374        let found = self.get(tag);
375        if let Some(TlvItemValue::OctetString(o)) = found {
376            Some(o.to_owned())
377        } else {
378            None
379        }
380    }
381    pub fn get_string_owned(&self, tag: &[u8]) -> Option<String> {
382        let found = self.get(tag);
383        if let Some(TlvItemValue::String(o)) = found {
384            Some(o.clone())
385        } else {
386            None
387        }
388    }
389    pub fn dump(&self, indent: usize) {
390        match &self.value {
391            TlvItemValue::List(vec) => {
392                println!("{} {}", " ".to_owned().repeat(indent), self.tag);
393                for v in vec {
394                    v.dump(indent + 1);
395                }
396            }
397            _ => {
398                println!(
399                    "{} {} {:?}",
400                    " ".to_owned().repeat(indent),
401                    self.tag,
402                    self.value
403                );
404            }
405        }
406    }
407}
408
409fn read_tag(tagctrl: u8, cursor: &mut Cursor<&[u8]>) -> Result<u8> {
410    if tagctrl == 1 {
411        cursor.read_u8()
412    } else {
413        Ok(0)
414    }
415}
416
417fn decode(cursor: &mut Cursor<&[u8]>, container: &mut Vec<TlvItem>) -> Result<()> {
418    while cursor.position() < cursor.get_ref().len() as u64 {
419        let fb = cursor.read_u8()?;
420        let tp = fb & 0x1f;
421        let tagctrl = fb >> 5;
422        let tag = read_tag(tagctrl, cursor)?;
423        match tp {
424            TYPE_INT_1 => {
425                let value = cursor.read_u8()?;
426                let item = TlvItem {
427                    tag,
428                    value: TlvItemValue::Int(value as u64),
429                };
430                container.push(item);
431            }
432            TYPE_INT_2 => {
433                let value = cursor.read_i16::<LittleEndian>()?;
434                let item = TlvItem {
435                    tag,
436                    value: TlvItemValue::Int(value as u64),
437                };
438                container.push(item);
439            }
440            TYPE_INT_4 => {
441                let value = cursor.read_i32::<LittleEndian>()?;
442                let item = TlvItem {
443                    tag,
444                    value: TlvItemValue::Int(value as u64),
445                };
446                container.push(item);
447            }
448            TYPE_INT_8 => {
449                let value = cursor.read_i64::<LittleEndian>()?;
450                let item = TlvItem {
451                    tag,
452                    value: TlvItemValue::Int(value as u64),
453                };
454                container.push(item);
455            }
456            TYPE_UINT_1 => {
457                let value = cursor.read_u8()?;
458                let item = TlvItem {
459                    tag,
460                    value: TlvItemValue::Int(value as u64),
461                };
462                container.push(item);
463            }
464            TYPE_UINT_2 => {
465                let value = cursor.read_u16::<LittleEndian>()?;
466                let item = TlvItem {
467                    tag,
468                    value: TlvItemValue::Int(value as u64),
469                };
470                container.push(item);
471            }
472            TYPE_UINT_4 => {
473                let value = cursor.read_u32::<LittleEndian>()?;
474                let item = TlvItem {
475                    tag,
476                    value: TlvItemValue::Int(value as u64),
477                };
478                container.push(item);
479            }
480            TYPE_UINT_8 => {
481                let value = cursor.read_u64::<LittleEndian>()?;
482                let item = TlvItem {
483                    tag,
484                    value: TlvItemValue::Int(value),
485                };
486                container.push(item);
487            }
488            TYPE_BOOL_FALSE => {
489                let item = TlvItem {
490                    tag,
491                    value: TlvItemValue::Bool(false),
492                };
493                container.push(item);
494            }
495            TYPE_BOOL_TRUE => {
496                let item = TlvItem {
497                    tag,
498                    value: TlvItemValue::Bool(true),
499                };
500                container.push(item);
501            }
502            TYPE_FLOAT_4 => {
503                let value = cursor.read_f32::<LittleEndian>()?;
504                let item = TlvItem {
505                    tag,
506                    value: TlvItemValue::Float(value as f64),
507                };
508                container.push(item);
509            }
510            TYPE_FLOAT_8 => {
511                let value = cursor.read_f64::<LittleEndian>()?;
512                let item = TlvItem {
513                    tag,
514                    value: TlvItemValue::Float(value),
515                };
516                container.push(item);
517            }
518            TYPE_UTF8_L1 => {
519                // utf8 string
520                let size = cursor.read_u8()?;
521                let mut value = vec![0; size as usize];
522                cursor.read_exact(&mut value)?;
523                let str = String::from_utf8(value);
524                let typ = match str {
525                    Ok(s) => TlvItemValue::String(s),
526                    Err(_) => TlvItemValue::Invalid(),
527                };
528                let item = TlvItem { tag, value: typ };
529                container.push(item);
530            }
531            TYPE_OCTET_STRING_L1 => {
532                // octet string
533                let size = cursor.read_u8()?;
534                let mut value = vec![0; size as usize];
535                cursor.read_exact(&mut value)?;
536                let item = TlvItem {
537                    tag,
538                    value: TlvItemValue::OctetString(value),
539                };
540                container.push(item);
541            }
542            TYPE_OCTET_STRING_L2 => {
543                // octet string large
544                let size = cursor.read_u16::<LittleEndian>()?;
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_L4 => {
554                // octet string very large
555                let size = cursor.read_u32::<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_L8 => {
565                // octet string very very xtra large
566                let size = cursor.read_u64::<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_STRUCT => {
576                //list
577                let mut c2 = Vec::new();
578                decode(cursor, &mut c2)?;
579                let item = TlvItem {
580                    tag,
581                    value: TlvItemValue::List(c2),
582                };
583                container.push(item);
584            }
585            TYPE_ARRAY => {
586                //list
587                let mut c2 = Vec::new();
588                decode(cursor, &mut c2)?;
589                let item = TlvItem {
590                    tag,
591                    value: TlvItemValue::List(c2),
592                };
593                container.push(item);
594            }
595            TYPE_LIST => {
596                //list
597                let mut c2 = Vec::new();
598                decode(cursor, &mut c2)?;
599                let item = TlvItem {
600                    tag,
601                    value: TlvItemValue::List(c2),
602                };
603                container.push(item);
604            }
605            TYPE_END_CONTAINER => return Ok(()),
606            0x14 => {
607                let item = TlvItem {
608                    tag,
609                    value: TlvItemValue::Nil(),
610                };
611                container.push(item);
612            }
613            _ => {
614                return Err(std::io::Error::new(
615                    std::io::ErrorKind::InvalidData,
616                    format!("unknown tlv type 0x{:x}", tp),
617                ))
618            }
619        }
620    }
621    Ok(())
622}
623
624/// decode raw buffer with tlv data
625pub fn decode_tlv(data: &[u8]) -> Result<TlvItem> {
626    let mut container = Vec::new();
627    let mut cursor = std::io::Cursor::new(data);
628    decode(&mut cursor, &mut container)?;
629    if container.len() == 1 {
630        if let Some(i) = container.pop() {
631            Ok(i)
632        } else {
633            Err(std::io::Error::new(
634                std::io::ErrorKind::InvalidData,
635                "no data found",
636            ))
637        }
638    } else {
639        Ok(TlvItem {
640            tag: 0,
641            value: TlvItemValue::List(container),
642        })
643    }
644}
645
646#[derive(Debug)]
647pub enum TlvItemValueEnc {
648    Int8(i8),
649    Int16(i16),
650    Int32(i32),
651    Int64(i64),
652    UInt8(u8),
653    UInt8Anonymous(u8),
654    UInt16(u16),
655    UInt32(u32),
656    UInt64(u64),
657    Bool(bool),
658    String(String),
659    OctetString(Vec<u8>),
660    StructAnon(Vec<TlvItemEnc>),
661    StructInvisible(Vec<TlvItemEnc>),
662    Struct(Vec<TlvItemEnc>),
663    List(Vec<TlvItemEnc>),
664    Array(Vec<TlvItemEnc>),
665    Invalid(),
666}
667
668/// Structure used for document style encoding.
669///
670/// ```
671/// # use matc::tlv;
672/// let t1 = tlv::TlvItemEnc {
673///   tag: 0,
674///   value: tlv::TlvItemValueEnc::StructAnon(vec![
675///     tlv::TlvItemEnc { tag: 0, value: tlv::TlvItemValueEnc::UInt8(6) },
676///     tlv::TlvItemEnc { tag: 1, value: tlv::TlvItemValueEnc::UInt8(7) }
677///   ]),
678/// };
679/// let o = t1.encode().unwrap();
680/// ```
681#[derive(Debug)]
682pub struct TlvItemEnc {
683    pub tag: u8,
684    pub value: TlvItemValueEnc,
685}
686
687impl From<(u8, TlvItemValueEnc)> for TlvItemEnc {
688    fn from(item: (u8, TlvItemValueEnc)) -> Self {
689        TlvItemEnc {
690            tag: item.0,
691            value: item.1,
692        }
693    }
694}
695
696impl TlvItemEnc {
697    fn encode_internal(&self, buf: &mut TlvBuffer) -> Result<()> {
698        match &self.value {
699            TlvItemValueEnc::Int8(i) => {
700                buf.write_int8(self.tag, *i)?;
701            }
702            TlvItemValueEnc::Int16(i) => {
703                buf.write_int16(self.tag, *i)?;
704            }
705            TlvItemValueEnc::Int32(i) => {
706                buf.write_int32(self.tag, *i)?;
707            }
708            TlvItemValueEnc::Int64(i) => {
709                buf.write_int64(self.tag, *i)?;
710            }
711            TlvItemValueEnc::UInt8(i) => {
712                buf.write_uint8(self.tag, *i)?;
713            }
714            TlvItemValueEnc::UInt8Anonymous(i) => {
715                buf.write_uint8_notag(*i)?;
716            }
717            TlvItemValueEnc::UInt16(i) => {
718                buf.write_uint16(self.tag, *i)?;
719            }
720            TlvItemValueEnc::UInt32(i) => {
721                buf.write_uint32(self.tag, *i)?;
722            }
723            TlvItemValueEnc::UInt64(i) => {
724                buf.write_uint64(self.tag, *i)?;
725            }
726            TlvItemValueEnc::Bool(v) => {
727                buf.write_bool(self.tag, *v)?;
728            }
729            TlvItemValueEnc::String(s) => {
730                buf.write_string(self.tag, s)?;
731            }
732            TlvItemValueEnc::OctetString(vec) => {
733                buf.write_octetstring(self.tag, vec)?;
734            }
735            TlvItemValueEnc::StructAnon(vec) => {
736                buf.write_anon_struct()?;
737                for i in vec {
738                    i.encode_internal(buf)?;
739                }
740                buf.write_struct_end()?;
741            }
742            TlvItemValueEnc::Struct(vec) => {
743                buf.write_struct(self.tag)?;
744                for i in vec {
745                    i.encode_internal(buf)?;
746                }
747                buf.write_struct_end()?;
748            }
749            TlvItemValueEnc::List(vec) => {
750                buf.write_list(self.tag)?;
751                for i in vec {
752                    i.encode_internal(buf)?;
753                }
754                buf.write_struct_end()?;
755            }
756            TlvItemValueEnc::Array(vec) => {
757                buf.write_array(self.tag)?;
758                for i in vec {
759                    i.encode_internal(buf)?;
760                }
761                buf.write_struct_end()?;
762            }
763            TlvItemValueEnc::StructInvisible(vec) => {
764                for i in vec {
765                    i.encode_internal(buf)?;
766                }
767            }
768            TlvItemValueEnc::Invalid() => todo!(),
769        }
770        Ok(())
771    }
772
773    pub fn encode(&self) -> Result<Vec<u8>> {
774        let mut tlv = TlvBuffer::new();
775        self.encode_internal(&mut tlv)?;
776        Ok(tlv.data)
777    }
778}
779
780#[cfg(test)]
781mod tests {
782    use super::{decode_tlv, TlvBuffer, TlvItemEnc, TlvItemValue, TlvItemValueEnc};
783
784    #[test]
785    fn test_1() {
786        let t1 = TlvItemEnc {
787            tag: 0,
788            value: TlvItemValueEnc::StructAnon(vec![
789                TlvItemEnc {
790                    tag: 0,
791                    value: TlvItemValueEnc::UInt8(6),
792                },
793                TlvItemEnc {
794                    tag: 1,
795                    value: TlvItemValueEnc::UInt8(7),
796                },
797            ]),
798        };
799        let o = t1.encode().unwrap();
800        assert_eq!(hex::encode(o), "1524000624010718");
801
802        let mut tlv = TlvBuffer::new();
803        tlv.write_anon_struct().unwrap();
804        tlv.write_octetstring(0x1, &[1, 2, 3]).unwrap();
805        tlv.write_struct_end().unwrap();
806        assert_eq!(hex::encode(tlv.data), "1530010301020318");
807
808        let t1 = TlvItemEnc {
809            tag: 0,
810            value: TlvItemValueEnc::StructAnon(vec![TlvItemEnc {
811                tag: 1,
812                value: TlvItemValueEnc::OctetString(vec![1, 2, 3]),
813            }]),
814        }
815        .encode()
816        .unwrap();
817        assert_eq!(hex::encode(t1), "1530010301020318");
818    }
819
820    #[test]
821    fn test_decode_integers() {
822        // Test uint8
823        let mut tlv = TlvBuffer::new();
824        tlv.write_uint8(1, 42).unwrap();
825        let decoded = decode_tlv(&tlv.data).unwrap();
826        assert_eq!(decoded.get_u8(&[]), Some(42));
827
828        // Test uint16
829        let mut tlv = TlvBuffer::new();
830        tlv.write_uint16(2, 1000).unwrap();
831        let decoded = decode_tlv(&tlv.data).unwrap();
832        assert_eq!(decoded.get_u16(&[]), Some(1000));
833
834        // Test uint32
835        let mut tlv = TlvBuffer::new();
836        tlv.write_uint32(3, 100000).unwrap();
837        let decoded = decode_tlv(&tlv.data).unwrap();
838        assert_eq!(decoded.get_u32(&[]), Some(100000));
839
840        // Test uint64
841        let mut tlv = TlvBuffer::new();
842        tlv.write_uint64(4, 1000000000000).unwrap();
843        let decoded = decode_tlv(&tlv.data).unwrap();
844        assert_eq!(decoded.get_u64(&[]), Some(1000000000000));
845    }
846
847    #[test]
848    fn test_decode_booleans() {
849        // Test true
850        let mut tlv = TlvBuffer::new();
851        tlv.write_bool(1, true).unwrap();
852        let decoded = decode_tlv(&tlv.data).unwrap();
853        assert_eq!(decoded.get_bool(&[]), Some(true));
854
855        // Test false
856        let mut tlv = TlvBuffer::new();
857        tlv.write_bool(2, false).unwrap();
858        let decoded = decode_tlv(&tlv.data).unwrap();
859        assert_eq!(decoded.get_bool(&[]), Some(false));
860        assert_eq!(decoded.get_t(&[]), Some(false));
861    }
862
863    #[test]
864    fn test_decode_strings() {
865        let mut tlv = TlvBuffer::new();
866        tlv.write_string(1, "hello world").unwrap();
867        let decoded = decode_tlv(&tlv.data).unwrap();
868        assert_eq!(
869            decoded.get_string_owned(&[]),
870            Some("hello world".to_string())
871        );
872        assert_eq!(decoded.get_t(&[]), Some("hello world".to_string()));
873    }
874
875    #[test]
876    fn test_decode_octet_strings() {
877        // Test small octet string (L1)
878        let mut tlv = TlvBuffer::new();
879        let data = vec![1, 2, 3, 4, 5];
880        tlv.write_octetstring(1, &data).unwrap();
881        let decoded = decode_tlv(&tlv.data).unwrap();
882        assert_eq!(decoded.get_octet_string(&[]), Some(data.as_slice()));
883
884        // Test large octet string (L2)
885        let mut tlv = TlvBuffer::new();
886        let large_data = vec![0; 300]; // Larger than 255 bytes
887        tlv.write_octetstring(2, &large_data).unwrap();
888        let decoded = decode_tlv(&tlv.data).unwrap();
889        assert_eq!(decoded.get_octet_string(&[]), Some(large_data.as_slice()));
890        assert_eq!(
891            decoded.get_octet_string_owned(&[]),
892            Some(large_data.clone())
893        );
894    }
895
896    #[test]
897    fn test_decode_structures() {
898        let mut tlv = TlvBuffer::new();
899        tlv.write_struct(1).unwrap();
900        tlv.write_uint8(0, 100).unwrap();
901        tlv.write_string(1, "test").unwrap();
902        tlv.write_bool(2, true).unwrap();
903        tlv.write_struct_end().unwrap();
904
905        let decoded = decode_tlv(&tlv.data).unwrap();
906
907        // Test nested access
908        assert_eq!(decoded.get_u8(&[0]), Some(100));
909        assert_eq!(decoded.get_string_owned(&[1]), Some("test".to_string()));
910        assert_eq!(decoded.get_bool(&[2]), Some(true));
911
912        // Verify it's a list structure
913        if let TlvItemValue::List(items) = &decoded.value {
914            assert_eq!(items.len(), 3);
915        }
916    }
917
918    #[test]
919    fn test_decode_anonymous_structures() {
920        let mut tlv = TlvBuffer::new();
921        tlv.write_anon_struct().unwrap();
922        tlv.write_uint8_notag(42).unwrap();
923        tlv.write_uint8_notag(84).unwrap();
924        tlv.write_struct_end().unwrap();
925
926        let decoded = decode_tlv(&tlv.data).unwrap();
927
928        if let TlvItemValue::List(items) = &decoded.value {
929            assert_eq!(items.len(), 2);
930            assert_eq!(items[0].tag, 0);
931            assert_eq!(items[1].tag, 0);
932        }
933    }
934
935    #[test]
936    fn test_decode_arrays_and_lists() {
937        // Test array
938        let mut tlv = TlvBuffer::new();
939        tlv.write_array(1).unwrap();
940        tlv.write_uint8(0, 1).unwrap();
941        tlv.write_uint8(0, 2).unwrap();
942        tlv.write_uint8(0, 3).unwrap();
943        tlv.write_struct_end().unwrap();
944
945        let decoded = decode_tlv(&tlv.data).unwrap();
946        if let Some(TlvItemValue::List(items)) = decoded.get(&[]) {
947            assert_eq!(items.len(), 3);
948            assert_eq!(items[0].get_u8(&[]), Some(1));
949            assert_eq!(items[1].get_u8(&[]), Some(2));
950            assert_eq!(items[2].get_u8(&[]), Some(3));
951        } else {
952            panic!("Expected array structure");
953        }
954
955        // Test list
956        let mut tlv = TlvBuffer::new();
957        tlv.write_list(2).unwrap();
958        tlv.write_string(0, "item1").unwrap();
959        tlv.write_string(1, "item2").unwrap();
960        tlv.write_struct_end().unwrap();
961
962        let decoded = decode_tlv(&tlv.data).unwrap();
963        if let Some(TlvItemValue::List(items)) = decoded.get(&[]) {
964            assert_eq!(items.len(), 2);
965            assert_eq!(items[0].get_string_owned(&[]), Some("item1".to_string()));
966            assert_eq!(items[1].get_string_owned(&[]), Some("item2".to_string()));
967        } else {
968            panic!("Expected list structure");
969        }
970    }
971
972    #[test]
973    fn test_decode_mixed_container() {
974        let mut tlv = TlvBuffer::new();
975        tlv.write_uint8(0, 255).unwrap();
976        tlv.write_string(1, "mixed").unwrap();
977        tlv.write_bool(2, false).unwrap();
978
979        let decoded = decode_tlv(&tlv.data).unwrap();
980
981        // Should create a list with multiple items
982        if let TlvItemValue::List(items) = &decoded.value {
983            assert_eq!(items.len(), 3);
984            assert_eq!(items[0].get_u8(&[]), Some(255));
985            assert_eq!(items[1].get_string_owned(&[]), Some("mixed".to_string()));
986            assert_eq!(items[2].get_bool(&[]), Some(false));
987        } else {
988            panic!("Expected list of items");
989        }
990    }
991
992    #[test]
993    fn test_decode_nested_structures() {
994        let mut tlv = TlvBuffer::new();
995        tlv.write_struct(1).unwrap();
996        tlv.write_struct(2).unwrap();
997        tlv.write_uint8(3, 42).unwrap();
998        tlv.write_struct_end().unwrap(); // End inner struct
999        tlv.write_string(4, "outer").unwrap();
1000        tlv.write_struct_end().unwrap(); // End outer struct
1001
1002        let decoded = decode_tlv(&tlv.data).unwrap();
1003
1004        // Test deep nested access
1005        assert_eq!(decoded.get_u8(&[2, 3]), Some(42));
1006        assert_eq!(decoded.get_string_owned(&[4]), Some("outer".to_string()));
1007    }
1008
1009    #[test]
1010    fn test_decode_getter_methods() {
1011        let mut tlv = TlvBuffer::new();
1012        tlv.write_struct(0).unwrap();
1013        tlv.write_uint64(1, 0xFFFFFFFFFFFFFFFF).unwrap();
1014        tlv.write_uint32(2, 0xFFFFFFFF).unwrap();
1015        tlv.write_uint16(3, 0xFFFF).unwrap();
1016        tlv.write_uint8(4, 0xFF).unwrap();
1017        tlv.write_struct_end().unwrap();
1018
1019        let decoded = decode_tlv(&tlv.data).unwrap();
1020
1021        // Test type conversions
1022        assert_eq!(decoded.get_u64(&[1]), Some(0xFFFFFFFFFFFFFFFF));
1023        assert_eq!(decoded.get_u32(&[2]), Some(0xFFFFFFFF));
1024        assert_eq!(decoded.get_u16(&[3]), Some(0xFFFF));
1025        assert_eq!(decoded.get_u8(&[4]), Some(0xFF));
1026
1027        // Test downcasting
1028        assert_eq!(decoded.get_u8(&[1]), Some(0xFF)); // u64 -> u8
1029        assert_eq!(decoded.get_u16(&[1]), Some(0xFFFF)); // u64 -> u16
1030    }
1031
1032    #[test]
1033    fn test_decode_invalid_access() {
1034        let mut tlv = TlvBuffer::new();
1035        tlv.write_uint8(1, 42).unwrap();
1036        let decoded = decode_tlv(&tlv.data).unwrap();
1037
1038        // Test accessing non-existent tags
1039        assert_eq!(decoded.get_u8(&[99]), None);
1040        assert_eq!(decoded.get_string_owned(&[1]), None); // Wrong type
1041        assert_eq!(decoded.get_bool(&[1]), None); // Wrong type
1042    }
1043
1044    #[test]
1045    fn test_decode_empty_structure() {
1046        let mut tlv = TlvBuffer::new();
1047        tlv.write_anon_struct().unwrap();
1048        tlv.write_struct_end().unwrap();
1049
1050        let decoded = decode_tlv(&tlv.data).unwrap();
1051
1052        if let TlvItemValue::List(items) = &decoded.value {
1053            assert_eq!(items.len(), 0);
1054        } else {
1055            panic!("Expected empty list");
1056        }
1057    }
1058
1059    #[test]
1060    fn test_get_item_method() {
1061        let mut tlv = TlvBuffer::new();
1062        tlv.write_struct(1).unwrap();
1063        tlv.write_uint8(2, 100).unwrap();
1064        tlv.write_string(3, "test").unwrap();
1065        tlv.write_bool(4, true).unwrap();
1066        tlv.write_struct(5).unwrap();
1067        tlv.write_string(1, "inner").unwrap();
1068        tlv.write_struct_end().unwrap();
1069        tlv.write_struct_end().unwrap();
1070
1071        let decoded = decode_tlv(&tlv.data).unwrap();
1072
1073        // Test get_item returns the actual item
1074        let item = decoded.get_item(&[2]).unwrap();
1075        assert_eq!(item.tag, 2);
1076        if let TlvItemValue::Int(val) = &item.value {
1077            assert_eq!(*val, 100);
1078        } else {
1079            panic!("Expected Int value");
1080        }
1081        let item = decoded.get_item(&[3]).unwrap();
1082        assert_eq!(item.tag, 3);
1083        if let TlvItemValue::String(val) = &item.value {
1084            assert_eq!(*val, "test");
1085        } else {
1086            panic!("Expected String value");
1087        }
1088        let item = decoded.get_item(&[4]).unwrap();
1089        assert_eq!(item.tag, 4);
1090        if let TlvItemValue::Bool(val) = &item.value {
1091            assert!(*val);
1092        } else {
1093            panic!("Expected Bool value");
1094        }
1095        let item = decoded.get_item(&[5]).unwrap();
1096        assert_eq!(item.tag, 5);
1097        if let TlvItemValue::List(items) = &item.value {
1098            assert_eq!(items.len(), 1);
1099            let inner_item = &items[0];
1100            assert_eq!(inner_item.tag, 1);
1101            if let TlvItemValue::String(val) = &inner_item.value {
1102                assert_eq!(*val, "inner");
1103            } else {
1104                panic!("Expected String value");
1105            }
1106        } else {
1107            panic!("Expected List value");
1108        }
1109        let item = decoded.get_item(&[99]);
1110        assert!(item.is_none());
1111    }
1112}