1use crate::error::{Result, Tlv8Error};
10
11pub struct Tlv8Reader;
13
14impl Tlv8Reader {
15 pub fn parse(bytes: &[u8]) -> Result<Vec<(u8, Vec<u8>)>> {
28 let mut items: Vec<(u8, Vec<u8>)> = Vec::new();
29 let mut open_run: Option<(u8, bool)> = None;
32 let mut pos = 0;
33 while pos < bytes.len() {
34 let ty = bytes[pos];
35 let len = *bytes.get(pos + 1).ok_or(Tlv8Error::UnexpectedEof)? as usize;
36 let start = pos + 2;
37 let end = start.checked_add(len).ok_or(Tlv8Error::UnexpectedEof)?;
38 let value = bytes.get(start..end).ok_or(Tlv8Error::UnexpectedEof)?;
39 pos = end;
40
41 if ty == crate::SEPARATOR {
44 open_run = None;
45 items.push((ty, value.to_vec()));
46 continue;
47 }
48
49 let continues = matches!(open_run, Some((run_ty, true)) if run_ty == ty);
50 if continues {
51 if let Some(last) = items.last_mut() {
53 last.1.extend_from_slice(value);
54 }
55 } else {
56 items.push((ty, value.to_vec()));
57 }
58 open_run = Some((ty, len == 255));
60 }
61 Ok(items)
62 }
63}
64
65#[cfg(test)]
66#[allow(clippy::unwrap_used, clippy::expect_used)]
68mod tests {
69 use super::*;
70
71 #[test]
72 fn parse_empty_input_yields_no_items() {
73 assert_eq!(Tlv8Reader::parse(&[]).unwrap(), vec![]);
74 }
75
76 #[test]
77 fn parse_single_short_item() {
78 let items = Tlv8Reader::parse(&[0x01, 0x02, 0xAB, 0xCD]).unwrap();
79 assert_eq!(items, vec![(0x01, vec![0xAB, 0xCD])]);
80 }
81
82 #[test]
83 fn parse_zero_length_item() {
84 let items = Tlv8Reader::parse(&[0x06, 0x00]).unwrap();
85 assert_eq!(items, vec![(0x06, vec![])]);
86 }
87
88 #[test]
89 fn parse_two_distinct_types() {
90 let items = Tlv8Reader::parse(&[0x01, 0x01, 0xAA, 0x02, 0x01, 0xBB]).unwrap();
91 assert_eq!(items, vec![(0x01, vec![0xAA]), (0x02, vec![0xBB])]);
92 }
93
94 #[test]
95 fn parse_truncated_value_errors() {
96 let err = Tlv8Reader::parse(&[0x01, 0x02, 0xAA]).unwrap_err();
98 assert_eq!(err, Tlv8Error::UnexpectedEof);
99 }
100
101 #[test]
102 fn parse_missing_length_byte_errors() {
103 let err = Tlv8Reader::parse(&[0x01]).unwrap_err();
104 assert_eq!(err, Tlv8Error::UnexpectedEof);
105 }
106
107 #[test]
108 fn parse_reassembles_256_byte_value() {
109 let mut stream = vec![0x09, 0xFF];
111 stream.extend((0u8..=254).collect::<Vec<u8>>()); stream.extend([0x09, 0x01, 0xFF]); let items = Tlv8Reader::parse(&stream).unwrap();
114 assert_eq!(items.len(), 1);
115 assert_eq!(items[0].0, 0x09);
116 assert_eq!(items[0].1.len(), 256);
117 assert_eq!(items[0].1, (0..=u8::MAX).collect::<Vec<u8>>());
118 }
119
120 #[test]
121 fn parse_reassembles_exact_255_with_terminator() {
122 let mut stream = vec![0x09, 0xFF];
123 stream.extend(vec![0x42_u8; 255]);
124 stream.extend([0x09, 0x00]); let items = Tlv8Reader::parse(&stream).unwrap();
126 assert_eq!(items.len(), 1);
127 assert_eq!(items[0].0, 0x09);
128 assert_eq!(items[0].1, vec![0x42; 255]);
129 }
130
131 #[test]
132 fn parse_reassembles_510_byte_value() {
133 let mut stream = vec![0x09, 0xFF];
134 stream.extend(vec![0xAB_u8; 255]);
135 stream.extend([0x09, 0xFF]);
136 stream.extend(vec![0xAB_u8; 255]);
137 stream.extend([0x09, 0x00]); let items = Tlv8Reader::parse(&stream).unwrap();
139 assert_eq!(items.len(), 1);
140 assert_eq!(items[0].1, vec![0xAB; 510]);
141 }
142
143 #[test]
144 fn parse_does_not_merge_two_short_items_of_same_type() {
145 let items = Tlv8Reader::parse(&[0x09, 0x01, 0xAA, 0x09, 0x01, 0xBB]).unwrap();
148 assert_eq!(items, vec![(0x09, vec![0xAA]), (0x09, vec![0xBB])]);
149 }
150
151 #[test]
152 fn parse_keeps_separator_as_distinct_item() {
153 let stream = [0x01, 0x01, 0xAA, 0xFF, 0x00, 0x01, 0x01, 0xBB];
155 let items = Tlv8Reader::parse(&stream).unwrap();
156 assert_eq!(
157 items,
158 vec![(0x01, vec![0xAA]), (0xFF, vec![]), (0x01, vec![0xBB])]
159 );
160 }
161}