ndn_transport/
tlv_codec.rs

1use bytes::{Bytes, BytesMut};
2use tokio_util::codec::{Decoder, Encoder};
3
4use ndn_tlv::read_varu64;
5
6/// `tokio_util::codec` implementation for NDN TLV framing over byte streams.
7///
8/// NDN uses length-prefix framing: each frame is a complete TLV element
9/// `[type | length | value]` where both type and length are `varu64`-encoded.
10/// This codec reassembles frames from the byte stream and passes complete
11/// TLV buffers up to the face.
12///
13/// ## Wire format
14///
15/// ```text
16/// ┌──────────┬──────────┬─────────────────┐
17/// │ type     │ length   │ value           │
18/// │ (varu64) │ (varu64) │ (length bytes)  │
19/// └──────────┴──────────┴─────────────────┘
20/// ```
21///
22/// Both `TcpFace` and `SerialFace` (over COBS) use this codec for framing.
23#[derive(Clone, Copy)]
24pub struct TlvCodec;
25
26impl Decoder for TlvCodec {
27    type Item = Bytes;
28    type Error = std::io::Error;
29
30    fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
31        if src.is_empty() {
32            return Ok(None);
33        }
34
35        // Peek the type field (varu64) to find its encoded length.
36        let (_, type_len) = match read_varu64(src) {
37            Ok(r) => r,
38            Err(_) => return Ok(None), // not enough bytes yet
39        };
40
41        // Peek the length field (varu64) that follows the type.
42        if src.len() < type_len + 1 {
43            return Ok(None);
44        }
45        let (value_len, len_len) = match read_varu64(&src[type_len..]) {
46            Ok(r) => r,
47            Err(_) => return Ok(None), // not enough bytes yet
48        };
49
50        let header_len = type_len + len_len;
51        let frame_len = header_len + value_len as usize;
52
53        if src.len() < frame_len {
54            // Tell tokio-util how much more we'll need so it can pre-allocate.
55            src.reserve(frame_len - src.len());
56            return Ok(None);
57        }
58
59        Ok(Some(src.split_to(frame_len).freeze()))
60    }
61}
62
63impl Encoder<Bytes> for TlvCodec {
64    type Error = std::io::Error;
65
66    fn encode(&mut self, item: Bytes, dst: &mut BytesMut) -> Result<(), Self::Error> {
67        dst.extend_from_slice(&item);
68        Ok(())
69    }
70}
71
72#[cfg(test)]
73mod tests {
74    use super::*;
75    use bytes::BufMut;
76    use ndn_tlv::TlvWriter;
77
78    fn make_tlv(typ: u8, value: &[u8]) -> Bytes {
79        let mut w = TlvWriter::new();
80        w.write_tlv(typ as u64, value);
81        w.finish()
82    }
83
84    fn decode_one(src: &mut BytesMut) -> Option<Bytes> {
85        TlvCodec.decode(src).unwrap()
86    }
87
88    // ── basic decode ─────────────────────────────────────────────────────────
89
90    #[test]
91    fn decode_complete_tlv() {
92        let tlv = make_tlv(0x05, b"hello");
93        let mut src = BytesMut::from(tlv.as_ref());
94        let frame = decode_one(&mut src).unwrap();
95        // Decoded frame matches the original TLV bytes.
96        assert_eq!(frame.as_ref(), tlv.as_ref());
97        assert!(src.is_empty());
98    }
99
100    #[test]
101    fn decode_empty_value_tlv() {
102        let tlv = make_tlv(0x21, &[]);
103        let mut src = BytesMut::from(tlv.as_ref());
104        let frame = decode_one(&mut src).unwrap();
105        assert_eq!(frame.as_ref(), &[0x21, 0x00]);
106    }
107
108    #[test]
109    fn decode_incomplete_returns_none() {
110        // Only 1 byte — not enough to parse type + length + value.
111        let mut src = BytesMut::from(&[0x05u8][..]);
112        assert!(decode_one(&mut src).is_none());
113    }
114
115    #[test]
116    fn decode_partial_value_returns_none() {
117        // Header says 5 bytes of value; only 2 are present.
118        let mut src = BytesMut::new();
119        src.put_u8(0x08); // type
120        src.put_u8(0x05); // length = 5
121        src.put_slice(&[0xAA, 0xBB]); // only 2 value bytes
122        assert!(decode_one(&mut src).is_none());
123    }
124
125    #[test]
126    fn decode_two_sequential_frames() {
127        let t1 = make_tlv(0x07, b"foo");
128        let t2 = make_tlv(0x08, b"bar");
129        let mut src = BytesMut::new();
130        src.extend_from_slice(&t1);
131        src.extend_from_slice(&t2);
132
133        let f1 = decode_one(&mut src).unwrap();
134        let f2 = decode_one(&mut src).unwrap();
135        assert_eq!(f1.as_ref(), t1.as_ref());
136        assert_eq!(f2.as_ref(), t2.as_ref());
137        assert!(src.is_empty());
138    }
139
140    #[test]
141    fn decode_large_value() {
142        let value = vec![0xABu8; 300]; // length > 0xFD, needs 3-byte varu64
143        let mut w = TlvWriter::new();
144        w.write_tlv(0x06, &value);
145        let tlv = w.finish();
146        let mut src = BytesMut::from(tlv.as_ref());
147        let frame = decode_one(&mut src).unwrap();
148        assert_eq!(frame.as_ref(), tlv.as_ref());
149    }
150
151    // ── encode ───────────────────────────────────────────────────────────────
152
153    #[test]
154    fn encode_appends_bytes_as_is() {
155        let pkt = Bytes::from_static(&[0x05, 0x03, b'a', b'b', b'c']);
156        let mut dst = BytesMut::new();
157        TlvCodec.encode(pkt.clone(), &mut dst).unwrap();
158        assert_eq!(dst.as_ref(), pkt.as_ref());
159    }
160
161    #[test]
162    fn encode_then_decode_roundtrip() {
163        let tlv = make_tlv(0x15, b"content");
164        let mut dst = BytesMut::new();
165        TlvCodec.encode(tlv.clone(), &mut dst).unwrap();
166        let frame = decode_one(&mut dst).unwrap();
167        assert_eq!(frame.as_ref(), tlv.as_ref());
168    }
169}