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