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