1mod error;
8
9use core::marker::PhantomData;
10use core::ptr::copy_nonoverlapping;
11
12pub use self::error::EncodeError;
13
14use crate::{
15 Encoder, EncoderExt as _, Slot, WireBox, WireF32, WireF64, WireI16, WireI32, WireI64, WireU16,
16 WireU32, WireU64,
17};
18
19pub struct CopyOptimization<T: ?Sized>(bool, PhantomData<T>);
21
22impl<T: ?Sized> CopyOptimization<T> {
23 pub const unsafe fn enable() -> Self {
29 Self(true, PhantomData)
30 }
31
32 pub const unsafe fn enable_if(value: bool) -> Self {
39 Self(value, PhantomData)
40 }
41
42 pub const fn disable() -> Self {
44 Self(false, PhantomData)
45 }
46
47 pub const fn is_enabled(&self) -> bool {
49 self.0
50 }
51}
52
53pub unsafe trait ZeroPadding {
59 unsafe fn zero_padding(ptr: *mut Self);
65}
66
67unsafe impl<T: ZeroPadding, const N: usize> ZeroPadding for [T; N] {
68 #[inline]
69 unsafe fn zero_padding(backing: *mut Self) {
70 for i in 0..N {
71 unsafe {
72 T::zero_padding(backing.cast::<T>().add(i));
73 }
74 }
75 }
76}
77
78macro_rules! impl_zero_padding_for_primitive {
79 ($ty:ty) => {
80 unsafe impl ZeroPadding for $ty {
81 #[inline]
82 unsafe fn zero_padding(_: *mut Self) {}
83 }
84 };
85}
86
87macro_rules! impl_zero_padding_for_primitives {
88 ($($ty:ty),* $(,)?) => {
89 $(
90 impl_zero_padding_for_primitive!($ty);
91 )*
92 }
93}
94
95impl_zero_padding_for_primitives! {
96 (), bool, i8, u8,
97 WireI16, WireI32, WireI64,
98 WireU16, WireU32, WireU64,
99 WireF32, WireF64,
100}
101
102pub trait Encodable {
104 const COPY_OPTIMIZATION: CopyOptimization<Self> = CopyOptimization::disable();
111
112 type Encoded: ZeroPadding;
114}
115
116pub trait Encode<E: ?Sized>: Encodable {
118 fn encode(&mut self, encoder: &mut E, slot: Slot<'_, Self::Encoded>)
120 -> Result<(), EncodeError>;
121}
122
123pub trait EncodableOption {
125 type EncodedOption: ZeroPadding;
127}
128
129pub trait EncodeOption<E: ?Sized>: EncodableOption {
131 fn encode_option(
133 this: Option<&mut Self>,
134 encoder: &mut E,
135 slot: Slot<'_, Self::EncodedOption>,
136 ) -> Result<(), EncodeError>;
137}
138
139macro_rules! impl_encode_for_primitive {
140 ($ty:ty, $enc:ty) => {
141 impl Encodable for $ty {
142 const COPY_OPTIMIZATION: CopyOptimization<Self> = unsafe {
145 CopyOptimization::enable_if(
146 size_of::<Self>() <= 1 || cfg!(target_endian = "little"),
147 )
148 };
149
150 type Encoded = $enc;
151 }
152
153 impl<E: ?Sized> Encode<E> for $ty {
154 #[inline]
155 fn encode(
156 &mut self,
157 _: &mut E,
158 mut slot: Slot<'_, Self::Encoded>,
159 ) -> Result<(), EncodeError> {
160 slot.write(<$enc>::from(*self));
161 Ok(())
162 }
163 }
164
165 impl EncodableOption for $ty {
166 type EncodedOption = WireBox<$enc>;
167 }
168
169 impl<E: Encoder + ?Sized> EncodeOption<E> for $ty {
170 #[inline]
171 fn encode_option(
172 this: Option<&mut Self>,
173 encoder: &mut E,
174 slot: Slot<'_, Self::EncodedOption>,
175 ) -> Result<(), EncodeError> {
176 if let Some(value) = this {
177 encoder.encode_next(value)?;
178 WireBox::encode_present(slot);
179 } else {
180 WireBox::encode_absent(slot);
181 }
182
183 Ok(())
184 }
185 }
186 };
187}
188
189macro_rules! impl_encode_for_primitives {
190 ($($ty:ty, $enc:ty);* $(;)?) => {
191 $(
192 impl_encode_for_primitive!($ty, $enc);
193 )*
194 }
195}
196
197impl_encode_for_primitives! {
198 (), (); bool, bool; i8, i8; u8, u8;
199
200 i16, WireI16; i32, WireI32; i64, WireI64;
201 u16, WireU16; u32, WireU32; u64, WireU64;
202 f32, WireF32; f64, WireF64;
203
204 WireI16, WireI16; WireI32, WireI32; WireI64, WireI64;
205 WireU16, WireU16; WireU32, WireU32; WireU64, WireU64;
206 WireF32, WireF32; WireF64, WireF64;
207}
208
209impl<T: Encodable, const N: usize> Encodable for [T; N] {
210 const COPY_OPTIMIZATION: CopyOptimization<Self> =
211 unsafe { CopyOptimization::enable_if(T::COPY_OPTIMIZATION.is_enabled()) };
212
213 type Encoded = [T::Encoded; N];
214}
215
216impl<E: ?Sized, T: Encode<E>, const N: usize> Encode<E> for [T; N] {
217 fn encode(
218 &mut self,
219 encoder: &mut E,
220 mut slot: Slot<'_, Self::Encoded>,
221 ) -> Result<(), EncodeError> {
222 if T::COPY_OPTIMIZATION.is_enabled() {
223 unsafe {
225 copy_nonoverlapping(self.as_ptr().cast(), slot.as_mut_ptr(), 1);
226 }
227 } else {
228 for (i, item) in self.iter_mut().enumerate() {
229 item.encode(encoder, slot.index(i))?;
230 }
231 }
232 Ok(())
233 }
234}
235
236impl<T: Encodable> Encodable for Box<T> {
237 type Encoded = T::Encoded;
238}
239
240impl<E: ?Sized, T: Encode<E>> Encode<E> for Box<T> {
241 fn encode(
242 &mut self,
243 encoder: &mut E,
244 slot: Slot<'_, Self::Encoded>,
245 ) -> Result<(), EncodeError> {
246 T::encode(self, encoder, slot)
247 }
248}
249
250#[cfg(test)]
251mod tests {
252 use crate::chunks;
253 use crate::testing::assert_encoded;
254
255 #[test]
256 fn encode_bool() {
257 assert_encoded(true, &chunks![0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
258 assert_encoded(false, &chunks![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
259 }
260
261 #[test]
262 fn encode_ints() {
263 assert_encoded(0xa3u8, &chunks![0xa3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
264 assert_encoded(-0x45i8, &chunks![0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
265
266 assert_encoded(0x1234u16, &chunks![0x34, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
267 assert_encoded(-0x1234i16, &chunks![0xcc, 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
268
269 assert_encoded(0x12345678u32, &chunks![0x78, 0x56, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00]);
270 assert_encoded(-0x12345678i32, &chunks![0x88, 0xa9, 0xcb, 0xed, 0x00, 0x00, 0x00, 0x00]);
271
272 assert_encoded(
273 0x123456789abcdef0u64,
274 &chunks![0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12],
275 );
276 assert_encoded(
277 -0x123456789abcdef0i64,
278 &chunks![0x10, 0x21, 0x43, 0x65, 0x87, 0xa9, 0xcb, 0xed],
279 );
280 }
281
282 #[test]
283 fn encode_floats() {
284 assert_encoded(
285 ::core::f32::consts::PI,
286 &chunks![0xdb, 0x0f, 0x49, 0x40, 0x00, 0x00, 0x00, 0x00],
287 );
288 assert_encoded(
289 ::core::f64::consts::PI,
290 &chunks![0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40],
291 );
292 }
293
294 #[test]
295 fn encode_box() {
296 assert_encoded(None::<u64>, &chunks![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
297 assert_encoded(
298 Some(0x123456789abcdef0u64),
299 &chunks![
300 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56,
301 0x34, 0x12,
302 ],
303 );
304 }
305
306 #[test]
307 fn encode_vec() {
308 assert_encoded(
309 None::<Vec<u32>>,
310 &chunks![
311 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
312 0x00, 0x00,
313 ],
314 );
315 assert_encoded(
316 Some(vec![0x12345678u32, 0x9abcdef0u32]),
317 &chunks![
318 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
319 0xff, 0xff, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a,
320 ],
321 );
322 assert_encoded(
323 Some(Vec::<u32>::new()),
324 &chunks![
325 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
326 0xff, 0xff,
327 ],
328 );
329 }
330
331 #[test]
332 fn encode_string() {
333 assert_encoded(
334 None::<String>,
335 &chunks![
336 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
337 0x00, 0x00,
338 ],
339 );
340 assert_encoded(
341 Some("0123".to_string()),
342 &chunks![
343 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
344 0xff, 0xff, 0x30, 0x31, 0x32, 0x33, 0x00, 0x00, 0x00, 0x00,
345 ],
346 );
347 assert_encoded(
348 Some(String::new()),
349 &chunks![
350 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
351 0xff, 0xff,
352 ],
353 );
354 }
355}