1use crate::error::{Error, Result};
4use crate::reader::MAX_DEPTH;
5use crate::tag::Tag;
6use crate::value::Value;
7use crate::{element_type as et, tag_control as tc};
8
9const MAX_HEADER: usize = 17;
13
14pub struct TlvWriter<'a> {
16 out: &'a mut Vec<u8>,
17}
18
19#[inline]
23fn encode_tag(tag: Tag, element_type: u8, buf: &mut [u8; MAX_HEADER]) -> usize {
24 match tag {
25 Tag::Anonymous => {
26 buf[0] = tc::ANONYMOUS | element_type;
27 1
28 }
29 Tag::Context(n) => {
30 buf[0] = tc::CONTEXT | element_type;
31 buf[1] = n;
32 2
33 }
34 Tag::CommonProfile(n) => {
35 if let Ok(n16) = u16::try_from(n) {
36 buf[0] = tc::COMMON_PROFILE_2 | element_type;
37 buf[1..3].copy_from_slice(&n16.to_le_bytes());
38 3
39 } else {
40 buf[0] = tc::COMMON_PROFILE_4 | element_type;
41 buf[1..5].copy_from_slice(&n.to_le_bytes());
42 5
43 }
44 }
45 Tag::ImplicitProfile(n) => {
46 if let Ok(n16) = u16::try_from(n) {
47 buf[0] = tc::IMPLICIT_PROFILE_2 | element_type;
48 buf[1..3].copy_from_slice(&n16.to_le_bytes());
49 3
50 } else {
51 buf[0] = tc::IMPLICIT_PROFILE_4 | element_type;
52 buf[1..5].copy_from_slice(&n.to_le_bytes());
53 5
54 }
55 }
56 Tag::FullyQualified {
57 vendor,
58 profile,
59 tag,
60 } => {
61 buf[1..3].copy_from_slice(&vendor.to_le_bytes());
62 buf[3..5].copy_from_slice(&profile.to_le_bytes());
63 if let Ok(tag16) = u16::try_from(tag) {
64 buf[0] = tc::FULLY_QUALIFIED_6 | element_type;
65 buf[5..7].copy_from_slice(&tag16.to_le_bytes());
66 7
67 } else {
68 buf[0] = tc::FULLY_QUALIFIED_8 | element_type;
69 buf[5..9].copy_from_slice(&tag.to_le_bytes());
70 9
71 }
72 }
73 }
74}
75
76impl<'a> TlvWriter<'a> {
77 #[inline]
80 pub fn new(out: &'a mut Vec<u8>) -> Self {
81 Self { out }
82 }
83
84 #[inline]
86 fn write_tag(&mut self, tag: Tag, element_type: u8) {
87 let mut buf = [0u8; MAX_HEADER];
88 let n = encode_tag(tag, element_type, &mut buf);
89 self.out.extend_from_slice(&buf[..n]);
90 }
91
92 #[inline]
96 fn put_scalar(&mut self, tag: Tag, element_type: u8, payload: &[u8]) {
97 let mut buf = [0u8; MAX_HEADER];
98 let n = encode_tag(tag, element_type, &mut buf);
99 buf[n..n + payload.len()].copy_from_slice(payload);
100 self.out.extend_from_slice(&buf[..n + payload.len()]);
101 }
102
103 #[inline]
110 pub fn put_bool(&mut self, tag: Tag, v: bool) -> Result<()> {
111 let et = if v { et::BOOL_TRUE } else { et::BOOL_FALSE };
112 self.put_scalar(tag, et, &[]);
113 Ok(())
114 }
115
116 #[inline]
123 pub fn put_null(&mut self, tag: Tag) -> Result<()> {
124 self.put_scalar(tag, et::NULL, &[]);
125 Ok(())
126 }
127
128 #[inline]
137 pub fn put_uint(&mut self, tag: Tag, v: u64) -> Result<()> {
138 if let Ok(n) = u8::try_from(v) {
139 self.put_scalar(tag, et::UINT8, &n.to_le_bytes());
140 } else if let Ok(n) = u16::try_from(v) {
141 self.put_scalar(tag, et::UINT16, &n.to_le_bytes());
142 } else if let Ok(n) = u32::try_from(v) {
143 self.put_scalar(tag, et::UINT32, &n.to_le_bytes());
144 } else {
145 self.put_scalar(tag, et::UINT64, &v.to_le_bytes());
146 }
147 Ok(())
148 }
149
150 #[inline]
159 pub fn put_int(&mut self, tag: Tag, v: i64) -> Result<()> {
160 if let Ok(n) = i8::try_from(v) {
161 self.put_scalar(tag, et::INT8, &n.to_le_bytes());
162 } else if let Ok(n) = i16::try_from(v) {
163 self.put_scalar(tag, et::INT16, &n.to_le_bytes());
164 } else if let Ok(n) = i32::try_from(v) {
165 self.put_scalar(tag, et::INT32, &n.to_le_bytes());
166 } else {
167 self.put_scalar(tag, et::INT64, &v.to_le_bytes());
168 }
169 Ok(())
170 }
171
172 #[inline]
179 pub fn put_float(&mut self, tag: Tag, v: f32) -> Result<()> {
180 self.put_scalar(tag, et::FLOAT32, &v.to_le_bytes());
181 Ok(())
182 }
183
184 #[inline]
191 pub fn put_double(&mut self, tag: Tag, v: f64) -> Result<()> {
192 self.put_scalar(tag, et::FLOAT64, &v.to_le_bytes());
193 Ok(())
194 }
195
196 #[inline]
205 pub fn put_utf8(&mut self, tag: Tag, v: &str) -> Result<()> {
206 self.put_string_payload(
207 tag,
208 v.as_bytes(),
209 et::UTF8_LEN8,
210 et::UTF8_LEN16,
211 et::UTF8_LEN32,
212 et::UTF8_LEN64,
213 )
214 }
215
216 #[inline]
225 pub fn put_bytes(&mut self, tag: Tag, v: &[u8]) -> Result<()> {
226 self.put_string_payload(
227 tag,
228 v,
229 et::BYTES_LEN8,
230 et::BYTES_LEN16,
231 et::BYTES_LEN32,
232 et::BYTES_LEN64,
233 )
234 }
235
236 pub fn put_preencoded(&mut self, tag: Tag, element: &[u8]) -> Result<()> {
253 let (&control, rest) = element.split_first().ok_or(Error::UnexpectedEof)?;
254 if control & tc::TAG_CONTROL_MASK != tc::ANONYMOUS {
255 return Err(Error::InvalidTagControl(control & tc::TAG_CONTROL_MASK));
256 }
257 let element_type = control & et::ELEMENT_TYPE_MASK;
258 if element_type == et::END_OF_CONTAINER {
259 return Err(Error::InvalidElementType(element_type));
260 }
261 self.write_tag(tag, element_type);
262 self.out.extend_from_slice(rest);
263 Ok(())
264 }
265
266 fn put_string_payload(
267 &mut self,
268 tag: Tag,
269 bytes: &[u8],
270 et_len8: u8,
271 et_len16: u8,
272 et_len32: u8,
273 et_len64: u8,
274 ) -> Result<()> {
275 let len = bytes.len();
276 let mut buf = [0u8; MAX_HEADER];
277 let header_len = if let Ok(len8) = u8::try_from(len) {
278 let n = encode_tag(tag, et_len8, &mut buf);
279 buf[n] = len8;
280 n + 1
281 } else if let Ok(len16) = u16::try_from(len) {
282 let n = encode_tag(tag, et_len16, &mut buf);
283 buf[n..n + 2].copy_from_slice(&len16.to_le_bytes());
284 n + 2
285 } else if let Ok(len32) = u32::try_from(len) {
286 let n = encode_tag(tag, et_len32, &mut buf);
287 buf[n..n + 4].copy_from_slice(&len32.to_le_bytes());
288 n + 4
289 } else {
290 let len64 = u64::try_from(len).map_err(|_| Error::LengthOverflow)?;
291 let n = encode_tag(tag, et_len64, &mut buf);
292 buf[n..n + 8].copy_from_slice(&len64.to_le_bytes());
293 n + 8
294 };
295 self.out.reserve(header_len + len);
298 self.out.extend_from_slice(&buf[..header_len]);
299 self.out.extend_from_slice(bytes);
300 Ok(())
301 }
302
303 #[inline]
312 pub fn start_structure(&mut self, tag: Tag) -> Result<()> {
313 self.write_tag(tag, et::STRUCTURE);
314 Ok(())
315 }
316
317 #[inline]
325 pub fn start_array(&mut self, tag: Tag) -> Result<()> {
326 self.write_tag(tag, et::ARRAY);
327 Ok(())
328 }
329
330 #[inline]
338 pub fn start_list(&mut self, tag: Tag) -> Result<()> {
339 self.write_tag(tag, et::LIST);
340 Ok(())
341 }
342
343 #[inline]
351 pub fn end_container(&mut self) -> Result<()> {
352 self.out.push(et::END_OF_CONTAINER);
353 Ok(())
354 }
355
356 pub fn write_value(&mut self, tag: Tag, value: &Value) -> Result<()> {
376 self.write_value_at_depth(tag, value, 0)
377 }
378
379 fn write_value_at_depth(&mut self, tag: Tag, value: &Value, depth: usize) -> Result<()> {
383 match value {
384 Value::Bool(v) => self.put_bool(tag, *v),
385 Value::Null => self.put_null(tag),
386 Value::Uint(v) => self.put_uint(tag, *v),
387 Value::Int(v) => self.put_int(tag, *v),
388 Value::Float(v) => self.put_float(tag, *v),
389 Value::Double(v) => self.put_double(tag, *v),
390 Value::Utf8(v) => self.put_utf8(tag, v),
391 Value::Bytes(v) => self.put_bytes(tag, v),
392 Value::Structure(members) => {
393 if depth >= MAX_DEPTH {
394 return Err(Error::ContainerTooDeep);
395 }
396 self.start_structure(tag)?;
397 for (member_tag, member_value) in members {
398 self.write_value_at_depth(*member_tag, member_value, depth + 1)?;
399 }
400 self.end_container()
401 }
402 Value::Array(elements) => {
403 if depth >= MAX_DEPTH {
404 return Err(Error::ContainerTooDeep);
405 }
406 self.start_array(tag)?;
407 for element in elements {
408 self.write_value_at_depth(Tag::Anonymous, element, depth + 1)?;
409 }
410 self.end_container()
411 }
412 Value::List(members) => {
413 if depth >= MAX_DEPTH {
414 return Err(Error::ContainerTooDeep);
415 }
416 self.start_list(tag)?;
417 for (member_tag, member_value) in members {
418 self.write_value_at_depth(*member_tag, member_value, depth + 1)?;
419 }
420 self.end_container()
421 }
422 }
423 }
424}
425
426#[cfg(test)]
427#[allow(clippy::unwrap_used)] mod tests {
430 use super::*;
431
432 #[test]
435 fn put_bool_true_anonymous_matches_vector_0001() {
436 let mut buf = Vec::new();
437 let mut w = TlvWriter::new(&mut buf);
438 w.put_bool(Tag::Anonymous, true).unwrap();
439 assert_eq!(buf, [0x09]);
440 }
441
442 #[test]
443 fn put_bool_false_anonymous_matches_vector_0002() {
444 let mut buf = Vec::new();
445 let mut w = TlvWriter::new(&mut buf);
446 w.put_bool(Tag::Anonymous, false).unwrap();
447 assert_eq!(buf, [0x08]);
448 }
449
450 #[test]
453 fn put_null_anonymous_emits_0x14() {
454 let mut buf = Vec::new();
455 let mut w = TlvWriter::new(&mut buf);
456 w.put_null(Tag::Anonymous).unwrap();
457 assert_eq!(buf, [0x14]);
458 }
459
460 #[test]
463 fn put_uint_42_anonymous_picks_1_byte_width_matches_vector_0003() {
464 let mut buf = Vec::new();
465 let mut w = TlvWriter::new(&mut buf);
466 w.put_uint(Tag::Anonymous, 42).unwrap();
467 assert_eq!(buf, [0x04, 0x2A]);
468 }
469
470 #[test]
471 fn put_uint_max_u8_anonymous_still_1_byte() {
472 let mut buf = Vec::new();
473 let mut w = TlvWriter::new(&mut buf);
474 w.put_uint(Tag::Anonymous, 255).unwrap();
475 assert_eq!(buf, [0x04, 0xFF]);
476 }
477
478 #[test]
479 fn put_uint_0x1234_anonymous_2_byte_le() {
480 let mut buf = Vec::new();
481 let mut w = TlvWriter::new(&mut buf);
482 w.put_uint(Tag::Anonymous, 0x1234).unwrap();
483 assert_eq!(buf, [0x05, 0x34, 0x12]);
484 }
485
486 #[test]
487 fn put_uint_0xcafebabe_anonymous_4_byte_le() {
488 let mut buf = Vec::new();
489 let mut w = TlvWriter::new(&mut buf);
490 w.put_uint(Tag::Anonymous, 0xCAFE_BABE).unwrap();
491 assert_eq!(buf, [0x06, 0xBE, 0xBA, 0xFE, 0xCA]);
492 }
493
494 #[test]
495 fn put_uint_big_anonymous_8_byte_le() {
496 let mut buf = Vec::new();
497 let mut w = TlvWriter::new(&mut buf);
498 w.put_uint(Tag::Anonymous, 0x0123_4567_89AB_CDEF).unwrap();
499 assert_eq!(buf, [0x07, 0xEF, 0xCD, 0xAB, 0x89, 0x67, 0x45, 0x23, 0x01]);
500 }
501
502 #[test]
505 fn put_int_neg17_anonymous_matches_vector_0008() {
506 let mut buf = Vec::new();
507 let mut w = TlvWriter::new(&mut buf);
508 w.put_int(Tag::Anonymous, -17).unwrap();
509 assert_eq!(buf, [0x00, 0xEF]);
510 }
511
512 #[test]
513 fn put_int_neg128_anonymous_1_byte() {
514 let mut buf = Vec::new();
515 let mut w = TlvWriter::new(&mut buf);
516 w.put_int(Tag::Anonymous, -128).unwrap();
517 assert_eq!(buf, [0x00, 0x80]);
518 }
519
520 #[test]
521 fn put_int_neg129_anonymous_2_byte() {
522 let mut buf = Vec::new();
523 let mut w = TlvWriter::new(&mut buf);
524 w.put_int(Tag::Anonymous, -129).unwrap();
525 assert_eq!(buf, [0x01, 0x7F, 0xFF]);
526 }
527
528 #[test]
529 fn put_int_i32_min_anonymous_4_byte() {
530 let mut buf = Vec::new();
531 let mut w = TlvWriter::new(&mut buf);
532 w.put_int(Tag::Anonymous, i64::from(i32::MIN)).unwrap();
533 assert_eq!(buf, [0x02, 0x00, 0x00, 0x00, 0x80]);
534 }
535
536 #[test]
537 fn put_int_i64_min_anonymous_8_byte() {
538 let mut buf = Vec::new();
539 let mut w = TlvWriter::new(&mut buf);
540 w.put_int(Tag::Anonymous, i64::MIN).unwrap();
541 assert_eq!(buf, [0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80]);
542 }
543
544 #[test]
547 fn put_float_zero_anonymous_matches_vector_0013() {
548 let mut buf = Vec::new();
549 let mut w = TlvWriter::new(&mut buf);
550 w.put_float(Tag::Anonymous, 0.0).unwrap();
551 assert_eq!(buf, [0x0A, 0x00, 0x00, 0x00, 0x00]);
552 }
553
554 #[test]
555 fn put_double_zero_anonymous_matches_vector_0014() {
556 let mut buf = Vec::new();
557 let mut w = TlvWriter::new(&mut buf);
558 w.put_double(Tag::Anonymous, 0.0).unwrap();
559 assert_eq!(buf, [0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
560 }
561
562 #[test]
565 fn put_uint_with_context_tag_5_emits_tag_byte() {
566 let mut buf = Vec::new();
567 let mut w = TlvWriter::new(&mut buf);
568 w.put_uint(Tag::Context(5), 42).unwrap();
569 assert_eq!(buf, [0x24, 0x05, 0x2A]);
572 }
573
574 #[test]
577 fn put_uint_with_common_profile_2_byte_tag() {
578 let mut buf = Vec::new();
579 let mut w = TlvWriter::new(&mut buf);
580 w.put_uint(Tag::CommonProfile(7), 42).unwrap();
581 assert_eq!(buf, [0x44, 0x07, 0x00, 0x2A]);
584 }
585
586 #[test]
587 fn put_uint_with_common_profile_4_byte_tag() {
588 let mut buf = Vec::new();
589 let mut w = TlvWriter::new(&mut buf);
590 w.put_uint(Tag::CommonProfile(0x0001_2345), 42).unwrap();
591 assert_eq!(buf, [0x64, 0x45, 0x23, 0x01, 0x00, 0x2A]);
594 }
595
596 #[test]
597 fn put_uint_with_common_profile_at_u16_boundary_picks_2_byte() {
598 let mut buf = Vec::new();
599 let mut w = TlvWriter::new(&mut buf);
600 w.put_uint(Tag::CommonProfile(0xFFFF), 0).unwrap();
601 assert_eq!(buf, [0x44, 0xFF, 0xFF, 0x00]);
602 }
603
604 #[test]
605 fn put_uint_with_common_profile_just_above_u16_picks_4_byte() {
606 let mut buf = Vec::new();
607 let mut w = TlvWriter::new(&mut buf);
608 w.put_uint(Tag::CommonProfile(0x0001_0000), 0).unwrap();
609 assert_eq!(buf, [0x64, 0x00, 0x00, 0x01, 0x00, 0x00]);
610 }
611
612 #[test]
615 fn put_uint_with_implicit_profile_2_byte_tag() {
616 let mut buf = Vec::new();
617 let mut w = TlvWriter::new(&mut buf);
618 w.put_uint(Tag::ImplicitProfile(7), 42).unwrap();
619 assert_eq!(buf, [0x84, 0x07, 0x00, 0x2A]);
621 }
622
623 #[test]
624 fn put_uint_with_implicit_profile_4_byte_tag() {
625 let mut buf = Vec::new();
626 let mut w = TlvWriter::new(&mut buf);
627 w.put_uint(Tag::ImplicitProfile(0x0001_2345), 42).unwrap();
628 assert_eq!(buf, [0xA4, 0x45, 0x23, 0x01, 0x00, 0x2A]);
630 }
631
632 #[test]
635 fn put_uint_with_fully_qualified_6_byte() {
636 let mut buf = Vec::new();
637 let mut w = TlvWriter::new(&mut buf);
638 w.put_uint(
639 Tag::FullyQualified {
640 vendor: 0xFFF1,
641 profile: 0x0006,
642 tag: 5,
643 },
644 42,
645 )
646 .unwrap();
647 assert_eq!(buf, [0xC4, 0xF1, 0xFF, 0x06, 0x00, 0x05, 0x00, 0x2A]);
650 }
651
652 #[test]
653 fn put_uint_with_fully_qualified_8_byte() {
654 let mut buf = Vec::new();
655 let mut w = TlvWriter::new(&mut buf);
656 w.put_uint(
657 Tag::FullyQualified {
658 vendor: 0xFFF1,
659 profile: 0x0006,
660 tag: 0x0001_2345,
661 },
662 42,
663 )
664 .unwrap();
665 assert_eq!(
667 buf,
668 [0xE4, 0xF1, 0xFF, 0x06, 0x00, 0x45, 0x23, 0x01, 0x00, 0x2A]
669 );
670 }
671
672 #[test]
675 fn put_utf8_hello_anonymous_matches_vector_0015() {
676 let mut buf = Vec::new();
677 let mut w = TlvWriter::new(&mut buf);
678 w.put_utf8(Tag::Anonymous, "Hello!").unwrap();
679 assert_eq!(buf, [0x0C, 0x06, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x21]);
680 }
681
682 #[test]
683 fn put_utf8_empty_anonymous_matches_vector_0016() {
684 let mut buf = Vec::new();
685 let mut w = TlvWriter::new(&mut buf);
686 w.put_utf8(Tag::Anonymous, "").unwrap();
687 assert_eq!(buf, [0x0C, 0x00]);
688 }
689
690 #[test]
691 fn put_utf8_at_255_byte_boundary_uses_len8() {
692 let s: String = "a".repeat(255);
693 let mut buf = Vec::new();
694 let mut w = TlvWriter::new(&mut buf);
695 w.put_utf8(Tag::Anonymous, &s).unwrap();
696 assert_eq!(buf.len(), 1 + 1 + 255);
697 assert_eq!(buf[0], 0x0C);
698 assert_eq!(buf[1], 0xFF);
699 assert!(buf[2..].iter().all(|&b| b == b'a'));
700 }
701
702 #[test]
703 fn put_utf8_at_256_bytes_picks_len16() {
704 let s: String = "a".repeat(256);
705 let mut buf = Vec::new();
706 let mut w = TlvWriter::new(&mut buf);
707 w.put_utf8(Tag::Anonymous, &s).unwrap();
708 assert_eq!(buf.len(), 1 + 2 + 256);
709 assert_eq!(buf[0], 0x0D);
710 assert_eq!(&buf[1..3], &[0x00, 0x01]);
711 assert!(buf[3..].iter().all(|&b| b == b'a'));
712 }
713
714 #[test]
715 fn put_utf8_at_u16_max_uses_len16() {
716 let s: String = "a".repeat(usize::from(u16::MAX));
717 let mut buf = Vec::new();
718 let mut w = TlvWriter::new(&mut buf);
719 w.put_utf8(Tag::Anonymous, &s).unwrap();
720 assert_eq!(buf[0], 0x0D);
721 assert_eq!(&buf[1..3], &[0xFF, 0xFF]);
722 assert_eq!(buf.len(), 1 + 2 + usize::from(u16::MAX));
723 }
724
725 #[test]
726 fn put_utf8_above_u16_max_picks_len32() {
727 let len = usize::from(u16::MAX) + 1; let s: String = "a".repeat(len);
729 let mut buf = Vec::new();
730 let mut w = TlvWriter::new(&mut buf);
731 w.put_utf8(Tag::Anonymous, &s).unwrap();
732 assert_eq!(buf[0], 0x0E);
733 assert_eq!(&buf[1..5], &[0x00, 0x00, 0x01, 0x00]);
734 assert_eq!(buf.len(), 1 + 4 + len);
735 }
736
737 #[test]
740 fn put_bytes_five_bytes_anonymous_matches_vector_0017() {
741 let mut buf = Vec::new();
742 let mut w = TlvWriter::new(&mut buf);
743 w.put_bytes(Tag::Anonymous, &[0x00, 0x01, 0x02, 0x03, 0x04])
744 .unwrap();
745 assert_eq!(buf, [0x10, 0x05, 0x00, 0x01, 0x02, 0x03, 0x04]);
746 }
747
748 #[test]
749 fn put_bytes_empty_anonymous_matches_vector_0018() {
750 let mut buf = Vec::new();
751 let mut w = TlvWriter::new(&mut buf);
752 w.put_bytes(Tag::Anonymous, &[]).unwrap();
753 assert_eq!(buf, [0x10, 0x00]);
754 }
755
756 #[test]
757 fn put_bytes_at_256_bytes_picks_len16() {
758 let data = vec![0xAB; 256];
759 let mut buf = Vec::new();
760 let mut w = TlvWriter::new(&mut buf);
761 w.put_bytes(Tag::Anonymous, &data).unwrap();
762 assert_eq!(buf[0], 0x11);
763 assert_eq!(&buf[1..3], &[0x00, 0x01]);
764 assert_eq!(buf.len(), 1 + 2 + 256);
765 assert!(buf[3..].iter().all(|&b| b == 0xAB));
766 }
767
768 #[test]
771 fn write_value_dispatches_on_utf8_and_bytes_variants() {
772 for (value, expected) in [
773 (
774 Value::Utf8(String::from("Hello!")),
775 vec![0x0C, 0x06, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x21],
776 ),
777 (
778 Value::Bytes(vec![0x00, 0x01, 0x02, 0x03, 0x04]),
779 vec![0x10, 0x05, 0x00, 0x01, 0x02, 0x03, 0x04],
780 ),
781 ] {
782 let mut buf = Vec::new();
783 let mut w = TlvWriter::new(&mut buf);
784 w.write_value(Tag::Anonymous, &value).unwrap();
785 assert_eq!(buf, expected, "value={value:?}");
786 }
787 }
788
789 #[test]
790 fn write_value_dispatches_on_variant() {
791 for (value, expected) in [
793 (Value::Bool(true), vec![0x09]),
794 (Value::Null, vec![0x14]),
795 (Value::Uint(42), vec![0x04, 0x2A]),
796 (Value::Int(-17), vec![0x00, 0xEF]),
797 (Value::Float(0.0), vec![0x0A, 0x00, 0x00, 0x00, 0x00]),
798 (
799 Value::Double(0.0),
800 vec![0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
801 ),
802 ] {
803 let mut buf = Vec::new();
804 let mut w = TlvWriter::new(&mut buf);
805 w.write_value(Tag::Anonymous, &value).unwrap();
806 assert_eq!(buf, expected, "value={value:?}");
807 }
808 }
809
810 #[test]
813 fn start_structure_anonymous_emits_0x15() {
814 let mut buf = Vec::new();
815 let mut w = TlvWriter::new(&mut buf);
816 w.start_structure(Tag::Anonymous).unwrap();
817 assert_eq!(buf, [0x15]);
818 }
819
820 #[test]
821 fn start_array_anonymous_emits_0x16() {
822 let mut buf = Vec::new();
823 let mut w = TlvWriter::new(&mut buf);
824 w.start_array(Tag::Anonymous).unwrap();
825 assert_eq!(buf, [0x16]);
826 }
827
828 #[test]
829 fn start_list_anonymous_emits_0x17() {
830 let mut buf = Vec::new();
831 let mut w = TlvWriter::new(&mut buf);
832 w.start_list(Tag::Anonymous).unwrap();
833 assert_eq!(buf, [0x17]);
834 }
835
836 #[test]
837 fn end_container_emits_0x18() {
838 let mut buf = Vec::new();
839 let mut w = TlvWriter::new(&mut buf);
840 w.end_container().unwrap();
841 assert_eq!(buf, [0x18]);
842 }
843
844 #[test]
845 fn start_structure_with_context_tag_emits_combined_byte() {
846 let mut buf = Vec::new();
847 let mut w = TlvWriter::new(&mut buf);
848 w.start_structure(Tag::Context(7)).unwrap();
849 assert_eq!(buf, [0x35, 0x07]);
851 }
852
853 #[test]
854 fn empty_structure_anonymous_matches_vector_0019() {
855 let mut buf = Vec::new();
856 let mut w = TlvWriter::new(&mut buf);
857 w.start_structure(Tag::Anonymous).unwrap();
858 w.end_container().unwrap();
859 assert_eq!(buf, [0x15, 0x18]);
860 }
861
862 #[test]
863 fn structure_with_one_member_matches_vector_0021() {
864 let mut buf = Vec::new();
866 let mut w = TlvWriter::new(&mut buf);
867 w.start_structure(Tag::Anonymous).unwrap();
868 w.put_uint(Tag::Context(0), 42).unwrap();
869 w.end_container().unwrap();
870 assert_eq!(buf, [0x15, 0x24, 0x00, 0x2A, 0x18]);
871 }
872
873 #[test]
876 fn write_value_empty_structure_matches_vector_0019() {
877 let mut buf = Vec::new();
878 let mut w = TlvWriter::new(&mut buf);
879 w.write_value(Tag::Anonymous, &Value::Structure(Vec::new()))
880 .unwrap();
881 assert_eq!(buf, [0x15, 0x18]);
882 }
883
884 #[test]
885 fn write_value_empty_array_matches_vector_0020() {
886 let mut buf = Vec::new();
887 let mut w = TlvWriter::new(&mut buf);
888 w.write_value(Tag::Anonymous, &Value::Array(Vec::new()))
889 .unwrap();
890 assert_eq!(buf, [0x16, 0x18]);
891 }
892
893 #[test]
894 fn write_value_structure_with_ctx_member_matches_vector_0021() {
895 let value = Value::Structure(vec![(Tag::Context(0), Value::Uint(42))]);
896 let mut buf = Vec::new();
897 let mut w = TlvWriter::new(&mut buf);
898 w.write_value(Tag::Anonymous, &value).unwrap();
899 assert_eq!(buf, [0x15, 0x24, 0x00, 0x2A, 0x18]);
900 }
901
902 #[test]
903 fn write_value_array_of_three_uint8_matches_vector_0022() {
904 let value = Value::Array(vec![Value::Uint(1), Value::Uint(2), Value::Uint(3)]);
905 let mut buf = Vec::new();
906 let mut w = TlvWriter::new(&mut buf);
907 w.write_value(Tag::Anonymous, &value).unwrap();
908 assert_eq!(buf, [0x16, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x18]);
909 }
910
911 #[test]
912 fn write_value_structure_with_bool_at_ctx7_matches_vector_0023() {
913 let value = Value::Structure(vec![(Tag::Context(7), Value::Bool(true))]);
914 let mut buf = Vec::new();
915 let mut w = TlvWriter::new(&mut buf);
916 w.write_value(Tag::Anonymous, &value).unwrap();
917 assert_eq!(buf, [0x15, 0x29, 0x07, 0x18]);
918 }
919
920 #[test]
921 fn write_value_empty_list_emits_0x17_0x18() {
922 let mut buf = Vec::new();
923 let mut w = TlvWriter::new(&mut buf);
924 w.write_value(Tag::Anonymous, &Value::List(Vec::new()))
925 .unwrap();
926 assert_eq!(buf, [0x17, 0x18]);
927 }
928
929 #[test]
932 fn put_preencoded_retags_anonymous_struct_to_context_1() {
933 let anonymous_struct = vec![0x15u8, 0x18];
935 let mut buf = Vec::new();
936 let mut w = TlvWriter::new(&mut buf);
937 w.put_preencoded(Tag::Context(1), &anonymous_struct)
938 .unwrap();
939 assert_eq!(buf, [0x35, 0x01, 0x18]);
944 }
945
946 #[test]
947 fn put_preencoded_rejects_empty_input() {
948 let mut buf = Vec::new();
949 let mut w = TlvWriter::new(&mut buf);
950 assert!(matches!(
951 w.put_preencoded(Tag::Context(0), &[]),
952 Err(Error::UnexpectedEof)
953 ));
954 }
955
956 #[test]
957 fn put_preencoded_rejects_non_anonymous_input() {
958 let non_anonymous = vec![0x28u8, 0x00];
960 let mut buf = Vec::new();
961 let mut w = TlvWriter::new(&mut buf);
962 assert!(matches!(
963 w.put_preencoded(Tag::Context(0), &non_anonymous),
964 Err(Error::InvalidTagControl(_))
965 ));
966 }
967
968 #[test]
969 fn put_preencoded_rejects_bare_end_of_container() {
970 let mut buf = Vec::new();
973 let mut w = TlvWriter::new(&mut buf);
974 assert!(matches!(
975 w.put_preencoded(Tag::Context(1), &[0x18]),
976 Err(Error::InvalidElementType(_))
977 ));
978 }
979
980 #[test]
981 fn write_value_nested_structure() {
982 let inner = Value::Structure(vec![(Tag::Context(0), Value::Uint(42))]);
984 let outer = Value::Structure(vec![(Tag::Context(0), inner)]);
985 let mut buf = Vec::new();
986 let mut w = TlvWriter::new(&mut buf);
987 w.write_value(Tag::Anonymous, &outer).unwrap();
988 assert_eq!(buf, [0x15, 0x35, 0x00, 0x24, 0x00, 0x2A, 0x18, 0x18]);
994 }
995
996 fn nested_structure(levels: usize) -> Value {
1001 let mut v = Value::Uint(0);
1002 for _ in 0..levels {
1003 v = Value::Structure(vec![(Tag::Anonymous, v)]);
1004 }
1005 v
1006 }
1007
1008 #[test]
1009 fn write_value_accepts_tree_at_max_depth() {
1010 let value = nested_structure(MAX_DEPTH);
1013 let mut buf = Vec::new();
1014 let mut w = TlvWriter::new(&mut buf);
1015 assert!(w.write_value(Tag::Anonymous, &value).is_ok());
1016 }
1017
1018 #[test]
1019 fn write_value_rejects_over_deep_tree() {
1020 let value = nested_structure(MAX_DEPTH + 1);
1023 let mut buf = Vec::new();
1024 let mut w = TlvWriter::new(&mut buf);
1025 assert!(matches!(
1026 w.write_value(Tag::Anonymous, &value),
1027 Err(Error::ContainerTooDeep)
1028 ));
1029 }
1030
1031 #[test]
1032 fn write_value_over_deep_tree_roundtrips_with_reader_limit() {
1033 let ok = nested_structure(MAX_DEPTH);
1036 let mut buf = Vec::new();
1037 TlvWriter::new(&mut buf)
1038 .write_value(Tag::Anonymous, &ok)
1039 .unwrap();
1040 let (_, decoded) = crate::reader::TlvReader::new(&buf).read_value().unwrap();
1041 assert_eq!(decoded, ok);
1042 }
1043
1044 #[test]
1050 fn put_uint_fq8_u64_max_is_seventeen_bytes() {
1051 let mut buf = Vec::new();
1052 let mut w = TlvWriter::new(&mut buf);
1053 w.put_uint(
1054 Tag::FullyQualified {
1055 vendor: 0xFFF1,
1056 profile: 0x0006,
1057 tag: u32::MAX,
1058 },
1059 u64::MAX,
1060 )
1061 .unwrap();
1062 assert_eq!(
1065 buf,
1066 [
1067 0xE7, 0xF1, 0xFF, 0x06, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1068 0xFF, 0xFF, 0xFF
1069 ]
1070 );
1071 assert_eq!(buf.len(), 17);
1072 }
1073}