1mod error;
8
9use core::mem::MaybeUninit;
10use core::ptr::copy_nonoverlapping;
11
12pub use self::error::EncodeError;
13
14use crate::{
15 Constrained, CopyOptimization, Encoder, EncoderExt as _, WireBox, WireF32, WireF64, WireI16,
16 WireI32, WireI64, WireU16, WireU32, WireU64,
17};
18
19pub unsafe trait Encode<W: Constrained, E: ?Sized>: Sized {
25 const COPY_OPTIMIZATION: CopyOptimization<Self, W> = CopyOptimization::disable();
30
31 fn encode(
33 self,
34 encoder: &mut E,
35 out: &mut MaybeUninit<W>,
36 constraint: W::Constraint,
37 ) -> Result<(), EncodeError>;
38}
39
40pub unsafe trait EncodeOption<W: Constrained, E: ?Sized>: Sized {
46 fn encode_option(
48 this: Option<Self>,
49 encoder: &mut E,
50 out: &mut MaybeUninit<W>,
51 constraint: W::Constraint,
52 ) -> Result<(), EncodeError>;
53}
54
55unsafe impl<W, E, T> Encode<W, E> for Box<T>
56where
57 W: Constrained,
58 E: ?Sized,
59 T: Encode<W, E>,
60{
61 fn encode(
62 self,
63 encoder: &mut E,
64 out: &mut MaybeUninit<W>,
65 constraint: <W as Constrained>::Constraint,
66 ) -> Result<(), EncodeError> {
67 T::encode(*self, encoder, out, constraint)
68 }
69}
70
71unsafe impl<'a, W, E, T> Encode<W, E> for &'a Box<T>
72where
73 W: Constrained,
74 E: ?Sized,
75 &'a T: Encode<W, E>,
76{
77 fn encode(
78 self,
79 encoder: &mut E,
80 out: &mut MaybeUninit<W>,
81 constraint: <W as Constrained>::Constraint,
82 ) -> Result<(), EncodeError> {
83 <&'a T>::encode(self, encoder, out, constraint)
84 }
85}
86
87unsafe impl<W, E, T> EncodeOption<W, E> for Box<T>
88where
89 W: Constrained,
90 E: ?Sized,
91 T: EncodeOption<W, E>,
92{
93 fn encode_option(
94 this: Option<Self>,
95 encoder: &mut E,
96 out: &mut MaybeUninit<W>,
97 constraint: <W as Constrained>::Constraint,
98 ) -> Result<(), EncodeError> {
99 T::encode_option(this.map(|value| *value), encoder, out, constraint)
100 }
101}
102
103unsafe impl<'a, W, E, T> EncodeOption<W, E> for &'a Box<T>
104where
105 W: Constrained,
106 E: ?Sized,
107 &'a T: EncodeOption<W, E>,
108{
109 fn encode_option(
110 this: Option<Self>,
111 encoder: &mut E,
112 out: &mut MaybeUninit<W>,
113 constraint: <W as Constrained>::Constraint,
114 ) -> Result<(), EncodeError> {
115 <&'a T>::encode_option(this.map(|value| &**value), encoder, out, constraint)
116 }
117}
118
119macro_rules! impl_primitive {
120 ($ty:ty) => {
121 impl_primitive!($ty, $ty);
122 };
123 ($ty:ty, $enc:ty) => {
124 unsafe impl<E: ?Sized> Encode<$enc, E> for $ty {
125 const COPY_OPTIMIZATION: CopyOptimization<$ty, $enc> =
126 CopyOptimization::<$ty, $enc>::PRIMITIVE;
127
128 #[inline]
129 fn encode(
130 self,
131 encoder: &mut E,
132 out: &mut MaybeUninit<$enc>,
133 constraint: <$enc as Constrained>::Constraint,
134 ) -> Result<(), EncodeError> {
135 Encode::encode(&self, encoder, out, constraint)
136 }
137 }
138
139 unsafe impl<'a, E: ?Sized> Encode<$enc, E> for &'a $ty {
140 #[inline]
141 fn encode(
142 self,
143 _: &mut E,
144 out: &mut MaybeUninit<$enc>,
145 _constraint: <$enc as Constrained>::Constraint,
146 ) -> Result<(), EncodeError> {
147 out.write(<$enc>::from(*self));
148 Ok(())
149 }
150 }
151
152 unsafe impl<E: Encoder + ?Sized> EncodeOption<WireBox<'static, $enc>, E> for $ty {
153 #[inline]
154 fn encode_option(
155 this: Option<Self>,
156 encoder: &mut E,
157 out: &mut MaybeUninit<WireBox<'static, $enc>>,
158 constraint: (),
159 ) -> Result<(), EncodeError> {
160 if let Some(value) = this {
161 encoder.encode_next(value, constraint)?;
162 WireBox::encode_present(out);
163 } else {
164 WireBox::encode_absent(out);
165 }
166
167 Ok(())
168 }
169 }
170
171 unsafe impl<E: Encoder + ?Sized> EncodeOption<WireBox<'static, $enc>, E> for &$ty {
172 #[inline]
173 fn encode_option(
174 this: Option<Self>,
175 encoder: &mut E,
176 out: &mut MaybeUninit<WireBox<'static, $enc>>,
177 constraint: (),
178 ) -> Result<(), EncodeError> {
179 <$ty>::encode_option(this.cloned(), encoder, out, constraint)
180 }
181 }
182 };
183}
184
185macro_rules! impl_primitives {
186 ($($ty:ty $(, $enc:ty)?);* $(;)?) => {
187 $(
188 impl_primitive!($ty $(, $enc)?);
189 )*
190 }
191}
192
193impl_primitives! {
194 ();
195
196 bool;
197
198 i8;
199 i16, WireI16; i32, WireI32; i64, WireI64;
200 WireI16; WireI32; WireI64;
201
202 u8;
203 u16, WireU16; u32, WireU32; u64, WireU64;
204 WireU16; WireU32; WireU64;
205
206 f32, WireF32; f64, WireF64;
207 WireF32; WireF64;
208}
209
210fn encode_to_array<A, W, E, T, const N: usize>(
211 value: A,
212 encoder: &mut E,
213 out: &mut MaybeUninit<[W; N]>,
214 constraint: <W as Constrained>::Constraint,
215) -> Result<(), EncodeError>
216where
217 A: AsRef<[T]> + IntoIterator,
218 A::Item: Encode<W, E>,
219 W: Constrained,
220 E: ?Sized,
221 T: Encode<W, E>,
222{
223 if T::COPY_OPTIMIZATION.is_enabled() {
224 unsafe {
226 copy_nonoverlapping(value.as_ref().as_ptr().cast(), out.as_mut_ptr(), 1);
227 }
228 } else {
229 for (i, item) in value.into_iter().enumerate() {
230 let out_i = unsafe { &mut *out.as_mut_ptr().cast::<MaybeUninit<W>>().add(i) };
240 item.encode(encoder, out_i, constraint)?;
241 }
242 }
243 Ok(())
244}
245
246unsafe impl<W, E, T, const N: usize> Encode<[W; N], E> for [T; N]
247where
248 W: Constrained,
249 E: ?Sized,
250 T: Encode<W, E>,
251{
252 const COPY_OPTIMIZATION: CopyOptimization<Self, [W; N]> = T::COPY_OPTIMIZATION.infer_array();
253
254 fn encode(
255 self,
256 encoder: &mut E,
257 out: &mut MaybeUninit<[W; N]>,
258 constraint: <W as Constrained>::Constraint,
259 ) -> Result<(), EncodeError> {
260 encode_to_array(self, encoder, out, constraint)
261 }
262}
263
264unsafe impl<'a, W, E, T, const N: usize> Encode<[W; N], E> for &'a [T; N]
265where
266 W: Constrained,
267 E: ?Sized,
268 T: Encode<W, E>,
269 &'a T: Encode<W, E>,
270{
271 fn encode(
272 self,
273 encoder: &mut E,
274 out: &mut MaybeUninit<[W; N]>,
275 constraint: <W as Constrained>::Constraint,
276 ) -> Result<(), EncodeError> {
277 encode_to_array(self, encoder, out, constraint)
278 }
279}
280
281unsafe impl<W, E, T> Encode<W, E> for Option<T>
282where
283 W: Constrained,
284 E: ?Sized,
285 T: EncodeOption<W, E>,
286{
287 fn encode(
288 self,
289 encoder: &mut E,
290 out: &mut MaybeUninit<W>,
291 constraint: <W as Constrained>::Constraint,
292 ) -> Result<(), EncodeError> {
293 T::encode_option(self, encoder, out, constraint)
294 }
295}
296
297unsafe impl<'a, W, E, T> Encode<W, E> for &'a Option<T>
298where
299 W: Constrained,
300 E: ?Sized,
301 Option<&'a T>: Encode<W, E>,
302{
303 fn encode(
304 self,
305 encoder: &mut E,
306 out: &mut MaybeUninit<W>,
307 constraint: <W as Constrained>::Constraint,
308 ) -> Result<(), EncodeError> {
309 self.as_ref().encode(encoder, out, constraint)
310 }
311}
312
313#[cfg(test)]
314mod tests {
315 use crate::chunks;
316 use crate::testing::{assert_encoded, assert_encoded_with_constraint};
317
318 #[test]
319 fn encode_unit() {
320 assert_encoded((), &chunks![]);
321 }
322
323 #[test]
324 fn encode_bool() {
325 assert_encoded(true, &chunks![0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
326 assert_encoded(false, &chunks![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
327 }
328
329 #[test]
330 fn encode_ints() {
331 assert_encoded(0xa3u8, &chunks![0xa3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
332 assert_encoded(-0x45i8, &chunks![0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
333
334 assert_encoded(0x1234u16, &chunks![0x34, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
335 assert_encoded(-0x1234i16, &chunks![0xcc, 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
336
337 assert_encoded(0x12345678u32, &chunks![0x78, 0x56, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00]);
338 assert_encoded(-0x12345678i32, &chunks![0x88, 0xa9, 0xcb, 0xed, 0x00, 0x00, 0x00, 0x00]);
339
340 assert_encoded(
341 0x123456789abcdef0u64,
342 &chunks![0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12],
343 );
344 assert_encoded(
345 -0x123456789abcdef0i64,
346 &chunks![0x10, 0x21, 0x43, 0x65, 0x87, 0xa9, 0xcb, 0xed],
347 );
348 }
349
350 #[test]
351 fn encode_floats() {
352 assert_encoded(
353 ::core::f32::consts::PI,
354 &chunks![0xdb, 0x0f, 0x49, 0x40, 0x00, 0x00, 0x00, 0x00],
355 );
356 assert_encoded(
357 ::core::f64::consts::PI,
358 &chunks![0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40],
359 );
360 }
361
362 #[test]
363 fn encode_box() {
364 assert_encoded(None::<u64>, &chunks![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
365 assert_encoded(
366 Some(0x123456789abcdef0u64),
367 &chunks![
368 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56,
369 0x34, 0x12,
370 ],
371 );
372 }
373
374 #[test]
375 fn encode_vec() {
376 assert_encoded_with_constraint::<crate::WireOptionalVector<'_, crate::WireU32>, _>(
377 None::<Vec<u32>>,
378 &chunks![
379 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
380 0x00, 0x00,
381 ],
382 (1000, ()),
383 );
384 assert_encoded_with_constraint::<crate::WireOptionalVector<'_, crate::WireU32>, _>(
385 Some(vec![0x12345678u32, 0x9abcdef0u32]),
386 &chunks![
387 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
388 0xff, 0xff, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a,
389 ],
390 (1000, ()),
391 );
392 assert_encoded_with_constraint::<crate::WireOptionalVector<'_, crate::WireU32>, _>(
393 Some(Vec::<u32>::new()),
394 &chunks![
395 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
396 0xff, 0xff,
397 ],
398 (1000, ()),
399 );
400 }
401
402 #[test]
403 fn encode_string() {
404 assert_encoded_with_constraint::<crate::WireOptionalString<'_>, _>(
405 None::<String>,
406 &chunks![
407 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
408 0x00, 0x00,
409 ],
410 1000,
411 );
412 assert_encoded_with_constraint::<crate::WireOptionalString<'_>, _>(
413 Some("0123".to_string()),
414 &chunks![
415 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
416 0xff, 0xff, 0x30, 0x31, 0x32, 0x33, 0x00, 0x00, 0x00, 0x00,
417 ],
418 1000,
419 );
420 assert_encoded_with_constraint::<crate::WireOptionalString<'_>, _>(
421 Some(String::new()),
422 &chunks![
423 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
424 0xff, 0xff,
425 ],
426 1000,
427 );
428 }
429}