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
extern crate byteorder;
use std::io::Read;
use std::io::Write;
use std::collections::HashMap;
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};


fn as_aligned(i: u16) -> u16 {
    let remainder = i % 4;
    if remainder == 0 {
        i
    } else {
        4 - remainder
    }
}

pub fn encode(hm: &HashMap<u16, String>) -> Vec<u8> {
    // each entry has at least 2 bytes
    let vec = Vec::with_capacity(hm.len() * 2);
    let mut buf = std::io::BufWriter::new(vec);
    for (k, v) in hm.iter() {
        // unwrap is fine since we're writing to an in-memory vector
        buf.write_u16::<BigEndian>(*k).unwrap();
        let write_length = v.len() as u16;
        buf.write_u16::<BigEndian>(write_length).unwrap();
        buf.write(v.as_bytes()).unwrap();
        let align = as_aligned(write_length);
        if align != 0 {
            buf.write(vec![0; align as usize].as_slice()).unwrap();
        }
    };
    buf.into_inner().unwrap()
}

pub fn decode<T: std::io::BufRead>(mut buf: &mut T) -> Result<HashMap<u16, String>, std::io::Error> {
    let mut attrs = HashMap::new();
    while let Ok(attr_type) = buf.read_u16::<BigEndian>() {
        let length = try!(buf.read_u16::<BigEndian>());
        let align = as_aligned(length);
        {
            let mut value_rdr = buf.take(length as u64);
            let mut value_vec = &mut Vec::with_capacity(length as usize);
            try!(value_rdr.read_to_end(value_vec));
            attrs.insert(attr_type, String::from_utf8(value_vec.to_owned()).expect("Invalid UTF8"));
        };
        buf.consume(align as usize);
    }
    Ok(attrs)
}


#[cfg(test)]
mod tests {

    use super::*;
    use std::io::Cursor;
    use std::collections::HashMap;

    #[test]
    fn test_decode_tlv() {
        let attrs_raw = vec![0, 6, 0, 5, 72, 101, 108, 108, 111, 0, 0, 0, 0, 6, 0, 5, 72, 101, 108, 108, 111, 0, 0, 0];
        let rdr = &mut Cursor::new(attrs_raw);
        match decode(rdr) {
            Ok(m) => {
                assert_eq!(m.len(), 1);
                match m.get(&6) {
                    Some(v) => assert_eq!(v.to_string(), "Hello".to_string()),
                    None => assert_eq!(false, true)
                }
            },
            Err(err) =>
                println!("{:?}:", err)
        }
    }

    #[test]
    fn test_encode_tlv() {
        let attrs_raw = vec![0, 6, 0, 5, 72, 101, 108, 108, 111, 0, 0, 0];
        let mut hm = HashMap::new();
        hm.insert(6 as u16, "Hello".to_string());
        assert_eq!(encode(&hm), attrs_raw);
    }

    #[test]
    fn test_encode_decode_tlv() {
        let mut hm = HashMap::new();
        hm.insert(6 as u16, "Hello".to_string());
        let encoded = &mut Cursor::new(encode(&hm));
        assert_eq!(hm, decode(encoded).unwrap());
    }
}