1use std::sync::Arc;
65
66#[derive(Debug, Clone, PartialEq, Eq)]
72pub struct BufferDecodeError {
73 pub context: &'static str,
76}
77
78impl std::fmt::Display for BufferDecodeError {
79 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80 write!(f, "malformed WeaveFFI value buffer: {}", self.context)
81 }
82}
83
84impl std::error::Error for BufferDecodeError {}
85
86#[derive(Debug, Default)]
94pub struct BufferWriter {
95 buf: Vec<u8>,
96}
97
98impl BufferWriter {
99 #[must_use]
101 pub fn new() -> Self {
102 Self::default()
103 }
104
105 #[must_use]
107 pub fn with_capacity(capacity: usize) -> Self {
108 Self {
109 buf: Vec::with_capacity(capacity),
110 }
111 }
112
113 #[must_use]
115 pub fn finish(self) -> Vec<u8> {
116 self.buf
117 }
118
119 pub fn write_raw(&mut self, bytes: &[u8]) {
121 self.buf.extend_from_slice(bytes);
122 }
123
124 pub fn write_bool(&mut self, v: bool) {
126 self.buf.push(u8::from(v));
127 }
128
129 pub fn write_i8(&mut self, v: i8) {
131 self.buf.extend_from_slice(&v.to_le_bytes());
132 }
133
134 pub fn write_u8(&mut self, v: u8) {
136 self.buf.push(v);
137 }
138
139 pub fn write_i16(&mut self, v: i16) {
141 self.buf.extend_from_slice(&v.to_le_bytes());
142 }
143
144 pub fn write_u16(&mut self, v: u16) {
146 self.buf.extend_from_slice(&v.to_le_bytes());
147 }
148
149 pub fn write_i32(&mut self, v: i32) {
152 self.buf.extend_from_slice(&v.to_le_bytes());
153 }
154
155 pub fn write_u32(&mut self, v: u32) {
157 self.buf.extend_from_slice(&v.to_le_bytes());
158 }
159
160 pub fn write_i64(&mut self, v: i64) {
162 self.buf.extend_from_slice(&v.to_le_bytes());
163 }
164
165 pub fn write_u64(&mut self, v: u64) {
167 self.buf.extend_from_slice(&v.to_le_bytes());
168 }
169
170 pub fn write_f32(&mut self, v: f32) {
172 self.buf.extend_from_slice(&v.to_le_bytes());
173 }
174
175 pub fn write_f64(&mut self, v: f64) {
177 self.buf.extend_from_slice(&v.to_le_bytes());
178 }
179
180 pub fn write_len(&mut self, len: usize) {
187 let len = u32::try_from(len).expect("WeaveFFI buffer length exceeds u32::MAX");
188 self.write_u32(len);
189 }
190
191 pub fn write_string(&mut self, v: &str) {
199 self.write_bytes(v.as_bytes());
200 }
201
202 pub fn write_bytes(&mut self, v: &[u8]) {
208 self.write_len(v.len());
209 self.buf.extend_from_slice(v);
210 }
211
212 pub fn write_option_flag(&mut self, present: bool) {
215 self.buf.push(u8::from(present));
216 }
217}
218
219#[derive(Debug)]
225pub struct BufferReader<'a> {
226 data: &'a [u8],
227 pos: usize,
228 tokens: bool,
229}
230
231impl<'a> BufferReader<'a> {
232 #[must_use]
235 pub fn new(data: &'a [u8]) -> Self {
236 Self {
237 data,
238 pos: 0,
239 tokens: true,
240 }
241 }
242
243 #[must_use]
249 pub fn token_free(data: &'a [u8]) -> Self {
250 Self {
251 data,
252 pos: 0,
253 tokens: false,
254 }
255 }
256
257 #[must_use]
260 pub fn adopts_tokens(&self) -> bool {
261 self.tokens
262 }
263
264 #[must_use]
266 pub fn remaining(&self) -> usize {
267 self.data.len() - self.pos
268 }
269
270 fn take(&mut self, n: usize, context: &'static str) -> Result<&'a [u8], BufferDecodeError> {
271 if self.remaining() < n {
272 return Err(BufferDecodeError { context });
273 }
274 let slice = &self.data[self.pos..self.pos + n];
275 self.pos += n;
276 Ok(slice)
277 }
278
279 pub fn read_bool(&mut self) -> Result<bool, BufferDecodeError> {
286 match self.take(1, "bool")?[0] {
287 0 => Ok(false),
288 1 => Ok(true),
289 _ => Err(BufferDecodeError {
290 context: "bool byte out of range",
291 }),
292 }
293 }
294
295 pub fn read_i8(&mut self) -> Result<i8, BufferDecodeError> {
301 Ok(i8::from_le_bytes([self.take(1, "i8")?[0]]))
302 }
303
304 pub fn read_u8(&mut self) -> Result<u8, BufferDecodeError> {
310 Ok(self.take(1, "u8")?[0])
311 }
312
313 pub fn read_i16(&mut self) -> Result<i16, BufferDecodeError> {
319 let b = self.take(2, "i16")?;
320 Ok(i16::from_le_bytes([b[0], b[1]]))
321 }
322
323 pub fn read_u16(&mut self) -> Result<u16, BufferDecodeError> {
329 let b = self.take(2, "u16")?;
330 Ok(u16::from_le_bytes([b[0], b[1]]))
331 }
332
333 pub fn read_i32(&mut self) -> Result<i32, BufferDecodeError> {
340 let b = self.take(4, "i32")?;
341 Ok(i32::from_le_bytes([b[0], b[1], b[2], b[3]]))
342 }
343
344 pub fn read_u32(&mut self) -> Result<u32, BufferDecodeError> {
350 let b = self.take(4, "u32")?;
351 Ok(u32::from_le_bytes([b[0], b[1], b[2], b[3]]))
352 }
353
354 pub fn read_i64(&mut self) -> Result<i64, BufferDecodeError> {
360 let b = self.take(8, "i64")?;
361 Ok(i64::from_le_bytes([
362 b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
363 ]))
364 }
365
366 pub fn read_u64(&mut self) -> Result<u64, BufferDecodeError> {
372 let b = self.take(8, "u64")?;
373 Ok(u64::from_le_bytes([
374 b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
375 ]))
376 }
377
378 pub fn read_f32(&mut self) -> Result<f32, BufferDecodeError> {
384 let b = self.take(4, "f32")?;
385 Ok(f32::from_le_bytes([b[0], b[1], b[2], b[3]]))
386 }
387
388 pub fn read_f64(&mut self) -> Result<f64, BufferDecodeError> {
394 let b = self.take(8, "f64")?;
395 Ok(f64::from_le_bytes([
396 b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
397 ]))
398 }
399
400 pub fn read_len(&mut self) -> Result<usize, BufferDecodeError> {
408 let len = self.read_count()?;
409 if len > self.remaining() {
410 return Err(BufferDecodeError {
411 context: "length prefix exceeds remaining buffer",
412 });
413 }
414 Ok(len)
415 }
416
417 pub fn read_count(&mut self) -> Result<usize, BufferDecodeError> {
429 Ok(self.read_u32()? as usize)
430 }
431
432 pub fn read_raw(&mut self, n: usize) -> Result<&'a [u8], BufferDecodeError> {
438 self.take(n, "raw bytes")
439 }
440
441 pub fn read_string(&mut self) -> Result<String, BufferDecodeError> {
448 let len = self.read_len()?;
449 let bytes = self.take(len, "string bytes")?;
450 std::str::from_utf8(bytes)
451 .map(str::to_owned)
452 .map_err(|_| BufferDecodeError {
453 context: "string is not valid UTF-8",
454 })
455 }
456
457 pub fn read_bytes(&mut self) -> Result<Vec<u8>, BufferDecodeError> {
463 let len = self.read_len()?;
464 Ok(self.take(len, "byte buffer")?.to_vec())
465 }
466
467 pub fn read_option_flag(&mut self) -> Result<bool, BufferDecodeError> {
474 match self.take(1, "option flag")?[0] {
475 0 => Ok(false),
476 1 => Ok(true),
477 _ => Err(BufferDecodeError {
478 context: "option flag byte out of range",
479 }),
480 }
481 }
482
483 pub fn expect_end(&self) -> Result<(), BufferDecodeError> {
490 if self.remaining() != 0 {
491 return Err(BufferDecodeError {
492 context: "trailing bytes after value",
493 });
494 }
495 Ok(())
496 }
497}
498
499#[derive(Debug, Clone, Copy)]
507pub struct FixedWidth(());
508
509pub trait BufferValue: Sized {
518 const FIXED_WIDTH: Option<FixedWidth> = None;
521
522 fn encoded_len(&self) -> usize {
526 0
527 }
528
529 fn write_value(&self, w: &mut BufferWriter);
531
532 unsafe fn read_value(r: &mut BufferReader<'_>) -> Result<Self, BufferDecodeError>;
548}
549
550#[diagnostic::on_unimplemented(
560 message = "`{Self}` is not a WeaveFFI record or rich enum; declare C-style enums and interfaces in the module tree that uses them",
561 label = "declared outside this module tree",
562 note = "a `#[weaveffi::module]` only sees the declarations inside its own tree, so it can pass a type from another tree only as a value buffer (a record or rich enum)",
563 note = "nest the modules under one `#[weaveffi::module]` root (as inner `mod`s) so the macro can see the declaration"
564)]
565pub trait ByValue {}
566
567macro_rules! scalar_buffer_value {
568 ($($t:ty => ($write:ident, $read:ident)),* $(,)?) => {
569 $(
570 impl BufferValue for $t {
571 fn encoded_len(&self) -> usize {
572 std::mem::size_of::<$t>()
573 }
574 fn write_value(&self, w: &mut BufferWriter) {
575 w.$write(*self);
576 }
577 unsafe fn read_value(r: &mut BufferReader<'_>) -> Result<Self, BufferDecodeError> {
578 r.$read()
579 }
580 }
581 )*
582 };
583}
584
585macro_rules! fixed_width_buffer_value {
586 ($($t:ty => ($write:ident, $read:ident)),* $(,)?) => {
587 $(
588 impl BufferValue for $t {
589 const FIXED_WIDTH: Option<FixedWidth> = if cfg!(target_endian = "little") {
590 Some(FixedWidth(()))
591 } else {
592 None
593 };
594 fn encoded_len(&self) -> usize {
595 std::mem::size_of::<$t>()
596 }
597 fn write_value(&self, w: &mut BufferWriter) {
598 w.$write(*self);
599 }
600 unsafe fn read_value(r: &mut BufferReader<'_>) -> Result<Self, BufferDecodeError> {
601 r.$read()
602 }
603 }
604 )*
605 };
606}
607
608scalar_buffer_value! {
609 bool => (write_bool, read_bool),
610}
611
612fixed_width_buffer_value! {
613 i8 => (write_i8, read_i8),
614 u8 => (write_u8, read_u8),
615 i16 => (write_i16, read_i16),
616 u16 => (write_u16, read_u16),
617 i32 => (write_i32, read_i32),
618 u32 => (write_u32, read_u32),
619 i64 => (write_i64, read_i64),
620 u64 => (write_u64, read_u64),
621 f32 => (write_f32, read_f32),
622 f64 => (write_f64, read_f64),
623}
624
625impl BufferValue for String {
626 fn encoded_len(&self) -> usize {
627 4 + self.len()
628 }
629 fn write_value(&self, w: &mut BufferWriter) {
630 w.write_string(self);
631 }
632 unsafe fn read_value(r: &mut BufferReader<'_>) -> Result<Self, BufferDecodeError> {
633 r.read_string()
634 }
635}
636
637impl<T> BufferValue for Arc<T> {
644 fn encoded_len(&self) -> usize {
645 8
646 }
647 fn write_value(&self, w: &mut BufferWriter) {
648 w.write_u64(crate::abi::object::object_to_token(self));
649 }
650 unsafe fn read_value(r: &mut BufferReader<'_>) -> Result<Self, BufferDecodeError> {
651 if !r.tokens {
652 return Err(BufferDecodeError {
653 context: "object token in a buffer that may not carry objects",
654 });
655 }
656 let token = r.read_u64()?;
657 unsafe { crate::abi::object::object_from_token(token) }.ok_or(BufferDecodeError {
660 context: "null object token",
661 })
662 }
663}
664
665impl<T: BufferValue> BufferValue for Option<T> {
666 fn encoded_len(&self) -> usize {
667 1 + self.as_ref().map_or(0, BufferValue::encoded_len)
668 }
669 fn write_value(&self, w: &mut BufferWriter) {
670 match self {
671 Some(v) => {
672 w.write_option_flag(true);
673 v.write_value(w);
674 }
675 None => w.write_option_flag(false),
676 }
677 }
678 unsafe fn read_value(r: &mut BufferReader<'_>) -> Result<Self, BufferDecodeError> {
679 if r.read_option_flag()? {
680 Ok(Some(unsafe { T::read_value(r) }?))
682 } else {
683 Ok(None)
684 }
685 }
686}
687
688impl<T: BufferValue> BufferValue for Vec<T> {
689 fn encoded_len(&self) -> usize {
690 if T::FIXED_WIDTH.is_some() {
691 return 4 + std::mem::size_of_val(self.as_slice());
692 }
693 4 + self.iter().map(BufferValue::encoded_len).sum::<usize>()
694 }
695
696 fn write_value(&self, w: &mut BufferWriter) {
697 w.write_len(self.len());
698 if let Some(proof) = T::FIXED_WIDTH {
699 w.write_raw(fixed_width_bytes(proof, self));
700 return;
701 }
702 for item in self {
703 item.write_value(w);
704 }
705 }
706
707 unsafe fn read_value(r: &mut BufferReader<'_>) -> Result<Self, BufferDecodeError> {
708 let count = r.read_count()?;
709 if let Some(proof) = T::FIXED_WIDTH {
710 let size = count
711 .checked_mul(std::mem::size_of::<T>())
712 .ok_or(BufferDecodeError {
713 context: "list length overflows",
714 })?;
715 let bytes = r.take(size, "fixed-width list")?;
716 return Ok(fixed_width_from_bytes(proof, bytes, count));
717 }
718 let mut out = Vec::with_capacity(count.min(r.remaining()));
719 for _ in 0..count {
720 out.push(unsafe { T::read_value(r) }?);
722 }
723 Ok(out)
724 }
725}
726
727fn fixed_width_bytes<T: BufferValue>(_proof: FixedWidth, items: &[T]) -> &[u8] {
729 unsafe { std::slice::from_raw_parts(items.as_ptr().cast::<u8>(), std::mem::size_of_val(items)) }
733}
734
735fn fixed_width_from_bytes<T: BufferValue>(
737 _proof: FixedWidth,
738 bytes: &[u8],
739 count: usize,
740) -> Vec<T> {
741 let mut out = Vec::<T>::with_capacity(count);
742 unsafe {
747 std::ptr::copy_nonoverlapping(bytes.as_ptr(), out.as_mut_ptr().cast::<u8>(), bytes.len());
748 out.set_len(count);
749 }
750 out
751}
752
753const DUPLICATE_KEY: BufferDecodeError = BufferDecodeError {
755 context: "duplicate map key",
756};
757
758impl<K: BufferValue + Ord, V: BufferValue> BufferValue for std::collections::BTreeMap<K, V> {
759 fn encoded_len(&self) -> usize {
760 4 + self
761 .iter()
762 .map(|(k, v)| k.encoded_len() + v.encoded_len())
763 .sum::<usize>()
764 }
765 fn write_value(&self, w: &mut BufferWriter) {
766 w.write_len(self.len());
767 for (k, v) in self {
768 k.write_value(w);
769 v.write_value(w);
770 }
771 }
772 unsafe fn read_value(r: &mut BufferReader<'_>) -> Result<Self, BufferDecodeError> {
773 let len = r.read_count()?;
774 let mut out = Self::new();
775 for _ in 0..len {
776 let (k, v) = unsafe { (K::read_value(r)?, V::read_value(r)?) };
778 if out.insert(k, v).is_some() {
779 return Err(DUPLICATE_KEY);
780 }
781 }
782 Ok(out)
783 }
784}
785
786impl<K: BufferValue + std::hash::Hash + Eq, V: BufferValue> BufferValue
787 for std::collections::HashMap<K, V>
788{
789 fn encoded_len(&self) -> usize {
790 4 + self
791 .iter()
792 .map(|(k, v)| k.encoded_len() + v.encoded_len())
793 .sum::<usize>()
794 }
795 fn write_value(&self, w: &mut BufferWriter) {
796 w.write_len(self.len());
797 for (k, v) in self {
798 k.write_value(w);
799 v.write_value(w);
800 }
801 }
802 unsafe fn read_value(r: &mut BufferReader<'_>) -> Result<Self, BufferDecodeError> {
803 let len = r.read_count()?;
804 let mut out = Self::with_capacity(len.min(r.remaining()));
805 for _ in 0..len {
806 let (k, v) = unsafe { (K::read_value(r)?, V::read_value(r)?) };
808 if out.insert(k, v).is_some() {
809 return Err(DUPLICATE_KEY);
810 }
811 }
812 Ok(out)
813 }
814}
815
816#[must_use]
819pub fn encode_value<T: BufferValue>(value: &T) -> Vec<u8> {
820 let mut w = BufferWriter::with_capacity(value.encoded_len());
821 value.write_value(&mut w);
822 w.finish()
823}
824
825pub unsafe fn decode_value<T: BufferValue>(data: &[u8]) -> Result<T, BufferDecodeError> {
839 let mut r = BufferReader::new(data);
840 let value = unsafe { T::read_value(&mut r) }?;
842 r.expect_end()?;
843 Ok(value)
844}
845
846#[cfg(test)]
847mod tests {
848 use super::*;
849 use std::collections::BTreeMap;
850
851 fn decode<T: BufferValue>(data: &[u8]) -> Result<T, BufferDecodeError> {
853 unsafe { decode_value(data) }
856 }
857
858 fn roundtrip<T: BufferValue + PartialEq + std::fmt::Debug>(value: T) {
859 let bytes = encode_value(&value);
860 let back: T = decode(&bytes).unwrap();
861 assert_eq!(back, value);
862 }
863
864 #[test]
865 fn scalars_roundtrip() {
866 roundtrip(true);
867 roundtrip(false);
868 roundtrip(-5i8);
869 roundtrip(200u8);
870 roundtrip(-1234i16);
871 roundtrip(54321u16);
872 roundtrip(-7i32);
873 roundtrip(4_000_000_000u32);
874 roundtrip(i64::MIN);
875 roundtrip(u64::MAX);
876 roundtrip(1.5f32);
877 roundtrip(-2.25f64);
878 }
879
880 #[test]
881 fn strings_roundtrip_including_interior_nul() {
882 roundtrip(String::new());
883 roundtrip("hello".to_string());
884 roundtrip("emoji \u{1F980} and\0nul".to_string());
885 }
886
887 #[test]
888 fn options_roundtrip() {
889 roundtrip::<Option<i32>>(None);
890 roundtrip(Some(42i32));
891 roundtrip(Some("text".to_string()));
892 roundtrip::<Option<Option<i64>>>(Some(None));
893 roundtrip::<Option<Option<i64>>>(Some(Some(9)));
894 }
895
896 #[test]
897 fn collections_roundtrip() {
898 roundtrip(vec![1u8, 2, 3]);
899 roundtrip(vec!["a".to_string(), String::new(), "ccc".to_string()]);
900 roundtrip(vec![vec![1i32, 2], vec![], vec![3]]);
901 roundtrip(vec![Some(1i32), None, Some(3)]);
902 let mut m = BTreeMap::new();
903 m.insert("a".to_string(), vec![1i64, 2]);
904 m.insert("b".to_string(), vec![]);
905 roundtrip(m);
906 }
907
908 #[test]
909 fn object_tokens_transfer_one_reference() {
910 let obj = Arc::new(String::from("shared"));
911 let bytes = encode_value(&vec![Some(Arc::clone(&obj)), None, Some(Arc::clone(&obj))]);
912 assert_eq!(Arc::strong_count(&obj), 3);
913 let back: Vec<Option<Arc<String>>> = decode(&bytes).unwrap();
914 assert_eq!(Arc::strong_count(&obj), 3);
915 assert!(Arc::ptr_eq(back[0].as_ref().unwrap(), &obj));
916 assert!(back[1].is_none());
917 drop(back);
918 assert_eq!(Arc::strong_count(&obj), 1);
919 let zero = [0u8; 8];
920 assert!(decode::<Arc<String>>(&zero).is_err());
921 }
922
923 #[test]
924 fn duplicate_map_keys_are_rejected() {
925 let mut w = BufferWriter::new();
926 w.write_len(2);
927 for v in [1i32, 2] {
928 w.write_string("k");
929 w.write_i32(v);
930 }
931 let bytes = w.finish();
932 let err = decode::<BTreeMap<String, i32>>(&bytes).unwrap_err();
933 assert_eq!(err.context, "duplicate map key");
934 assert!(decode::<std::collections::HashMap<String, i32>>(&bytes).is_err());
935 }
936
937 #[test]
938 fn token_free_readers_refuse_objects() {
939 let obj = Arc::new(5u8);
940 let bytes = encode_value(&obj);
941 let mut r = BufferReader::token_free(&bytes);
942 assert!(!r.adopts_tokens());
943 assert!(unsafe { Arc::<u8>::read_value(&mut r) }.is_err());
945 let back: Arc<u8> = decode(&bytes).unwrap();
947 assert!(Arc::ptr_eq(&back, &obj));
948 }
949
950 #[test]
951 fn known_byte_layout() {
952 let bytes = encode_value(&vec!["a".to_string(), String::new()]);
954 assert_eq!(bytes, [2, 0, 0, 0, 1, 0, 0, 0, b'a', 0, 0, 0, 0].as_slice());
955 }
956
957 #[test]
958 fn truncated_buffer_is_rejected() {
959 let bytes = encode_value(&"hello".to_string());
960 let err = decode::<String>(&bytes[..bytes.len() - 1]).unwrap_err();
961 assert!(err.to_string().contains("malformed"));
962 }
963
964 #[test]
965 fn trailing_bytes_are_rejected() {
966 let mut bytes = encode_value(&7i32);
967 bytes.push(0);
968 assert!(decode::<i32>(&bytes).is_err());
969 }
970
971 #[test]
972 fn hostile_length_prefix_is_rejected() {
973 let bytes = [0xFF, 0xFF, 0xFF, 0xFF];
976 assert!(decode::<Vec<u8>>(&bytes).is_err());
977 }
978
979 #[test]
980 fn invalid_bool_and_flag_bytes_are_rejected() {
981 assert!(decode::<bool>(&[2]).is_err());
982 assert!(decode::<Option<i32>>(&[9]).is_err());
983 }
984
985 #[test]
986 fn invalid_utf8_is_rejected() {
987 let bytes = [2, 0, 0, 0, 0xFF, 0xFE];
988 assert!(decode::<String>(&bytes).is_err());
989 }
990
991 #[derive(Debug, PartialEq)]
992 struct NoFields;
993
994 impl BufferValue for NoFields {
995 fn write_value(&self, _w: &mut BufferWriter) {}
996 unsafe fn read_value(_r: &mut BufferReader<'_>) -> Result<Self, BufferDecodeError> {
997 Ok(NoFields)
998 }
999 }
1000
1001 #[test]
1002 fn zero_sized_elements_allow_counts_beyond_the_remaining_bytes() {
1003 roundtrip(vec![NoFields, NoFields, NoFields]);
1004 assert_eq!(encode_value(&vec![NoFields, NoFields]), [2, 0, 0, 0]);
1005 }
1006
1007 #[test]
1008 fn encoded_len_is_exact() {
1009 fn check<T: BufferValue>(v: T) {
1010 let bytes = encode_value(&v);
1011 assert_eq!(bytes.len(), v.encoded_len());
1012 assert_eq!(bytes.capacity(), bytes.len());
1013 }
1014 check(vec![1u16, 2, 3]);
1015 check(vec![1.5f64]);
1016 check(vec![true, false]);
1017 check(Some("text".to_string()));
1018 check(vec![Some(vec![1i64]), None]);
1019 let mut m = BTreeMap::new();
1020 m.insert("k".to_string(), vec![Some(1u8)]);
1021 check(m);
1022 }
1023
1024 #[test]
1025 fn fixed_width_lists_use_the_scalar_layout() {
1026 let v = vec![1i32, -2, 0x0102_0304];
1027 let mut slow = BufferWriter::new();
1028 slow.write_len(v.len());
1029 for x in &v {
1030 slow.write_i32(*x);
1031 }
1032 assert_eq!(encode_value(&v), slow.finish());
1033 roundtrip(v);
1034 roundtrip(vec![f32::MIN, 0.0, f32::MAX]);
1035 roundtrip(Vec::<u64>::new());
1036 }
1037
1038 #[test]
1039 fn truncated_fixed_width_list_is_rejected() {
1040 let mut bytes = encode_value(&vec![7u32, 8]);
1041 bytes.pop();
1042 assert!(decode::<Vec<u32>>(&bytes).is_err());
1043 let huge = [0xFF, 0xFF, 0xFF, 0xFF];
1044 assert!(decode::<Vec<u64>>(&huge).is_err());
1045 assert!(decode::<Vec<String>>(&huge).is_err());
1046 }
1047}