lnmp_envelope/
binary_codec.rs1use crate::{EnvelopeError, EnvelopeMetadata, Result};
25use std::io::{Read, Write};
26
27pub mod tlv_type {
29 pub const TIMESTAMP: u8 = 0x10;
31 pub const SOURCE: u8 = 0x11;
33 pub const TRACE_ID: u8 = 0x12;
35 pub const SEQUENCE: u8 = 0x13;
37 pub const LABELS: u8 = 0x14;
39}
40
41pub struct TlvEncoder;
43
44impl TlvEncoder {
45 pub fn encode(metadata: &EnvelopeMetadata) -> Result<Vec<u8>> {
66 let mut buf = Vec::new();
67
68 if let Some(ts) = metadata.timestamp {
71 Self::write_timestamp(&mut buf, ts)?;
72 }
73
74 if let Some(ref source) = metadata.source {
75 Self::write_source(&mut buf, source)?;
76 }
77
78 if let Some(ref trace_id) = metadata.trace_id {
79 Self::write_trace_id(&mut buf, trace_id)?;
80 }
81
82 if let Some(seq) = metadata.sequence {
83 Self::write_sequence(&mut buf, seq)?;
84 }
85
86 Ok(buf)
89 }
90
91 fn write_timestamp<W: Write>(w: &mut W, ts: u64) -> Result<()> {
92 w.write_all(&[tlv_type::TIMESTAMP])?;
93 w.write_all(&8u16.to_be_bytes())?;
94 w.write_all(&ts.to_be_bytes())?;
95 Ok(())
96 }
97
98 fn write_source<W: Write>(w: &mut W, source: &str) -> Result<()> {
99 let bytes = source.as_bytes();
100 if bytes.len() > u16::MAX as usize {
101 return Err(EnvelopeError::StringTooLong(
102 "source".to_string(),
103 u16::MAX as usize,
104 ));
105 }
106
107 w.write_all(&[tlv_type::SOURCE])?;
108 w.write_all(&(bytes.len() as u16).to_be_bytes())?;
109 w.write_all(bytes)?;
110 Ok(())
111 }
112
113 fn write_trace_id<W: Write>(w: &mut W, trace_id: &str) -> Result<()> {
114 let bytes = trace_id.as_bytes();
115 if bytes.len() > u16::MAX as usize {
116 return Err(EnvelopeError::StringTooLong(
117 "trace_id".to_string(),
118 u16::MAX as usize,
119 ));
120 }
121
122 w.write_all(&[tlv_type::TRACE_ID])?;
123 w.write_all(&(bytes.len() as u16).to_be_bytes())?;
124 w.write_all(bytes)?;
125 Ok(())
126 }
127
128 fn write_sequence<W: Write>(w: &mut W, seq: u64) -> Result<()> {
129 w.write_all(&[tlv_type::SEQUENCE])?;
130 w.write_all(&8u16.to_be_bytes())?;
131 w.write_all(&seq.to_be_bytes())?;
132 Ok(())
133 }
134}
135
136pub struct TlvDecoder;
138
139impl TlvDecoder {
140 pub fn decode(data: &[u8]) -> Result<EnvelopeMetadata> {
160 let mut metadata = EnvelopeMetadata::new();
161 let mut cursor = std::io::Cursor::new(data);
162 let mut last_type: Option<u8> = None;
163
164 while cursor.position() < data.len() as u64 {
165 let tlv_type = Self::read_u8(&mut cursor)?;
166 let length = Self::read_u16_be(&mut cursor)?;
167
168 if let Some(prev) = last_type {
170 if tlv_type <= prev {
171 return Err(EnvelopeError::NonCanonicalOrder(tlv_type, prev));
172 }
173 }
174 last_type = Some(tlv_type);
175
176 match tlv_type {
177 tlv_type::TIMESTAMP => {
178 if metadata.timestamp.is_some() {
180 return Err(EnvelopeError::DuplicateTlvEntry(tlv_type));
181 }
182 metadata.timestamp = Some(Self::read_timestamp(&mut cursor, length)?);
183 }
184 tlv_type::SOURCE => {
185 if metadata.source.is_some() {
187 return Err(EnvelopeError::DuplicateTlvEntry(tlv_type));
188 }
189 metadata.source = Some(Self::read_string(&mut cursor, length)?);
190 }
191 tlv_type::TRACE_ID => {
192 if metadata.trace_id.is_some() {
194 return Err(EnvelopeError::DuplicateTlvEntry(tlv_type));
195 }
196 metadata.trace_id = Some(Self::read_string(&mut cursor, length)?);
197 }
198 tlv_type::SEQUENCE => {
199 if metadata.sequence.is_some() {
201 return Err(EnvelopeError::DuplicateTlvEntry(tlv_type));
202 }
203 metadata.sequence = Some(Self::read_sequence(&mut cursor, length)?);
204 }
205 _ => {
206 Self::skip(&mut cursor, length as usize)?;
208 }
209 }
210 }
211
212 Ok(metadata)
213 }
214
215 fn read_u8<R: Read>(r: &mut R) -> Result<u8> {
216 let mut buf = [0u8; 1];
217 r.read_exact(&mut buf)
218 .map_err(|_| EnvelopeError::UnexpectedEof(0))?;
219 Ok(buf[0])
220 }
221
222 fn read_u16_be<R: Read>(r: &mut R) -> Result<u16> {
223 let mut buf = [0u8; 2];
224 r.read_exact(&mut buf)
225 .map_err(|_| EnvelopeError::UnexpectedEof(0))?;
226 Ok(u16::from_be_bytes(buf))
227 }
228
229 fn read_u64_be<R: Read>(r: &mut R) -> Result<u64> {
230 let mut buf = [0u8; 8];
231 r.read_exact(&mut buf)
232 .map_err(|_| EnvelopeError::UnexpectedEof(0))?;
233 Ok(u64::from_be_bytes(buf))
234 }
235
236 fn read_timestamp<R: Read>(r: &mut R, length: u16) -> Result<u64> {
237 if length != 8 {
238 return Err(EnvelopeError::InvalidTlvLength(length as usize));
239 }
240 Self::read_u64_be(r)
241 }
242
243 fn read_sequence<R: Read>(r: &mut R, length: u16) -> Result<u64> {
244 if length != 8 {
245 return Err(EnvelopeError::InvalidTlvLength(length as usize));
246 }
247 Self::read_u64_be(r)
248 }
249
250 fn read_string<R: Read>(r: &mut R, length: u16) -> Result<String> {
251 let mut buf = vec![0u8; length as usize];
252 r.read_exact(&mut buf)
253 .map_err(|_| EnvelopeError::UnexpectedEof(0))?;
254 String::from_utf8(buf).map_err(|e| e.into())
255 }
256
257 fn skip<R: Read>(r: &mut R, length: usize) -> Result<()> {
258 let mut buf = vec![0u8; length];
259 r.read_exact(&mut buf)
260 .map_err(|_| EnvelopeError::UnexpectedEof(0))?;
261 Ok(())
262 }
263}
264
265#[cfg(test)]
266mod tests {
267 use super::*;
268
269 #[test]
270 fn test_encode_decode_timestamp_only() {
271 let mut metadata = EnvelopeMetadata::new();
272 metadata.timestamp = Some(1732373147000);
273
274 let bytes = TlvEncoder::encode(&metadata).unwrap();
275 let decoded = TlvDecoder::decode(&bytes).unwrap();
276
277 assert_eq!(metadata, decoded);
278 }
279
280 #[test]
281 fn test_encode_decode_all_fields() {
282 let mut metadata = EnvelopeMetadata::new();
283 metadata.timestamp = Some(1732373147000);
284 metadata.source = Some("auth-service".to_string());
285 metadata.trace_id = Some("abc-123-xyz".to_string());
286 metadata.sequence = Some(42);
287
288 let bytes = TlvEncoder::encode(&metadata).unwrap();
289 let decoded = TlvDecoder::decode(&bytes).unwrap();
290
291 assert_eq!(metadata, decoded);
292 }
293
294 #[test]
295 fn test_encode_canonical_order() {
296 let mut metadata = EnvelopeMetadata::new();
297 metadata.sequence = Some(42); metadata.timestamp = Some(123); let bytes = TlvEncoder::encode(&metadata).unwrap();
301
302 assert_eq!(bytes[0], tlv_type::TIMESTAMP);
304 }
305
306 #[test]
307 fn test_decode_rejects_duplicate() {
308 let mut buf = Vec::new();
309
310 buf.write_all(&[tlv_type::TIMESTAMP]).unwrap();
312 buf.write_all(&8u16.to_be_bytes()).unwrap();
313 buf.write_all(&123u64.to_be_bytes()).unwrap();
314
315 buf.write_all(&[tlv_type::TIMESTAMP]).unwrap();
316 buf.write_all(&8u16.to_be_bytes()).unwrap();
317 buf.write_all(&456u64.to_be_bytes()).unwrap();
318
319 let result = TlvDecoder::decode(&buf);
320 assert!(result.is_err());
321 assert!(matches!(
323 result,
324 Err(EnvelopeError::NonCanonicalOrder(_, _))
325 ));
326 }
327
328 #[test]
329 fn test_decode_rejects_non_canonical_order() {
330 let mut buf = Vec::new();
331
332 buf.write_all(&[tlv_type::SOURCE]).unwrap();
334 buf.write_all(&4u16.to_be_bytes()).unwrap();
335 buf.write_all(b"test").unwrap();
336
337 buf.write_all(&[tlv_type::TIMESTAMP]).unwrap();
338 buf.write_all(&8u16.to_be_bytes()).unwrap();
339 buf.write_all(&123u64.to_be_bytes()).unwrap();
340
341 let result = TlvDecoder::decode(&buf);
342 assert!(result.is_err());
343 assert!(matches!(
344 result,
345 Err(EnvelopeError::NonCanonicalOrder(_, _))
346 ));
347 }
348
349 #[test]
350 fn test_decode_skips_unknown_type() {
351 let mut buf = Vec::new();
352
353 buf.write_all(&[tlv_type::TIMESTAMP]).unwrap();
355 buf.write_all(&8u16.to_be_bytes()).unwrap();
356 buf.write_all(&123u64.to_be_bytes()).unwrap();
357
358 buf.write_all(&[0xFF]).unwrap();
360 buf.write_all(&4u16.to_be_bytes()).unwrap();
361 buf.write_all(&[0xAA, 0xBB, 0xCC, 0xDD]).unwrap();
362
363 let decoded = TlvDecoder::decode(&buf).unwrap();
364 assert_eq!(decoded.timestamp, Some(123));
365 assert!(decoded.source.is_none());
366 }
367}