1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
use std::io::{Write, Read};
use crate::XResult;

pub struct Tlv {
    pub r#type: u16,
    pub length: u32,
    pub value: Vec<u8>,
}

impl Tlv {
    pub fn new_empty(ty: u16) -> Self {
        Self {
            r#type: ty,
            length: 0,
            value: vec![],
        }
    }

    pub fn new(ty: u16, value: Vec<u8>) -> Self {
        assert!(value.len() < u32::MAX as usize, "Value too huge");
        Self {
            r#type: ty,
            length: value.len() as u32,
            value,
        }
    }

    pub fn compose(&self) -> Vec<u8> {
        let cap = self.value.len() + 4 + 2;
        let mut v = Vec::with_capacity(cap);
        v.extend_from_slice(&self.r#type.to_be_bytes());
        v.extend_from_slice(&self.length.to_be_bytes());
        v.extend_from_slice(self.value.as_slice());
        v
    }

    pub fn write<T>(&self, mut w: T) -> XResult<usize> where T: Write {
        let mut len = w.write(&self.r#type.to_be_bytes())?;
        len += w.write(&self.length.to_be_bytes())?;
        len += w.write(self.value.as_slice())?;
        Ok(len)
    }

    pub fn read<T>(mut r: T) -> XResult<Self> where T: Read {
        let mut r#type = [0_u8; 2];
        r.read_exact(&mut r#type)?;
        let mut length = [0_u8; 4];
        r.read_exact(&mut length)?;
        let len = u32::from_be_bytes(length);
        let mut value = vec![0_u8; len as usize];
        r.read_exact(&mut value)?;
        Ok(Self {
            r#type: u16::from_be_bytes(r#type),
            length: len,
            value,
        })
    }
}

#[test]
fn test_tlv() {
    {
        let tlv = Tlv::new_empty(0);
        assert_eq!([0, 0, 0, 0, 0, 0], tlv.compose().as_slice());
    }
    {
        let tlv = Tlv::new_empty(1);
        assert_eq!([0, 1, 0, 0, 0, 0], tlv.compose().as_slice());
    }
    {
        let tlv = Tlv::new_empty(256);
        assert_eq!([1, 0, 0, 0, 0, 0], tlv.compose().as_slice());
    }
    {
        let tlv = Tlv::new(1, vec![0]);
        assert_eq!([0, 1, 0, 0, 0, 1, 0], tlv.compose().as_slice());
    }
    {
        let tlv = Tlv::new(2, vec![1, 2]);
        assert_eq!([0, 2, 0, 0, 0, 2, 1, 2], tlv.compose().as_slice());
    }
    {
        let tlv = Tlv::new(2, vec![1, 2]);
        let bs = tlv.compose().clone();
        let tlv2 = Tlv::read(bs.as_slice()).unwrap();
        assert_eq!(bs, tlv2.compose());
        assert_eq!(2, tlv2.r#type);
        assert_eq!(2, tlv2.length);
        assert_eq!([1, 2], tlv2.value.as_slice());
    }
}