1use crate::{Array, ArraySize};
4use core::mem;
5use core::mem::MaybeUninit;
6use core::mem::transmute;
7use wincode::ReadResult;
8use wincode::SchemaRead;
9use wincode::SchemaWrite;
10use wincode::TypeMeta;
11use wincode::WriteResult;
12use wincode::ZeroCopy;
13use wincode::io::Reader;
14use wincode::io::Writer;
15
16pub(crate) struct SliceDropGuard<T> {
17 ptr: *mut MaybeUninit<T>,
18 initialized_len: usize,
19}
20
21impl<T> SliceDropGuard<T> {
22 pub(crate) fn new(ptr: *mut MaybeUninit<T>) -> Self {
23 Self {
24 ptr,
25 initialized_len: 0,
26 }
27 }
28
29 #[inline(always)]
30 #[allow(clippy::arithmetic_side_effects)]
31 pub(crate) fn inc_len(&mut self) {
32 self.initialized_len += 1;
33 }
34}
35
36impl<T> Drop for SliceDropGuard<T> {
37 #[inline(always)]
38 fn drop(&mut self) {
39 unsafe {
40 core::ptr::drop_in_place(core::ptr::slice_from_raw_parts_mut(
41 self.ptr.cast::<T>(),
42 self.initialized_len,
43 ));
44 }
45 }
46}
47
48unsafe impl<T, U: ArraySize> ZeroCopy for Array<T, U> where T: ZeroCopy {}
52
53impl<'de, T, U> SchemaRead<'de> for Array<T, U>
54where
55 T: SchemaRead<'de>,
56 U: ArraySize,
57{
58 type Dst = Array<T::Dst, U>;
59
60 const TYPE_META: TypeMeta = const {
61 match T::TYPE_META {
62 TypeMeta::Static { size, zero_copy } => TypeMeta::Static {
63 size: U::USIZE * size,
64 zero_copy,
65 },
66 TypeMeta::Dynamic => TypeMeta::Dynamic,
67 }
68 };
69
70 #[inline]
71 fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
72 if let TypeMeta::Static {
73 zero_copy: true, ..
74 } = T::TYPE_META
75 {
76 unsafe { reader.copy_into_t(dst)? };
78 return Ok(());
79 }
80
81 let dst = unsafe {
83 transmute::<&mut MaybeUninit<Self::Dst>, &mut Array<MaybeUninit<T::Dst>, U>>(dst)
84 };
85 let base = dst.as_mut_ptr();
86 let mut guard = SliceDropGuard::<T::Dst>::new(base);
87 if let TypeMeta::Static { size, .. } = Self::TYPE_META {
88 let reader = &mut unsafe { reader.as_trusted_for(size) }?;
91 for i in 0..U::USIZE {
92 let slot = unsafe { &mut *base.add(i) };
93 T::read(reader, slot)?;
94 guard.inc_len();
95 }
96 } else {
97 for i in 0..U::USIZE {
98 let slot = unsafe { &mut *base.add(i) };
99 T::read(reader, slot)?;
100 guard.inc_len();
101 }
102 }
103 mem::forget(guard);
104 Ok(())
105 }
106}
107
108impl<T, U> SchemaWrite for Array<T, U>
109where
110 T: SchemaWrite,
111 T::Src: Sized,
112 U: ArraySize,
113{
114 type Src = Array<T::Src, U>;
115
116 const TYPE_META: TypeMeta = const {
117 match T::TYPE_META {
118 TypeMeta::Static { size, zero_copy } => TypeMeta::Static {
119 size: U::USIZE * size,
120 zero_copy,
121 },
122 TypeMeta::Dynamic => TypeMeta::Dynamic,
123 }
124 };
125
126 #[inline]
127 #[allow(clippy::arithmetic_side_effects)]
128 fn size_of(value: &Self::Src) -> WriteResult<usize> {
129 if let TypeMeta::Static { size, .. } = Self::TYPE_META {
130 return Ok(size);
131 }
132 value
134 .iter()
135 .map(T::size_of)
136 .try_fold(0usize, |acc, x| x.map(|x| acc + x))
137 }
138
139 #[inline]
140 fn write(writer: &mut impl Writer, value: &Self::Src) -> WriteResult<()> {
141 match Self::TYPE_META {
142 TypeMeta::Static {
143 zero_copy: true, ..
144 } => {
145 unsafe { writer.write_slice_t(value)? };
147 }
148 TypeMeta::Static {
149 size,
150 zero_copy: false,
151 } => {
152 let writer = &mut unsafe { writer.as_trusted_for(size) }?;
155 for item in value {
156 T::write(writer, item)?;
157 }
158 writer.finish()?;
159 }
160 TypeMeta::Dynamic => {
161 for item in value {
162 T::write(writer, item)?;
163 }
164 }
165 }
166
167 Ok(())
168 }
169}