ndn_tlv/
writer.rs

1#[cfg(not(feature = "std"))]
2use alloc::vec::Vec;
3
4use bytes::{BufMut, BytesMut};
5
6use crate::varu64_size;
7
8/// TLV encoder backed by a growable `BytesMut` buffer.
9pub struct TlvWriter {
10    buf: BytesMut,
11}
12
13impl TlvWriter {
14    pub fn new() -> Self {
15        Self {
16            buf: BytesMut::new(),
17        }
18    }
19
20    pub fn with_capacity(cap: usize) -> Self {
21        Self {
22            buf: BytesMut::with_capacity(cap),
23        }
24    }
25
26    fn write_varu64_inner(&mut self, value: u64) {
27        let mut tmp = [0u8; 9];
28        let n = crate::write_varu64(&mut tmp, value);
29        self.buf.put_slice(&tmp[..n]);
30    }
31
32    /// Write a flat TLV element (type + length + value bytes).
33    pub fn write_tlv(&mut self, typ: u64, value: &[u8]) {
34        self.write_varu64_inner(typ);
35        self.write_varu64_inner(value.len() as u64);
36        self.buf.put_slice(value);
37    }
38
39    /// Write a nested TLV element. The closure encodes the inner content;
40    /// this method wraps it with the correct outer type and length.
41    ///
42    /// Inner content is written to a temporary writer, then the type, minimal
43    /// length, and content are appended to the main buffer.
44    pub fn write_nested<F>(&mut self, typ: u64, f: F)
45    where
46        F: FnOnce(&mut TlvWriter),
47    {
48        let mut inner = TlvWriter::new();
49        f(&mut inner);
50        let inner_bytes = inner.buf;
51
52        self.write_varu64_inner(typ);
53        self.write_varu64_inner(inner_bytes.len() as u64);
54        self.buf.put_slice(&inner_bytes);
55    }
56
57    /// Write a raw VarNumber (type or length field) without TLV framing.
58    pub fn write_varu64(&mut self, value: u64) {
59        self.write_varu64_inner(value);
60    }
61
62    /// Write raw bytes directly into the buffer (no TLV framing).
63    ///
64    /// Used when embedding a pre-encoded signed region into an outer TLV.
65    pub fn write_raw(&mut self, data: &[u8]) {
66        self.buf.put_slice(data);
67    }
68
69    /// Return a zero-copy view of the bytes written since `start` offset.
70    ///
71    /// Used to read back a signed region written incrementally — e.g. to pass
72    /// it to a signing function or to copy it into an outer TLV.  No allocation.
73    pub fn slice_from(&self, start: usize) -> &[u8] {
74        &self.buf[start..]
75    }
76
77    /// Return a copy of the bytes written since `start` offset.
78    ///
79    /// Prefer [`slice_from`] when a borrowed slice is sufficient.
80    #[deprecated(note = "use slice_from for a zero-copy &[u8]")]
81    pub fn snapshot(&self, start: usize) -> Vec<u8> {
82        self.buf[start..].to_vec()
83    }
84
85    /// Freeze and return the encoded bytes.
86    pub fn finish(self) -> bytes::Bytes {
87        self.buf.freeze()
88    }
89
90    /// Current encoded length in bytes.
91    pub fn len(&self) -> usize {
92        self.buf.len()
93    }
94
95    pub fn is_empty(&self) -> bool {
96        self.buf.is_empty()
97    }
98}
99
100impl Default for TlvWriter {
101    fn default() -> Self {
102        Self::new()
103    }
104}
105
106/// Compute the total encoded size of a TLV element without allocating.
107pub fn tlv_size(typ: u64, value_len: usize) -> usize {
108    varu64_size(typ) + varu64_size(value_len as u64) + value_len
109}
110
111#[cfg(test)]
112mod tests {
113    use super::*;
114    use crate::TlvReader;
115
116    // ── write_tlv ─────────────────────────────────────────────────────────────
117
118    #[test]
119    fn write_tlv_empty_value() {
120        let mut w = TlvWriter::new();
121        w.write_tlv(0x21, &[]);
122        let bytes = w.finish();
123        assert_eq!(bytes.as_ref(), &[0x21, 0x00]);
124    }
125
126    #[test]
127    fn write_tlv_with_value() {
128        let mut w = TlvWriter::new();
129        w.write_tlv(0x08, b"ndn");
130        let bytes = w.finish();
131        assert_eq!(bytes.as_ref(), &[0x08, 0x03, b'n', b'd', b'n']);
132    }
133
134    #[test]
135    fn write_tlv_3byte_type() {
136        let mut w = TlvWriter::new();
137        w.write_tlv(0x0320, &[0xAB]);
138        let bytes = w.finish();
139        // Type 0x0320 = 800 → [0xFD, 0x03, 0x20]; length 1 → [0x01]; value [0xAB]
140        assert_eq!(bytes.as_ref(), &[0xFD, 0x03, 0x20, 0x01, 0xAB]);
141    }
142
143    #[test]
144    fn write_tlv_roundtrip() {
145        let payload = b"hello world";
146        let mut w = TlvWriter::new();
147        w.write_tlv(0x15, payload);
148        let bytes = w.finish();
149
150        let mut r = TlvReader::new(bytes);
151        let (typ, val) = r.read_tlv().unwrap();
152        assert_eq!(typ, 0x15);
153        assert_eq!(val.as_ref(), payload);
154        assert!(r.is_empty());
155    }
156
157    #[test]
158    fn write_multiple_tlvs() {
159        let mut w = TlvWriter::new();
160        w.write_tlv(0x07, b"name");
161        w.write_tlv(0x15, b"content");
162        let bytes = w.finish();
163
164        let mut r = TlvReader::new(bytes);
165        let (t1, v1) = r.read_tlv().unwrap();
166        let (t2, v2) = r.read_tlv().unwrap();
167        assert_eq!(t1, 0x07);
168        assert_eq!(v1.as_ref(), b"name");
169        assert_eq!(t2, 0x15);
170        assert_eq!(v2.as_ref(), b"content");
171        assert!(r.is_empty());
172    }
173
174    // ── write_nested ──────────────────────────────────────────────────────────
175
176    #[test]
177    fn write_nested_empty_inner() {
178        let mut w = TlvWriter::new();
179        w.write_nested(0x07, |_| {});
180        let bytes = w.finish();
181
182        // type(1) + length-placeholder(5 bytes: 0xFE + u32) + no content
183        let mut r = TlvReader::new(bytes);
184        let (typ, val) = r.read_tlv().unwrap();
185        assert_eq!(typ, 0x07);
186        assert_eq!(val.len(), 0);
187    }
188
189    #[test]
190    fn write_nested_with_inner_tlvs() {
191        let mut w = TlvWriter::new();
192        w.write_nested(0x07, |inner| {
193            inner.write_tlv(0x08, b"foo");
194            inner.write_tlv(0x08, b"bar");
195        });
196        let bytes = w.finish();
197
198        let mut r = TlvReader::new(bytes);
199        let (typ, val) = r.read_tlv().unwrap();
200        assert_eq!(typ, 0x07);
201
202        let mut inner = TlvReader::new(val);
203        let (t1, v1) = inner.read_tlv().unwrap();
204        let (t2, v2) = inner.read_tlv().unwrap();
205        assert_eq!(t1, 0x08);
206        assert_eq!(v1.as_ref(), b"foo");
207        assert_eq!(t2, 0x08);
208        assert_eq!(v2.as_ref(), b"bar");
209        assert!(inner.is_empty());
210    }
211
212    #[test]
213    fn write_nested_three_levels() {
214        let mut w = TlvWriter::new();
215        w.write_nested(0x05, |outer| {
216            outer.write_nested(0x07, |name| {
217                name.write_tlv(0x08, b"test");
218            });
219        });
220        let bytes = w.finish();
221
222        let mut r = TlvReader::new(bytes);
223        let (t0, v0) = r.read_tlv().unwrap();
224        assert_eq!(t0, 0x05);
225        let mut r1 = TlvReader::new(v0);
226        let (t1, v1) = r1.read_tlv().unwrap();
227        assert_eq!(t1, 0x07);
228        let mut r2 = TlvReader::new(v1);
229        let (t2, v2) = r2.read_tlv().unwrap();
230        assert_eq!(t2, 0x08);
231        assert_eq!(v2.as_ref(), b"test");
232    }
233
234    // ── tlv_size ──────────────────────────────────────────────────────────────
235
236    #[test]
237    fn tlv_size_matches_write_tlv_output() {
238        let cases: &[(u64, &[u8])] = &[(0x08, b"hello"), (0x0320, &[0xAB, 0xCD]), (0x21, &[])];
239        for &(typ, value) in cases {
240            let mut w = TlvWriter::new();
241            w.write_tlv(typ, value);
242            let expected_size = tlv_size(typ, value.len());
243            assert_eq!(
244                w.len(),
245                expected_size,
246                "typ={typ:#x} value_len={}",
247                value.len()
248            );
249        }
250    }
251
252    // ── len / is_empty / with_capacity ────────────────────────────────────────
253
254    #[test]
255    fn writer_starts_empty() {
256        let w = TlvWriter::new();
257        assert!(w.is_empty());
258        assert_eq!(w.len(), 0);
259    }
260
261    #[test]
262    fn with_capacity_works_same_as_new() {
263        let mut w = TlvWriter::with_capacity(64);
264        w.write_tlv(0x08, b"hi");
265        assert_eq!(w.len(), 4);
266    }
267}