ndn_tlv/
reader.rs

1use bytes::Bytes;
2
3use crate::{TlvError, read_varu64};
4
5/// Zero-copy TLV reader over a `Bytes` buffer.
6///
7/// Every slice returned by this reader is a sub-slice of the original `Bytes`,
8/// sharing the same reference-counted allocation — no copies.
9pub struct TlvReader {
10    buf: Bytes,
11    pos: usize,
12}
13
14impl TlvReader {
15    pub fn new(buf: Bytes) -> Self {
16        Self { buf, pos: 0 }
17    }
18
19    pub fn remaining(&self) -> usize {
20        self.buf.len() - self.pos
21    }
22
23    pub fn is_empty(&self) -> bool {
24        self.pos >= self.buf.len()
25    }
26
27    /// Current byte position within the original buffer.
28    pub fn position(&self) -> usize {
29        self.pos
30    }
31
32    /// Read the next TLV type code.
33    pub fn read_type(&mut self) -> Result<u64, TlvError> {
34        let (v, n) = read_varu64(&self.buf[self.pos..])?;
35        self.pos += n;
36        Ok(v)
37    }
38
39    /// Read the next TLV length field.
40    pub fn read_length(&mut self) -> Result<usize, TlvError> {
41        let (v, n) = read_varu64(&self.buf[self.pos..])?;
42        self.pos += n;
43        Ok(v as usize)
44    }
45
46    /// Read exactly `len` bytes as a zero-copy `Bytes` slice.
47    pub fn read_bytes(&mut self, len: usize) -> Result<Bytes, TlvError> {
48        if self.pos + len > self.buf.len() {
49            return Err(TlvError::UnexpectedEof);
50        }
51        let slice = self.buf.slice(self.pos..self.pos + len);
52        self.pos += len;
53        Ok(slice)
54    }
55
56    /// Read a complete TLV element: returns `(type, value_bytes)`.
57    pub fn read_tlv(&mut self) -> Result<(u64, Bytes), TlvError> {
58        let typ = self.read_type()?;
59        let len = self.read_length()?;
60        let val = self.read_bytes(len)?;
61        Ok((typ, val))
62    }
63
64    /// Peek at the next TLV type without advancing the position.
65    pub fn peek_type(&self) -> Result<u64, TlvError> {
66        let (v, _) = read_varu64(&self.buf[self.pos..])?;
67        Ok(v)
68    }
69
70    /// Skip an unknown TLV element, respecting the critical-bit rule.
71    ///
72    /// Types 0–31 are always critical (grandfathered, NDN Packet Format v0.3
73    /// §1.3). For types >= 32, odd numbers are critical and even are
74    /// non-critical.
75    pub fn skip_unknown(&mut self, typ: u64) -> Result<(), TlvError> {
76        if typ <= 31 || typ & 1 == 1 {
77            return Err(TlvError::UnknownCriticalType(typ));
78        }
79        let len = self.read_length()?;
80        if self.pos + len > self.buf.len() {
81            return Err(TlvError::UnexpectedEof);
82        }
83        self.pos += len;
84        Ok(())
85    }
86
87    /// Return a sub-reader scoped to `len` bytes from the current position.
88    pub fn scoped(&mut self, len: usize) -> Result<TlvReader, TlvError> {
89        let slice = self.read_bytes(len)?;
90        Ok(TlvReader::new(slice))
91    }
92
93    /// Return the full remaining buffer as a `Bytes` slice without advancing.
94    pub fn as_bytes(&self) -> Bytes {
95        self.buf.slice(self.pos..)
96    }
97}
98
99#[cfg(test)]
100mod tests {
101    use super::*;
102
103    fn make_tlv(typ: u8, value: &[u8]) -> Bytes {
104        let mut v = vec![typ, value.len() as u8];
105        v.extend_from_slice(value);
106        Bytes::from(v)
107    }
108
109    // ── basic read_tlv ─────────────────────────────────────────────────────────
110
111    #[test]
112    fn read_tlv_basic() {
113        let raw = make_tlv(0x08, b"hello");
114        let mut r = TlvReader::new(raw);
115        let (typ, val) = r.read_tlv().unwrap();
116        assert_eq!(typ, 0x08);
117        assert_eq!(val.as_ref(), b"hello");
118        assert!(r.is_empty());
119    }
120
121    #[test]
122    fn read_tlv_zero_length_value() {
123        let raw = Bytes::from(vec![0x21, 0x00]); // CAN_BE_PREFIX with empty value
124        let mut r = TlvReader::new(raw);
125        let (typ, val) = r.read_tlv().unwrap();
126        assert_eq!(typ, 0x21);
127        assert_eq!(val.len(), 0);
128    }
129
130    #[test]
131    fn read_tlv_zero_copy_same_allocation() {
132        let raw = Bytes::from(vec![0x15, 0x03, 0xAA, 0xBB, 0xCC]);
133        let ptr = raw.as_ptr();
134        let mut r = TlvReader::new(raw);
135        let (_, val) = r.read_tlv().unwrap();
136        // The value slice should point into the same allocation.
137        assert_eq!(val.as_ptr(), unsafe { ptr.add(2) });
138    }
139
140    #[test]
141    fn read_tlv_three_byte_type() {
142        // Type 0x0320 (800) — 3-byte varu64 encoding: [0xFD, 0x03, 0x20]
143        let raw = vec![0xFD, 0x03, 0x20, 0x02, 0xAA, 0xBB];
144        let bytes = Bytes::from(raw);
145        let mut r = TlvReader::new(bytes);
146        let (typ, val) = r.read_tlv().unwrap();
147        assert_eq!(typ, 0x0320);
148        assert_eq!(val.as_ref(), &[0xAA, 0xBB]);
149    }
150
151    #[test]
152    fn read_tlv_multiple_sequential() {
153        let mut raw = vec![];
154        raw.extend_from_slice(&[0x07, 0x03, b'f', b'o', b'o']);
155        raw.extend_from_slice(&[0x08, 0x03, b'b', b'a', b'r']);
156        let mut r = TlvReader::new(Bytes::from(raw));
157        let (t1, v1) = r.read_tlv().unwrap();
158        let (t2, v2) = r.read_tlv().unwrap();
159        assert_eq!(t1, 0x07);
160        assert_eq!(v1.as_ref(), b"foo");
161        assert_eq!(t2, 0x08);
162        assert_eq!(v2.as_ref(), b"bar");
163        assert!(r.is_empty());
164    }
165
166    // ── peek_type ─────────────────────────────────────────────────────────────
167
168    #[test]
169    fn peek_type_does_not_advance() {
170        let raw = make_tlv(0x05, b"data");
171        let r = TlvReader::new(raw);
172        let t1 = r.peek_type().unwrap();
173        let t2 = r.peek_type().unwrap();
174        assert_eq!(t1, 0x05);
175        assert_eq!(t2, 0x05);
176        assert_eq!(r.remaining(), 6); // type(1) + len(1) + value(4)
177    }
178
179    // ── remaining / is_empty / position ───────────────────────────────────────
180
181    #[test]
182    fn remaining_and_is_empty() {
183        let raw = Bytes::from(vec![0x08, 0x01, 0x42]);
184        let mut r = TlvReader::new(raw);
185        assert!(!r.is_empty());
186        assert_eq!(r.remaining(), 3);
187        r.read_tlv().unwrap();
188        assert!(r.is_empty());
189        assert_eq!(r.remaining(), 0);
190    }
191
192    // ── skip_unknown (critical-bit rule) ──────────────────────────────────────
193
194    #[test]
195    fn skip_unknown_even_type_above_31_succeeds() {
196        // Type 0x22 (34) is even and >= 32 → non-critical, must skip silently.
197        let raw = Bytes::from(vec![0x22, 0x02, 0xAA, 0xBB, 0x08, 0x01, 0x42]);
198        let mut r = TlvReader::new(raw);
199        let typ = r.read_type().unwrap();
200        assert_eq!(typ, 0x22);
201        r.skip_unknown(typ).unwrap();
202        // Should now be positioned at the 0x08 TLV.
203        let (t, v) = r.read_tlv().unwrap();
204        assert_eq!(t, 0x08);
205        assert_eq!(v.as_ref(), &[0x42]);
206    }
207
208    #[test]
209    fn skip_unknown_even_type_0_to_31_is_critical() {
210        // Type 0x12 (18) is even but <= 31 → grandfathered as critical.
211        let raw = Bytes::from(vec![0x12, 0x02, 0xAA, 0xBB]);
212        let mut r = TlvReader::new(raw);
213        let typ = r.read_type().unwrap();
214        assert_eq!(typ, 0x12);
215        let err = r.skip_unknown(typ).unwrap_err();
216        assert_eq!(err, TlvError::UnknownCriticalType(0x12));
217    }
218
219    #[test]
220    fn skip_unknown_odd_type_errors() {
221        // Type 0x21 (33) is odd → critical, must return error.
222        let raw = Bytes::from(vec![0x21, 0x00]);
223        let mut r = TlvReader::new(raw);
224        let typ = r.read_type().unwrap();
225        let err = r.skip_unknown(typ).unwrap_err();
226        assert_eq!(err, TlvError::UnknownCriticalType(0x21));
227    }
228
229    // ── scoped sub-reader ─────────────────────────────────────────────────────
230
231    #[test]
232    fn scoped_reader_contains_only_inner_bytes() {
233        // Build: outer TLV containing two inner TLVs.
234        let inner: Vec<u8> = vec![0x08, 0x01, b'A', 0x08, 0x01, b'B'];
235        let mut raw = vec![0x07, inner.len() as u8];
236        raw.extend_from_slice(&inner);
237        raw.extend_from_slice(&[0x15, 0x01, 0x99]); // extra TLV after
238        let mut r = TlvReader::new(Bytes::from(raw));
239
240        let (typ, _) = r.read_tlv().unwrap();
241        assert_eq!(typ, 0x07);
242
243        // Rebuild to test scoped: re-read from scratch.
244        let inner2: Vec<u8> = vec![0x08, 0x01, b'A', 0x08, 0x01, b'B'];
245        let mut raw2 = vec![0x07, inner2.len() as u8];
246        raw2.extend_from_slice(&inner2);
247        raw2.push(0x15);
248        raw2.push(0x01);
249        raw2.push(0x99);
250        let mut r2 = TlvReader::new(Bytes::from(raw2));
251        let _outer_type = r2.read_type().unwrap();
252        let outer_len = r2.read_length().unwrap();
253        let mut inner_r = r2.scoped(outer_len).unwrap();
254
255        let (t1, v1) = inner_r.read_tlv().unwrap();
256        let (t2, v2) = inner_r.read_tlv().unwrap();
257        assert_eq!(t1, 0x08);
258        assert_eq!(v1.as_ref(), b"A");
259        assert_eq!(t2, 0x08);
260        assert_eq!(v2.as_ref(), b"B");
261        assert!(inner_r.is_empty());
262
263        // The outer reader should now be at the 0x15 TLV.
264        let (t3, _) = r2.read_tlv().unwrap();
265        assert_eq!(t3, 0x15);
266    }
267
268    // ── error cases ───────────────────────────────────────────────────────────
269
270    #[test]
271    fn read_tlv_truncated_value_errors() {
272        // Length says 5 bytes but only 2 are present.
273        let raw = Bytes::from(vec![0x08, 0x05, 0xAA, 0xBB]);
274        let mut r = TlvReader::new(raw);
275        assert_eq!(r.read_tlv().unwrap_err(), TlvError::UnexpectedEof);
276    }
277
278    #[test]
279    fn read_bytes_truncated_errors() {
280        let raw = Bytes::from(vec![0x01, 0x02]);
281        let mut r = TlvReader::new(raw);
282        assert_eq!(r.read_bytes(10).unwrap_err(), TlvError::UnexpectedEof);
283    }
284}