wincode/schema/external/
smallvec.rs1use {
2 crate::{
3 ReadResult, SchemaRead, SchemaWrite, WriteResult,
4 config::Config,
5 containers::decode_into_container_t,
6 io::{Reader, Writer},
7 len::SeqLen,
8 schema::{size_of_elem_slice, write_elem_slice_prealloc_check},
9 },
10 core::{mem::MaybeUninit, slice::from_raw_parts_mut},
11 smallvec::SmallVec,
12};
13
14unsafe impl<T, const N: usize, C: Config> SchemaWrite<C> for SmallVec<[T; N]>
15where
16 T: SchemaWrite<C>,
17 T::Src: Sized,
18{
19 type Src = SmallVec<[T::Src; N]>;
20
21 #[inline]
22 fn size_of(src: &Self::Src) -> WriteResult<usize> {
23 size_of_elem_slice::<T, C::LengthEncoding, C>(src)
24 }
25
26 #[inline]
27 fn write(writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
28 write_elem_slice_prealloc_check::<T, C::LengthEncoding, C>(writer, src)
29 }
30}
31
32unsafe impl<'de, T, const N: usize, C: Config> SchemaRead<'de, C> for SmallVec<[T; N]>
33where
34 T: SchemaRead<'de, C>,
35{
36 type Dst = SmallVec<[T::Dst; N]>;
37
38 #[inline]
39 fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
40 let len = C::LengthEncoding::read_prealloc_check::<T::Dst>(reader.by_ref())?;
41
42 struct Guard<'a, U>(&'a mut MaybeUninit<U>);
46 impl<U> Drop for Guard<'_, U> {
47 fn drop(&mut self) {
48 unsafe { self.0.assume_init_drop() };
52 }
53 }
54
55 let guard = decode_into_container_t::<T, C, _>(
56 reader,
57 len,
58 move |len| {
61 dst.write(SmallVec::new()).reserve_exact(len);
62 Guard(dst)
63 },
64 |guard| unsafe {
66 let ptr = guard.0.assume_init_mut().as_mut_ptr();
67 from_raw_parts_mut(ptr.cast::<MaybeUninit<T::Dst>>(), len)
68 },
69 )?;
70
71 unsafe { guard.0.assume_init_mut().set_len(len) };
73 core::mem::forget(guard);
75 Ok(())
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use {
82 crate::{deserialize, proptest_config::proptest_cfg, serialize},
83 proptest::prelude::*,
84 smallvec::{SmallVec, smallvec},
85 };
86
87 type SmallVec4<T> = SmallVec<[T; 4]>;
88
89 #[test]
90 fn test_smallvec_inline_roundtrip() {
91 let value: SmallVec4<u8> = smallvec![1u8, 2, 3];
92 let serialized = serialize(&value).unwrap();
93 let deserialized: SmallVec4<u8> = deserialize(&serialized).unwrap();
94 assert_eq!(deserialized, value);
95 }
96
97 #[test]
98 fn test_smallvec_spilled_roundtrip() {
99 let value: SmallVec4<u8> = smallvec![1u8, 2, 3, 4, 5];
100 let serialized = serialize(&value).unwrap();
101 let deserialized: SmallVec4<u8> = deserialize(&serialized).unwrap();
102 assert_eq!(deserialized, value);
103 }
104
105 proptest! {
106 #![proptest_config(proptest_cfg())]
107
108 #[test]
109 fn test_smallvec_static(value in proptest::collection::vec(any::<u64>(), 0..=100).prop_map(SmallVec4::from_vec)) {
110 let bincode_serialized = bincode::serialize(&value).unwrap();
111 let schema_serialized = serialize(&value).unwrap();
112 prop_assert_eq!(&bincode_serialized, &schema_serialized);
113
114 let bincode_deserialized: SmallVec4<u64> = bincode::deserialize(&bincode_serialized).unwrap();
115 let schema_deserialized: SmallVec4<u64> = deserialize(&schema_serialized).unwrap();
116 prop_assert_eq!(&value, &bincode_deserialized);
117 prop_assert_eq!(value, schema_deserialized);
118 }
119
120 #[test]
121 fn test_smallvec_non_static(value in proptest::collection::vec(any::<String>(), 0..=16).prop_map(SmallVec4::from_vec)) {
122 let bincode_serialized = bincode::serialize(&value).unwrap();
123 let schema_serialized = serialize(&value).unwrap();
124 prop_assert_eq!(&bincode_serialized, &schema_serialized);
125
126 let bincode_deserialized: SmallVec4<String> = bincode::deserialize(&bincode_serialized).unwrap();
127 let schema_deserialized: SmallVec4<String> = deserialize(&schema_serialized).unwrap();
128 prop_assert_eq!(&value, &bincode_deserialized);
129 prop_assert_eq!(value, schema_deserialized);
130 }
131 }
132}