Skip to main content

fidl_next_codec/wire/
primitives.rs

1// Copyright 2025 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#[cfg(not(target_endian = "little"))]
6compile_error!("only little-endian targets are supported by FIDL");
7
8// Standard library traits
9
10macro_rules! impl_unop {
11    ($trait:ident:: $fn:ident for $name:ident : $prim:ty) => {
12        impl ::core::ops::$trait for $name {
13            type Output = <$prim as ::core::ops::$trait>::Output;
14
15            #[inline]
16            fn $fn(self) -> Self::Output {
17                self.0.$fn()
18            }
19        }
20    };
21}
22
23macro_rules! impl_binop_one {
24    ($trait:ident:: $fn:ident($self:ty, $other:ty) -> $output:ty) => {
25        impl ::core::ops::$trait<$other> for $self {
26            type Output = $output;
27
28            #[inline]
29            fn $fn(self, other: $other) -> Self::Output {
30                self.0.$fn(other.0)
31            }
32        }
33    };
34}
35
36macro_rules! impl_binop_both {
37    ($trait:ident:: $fn:ident($self:ty, $other:ty) -> $output:ty) => {
38        impl ::core::ops::$trait<$other> for $self {
39            type Output = $output;
40
41            #[inline]
42            fn $fn(self, other: $other) -> Self::Output {
43                self.0.$fn(other)
44            }
45        }
46
47        impl ::core::ops::$trait<$self> for $other {
48            type Output = $output;
49
50            #[inline]
51            fn $fn(self, other: $self) -> Self::Output {
52                self.$fn(other.0)
53            }
54        }
55    };
56}
57
58macro_rules! impl_binop {
59    ($trait:ident::$fn:ident for $name:ident: $prim:ty) => {
60        impl_binop_both!($trait::$fn ($name, $prim) -> $prim);
61        impl_binop_both!($trait::$fn (&'_ $name, $prim) -> $prim);
62        impl_binop_both!($trait::$fn ($name, &'_ $prim) -> $prim);
63        impl_binop_both!($trait::$fn (&'_ $name, &'_ $prim) -> $prim);
64
65        impl_binop_one!($trait::$fn ($name, $name) -> $prim);
66        impl_binop_one!($trait::$fn (&'_ $name, $name) -> $prim);
67        impl_binop_one!($trait::$fn ($name, &'_ $name) -> $prim);
68        impl_binop_one!($trait::$fn (&'_ $name, &'_ $name) -> $prim);
69    };
70}
71
72macro_rules! impl_binassign {
73    ($trait:ident:: $fn:ident for $name:ident : $prim:ty) => {
74        impl ::core::ops::$trait<$prim> for $name {
75            #[inline]
76            fn $fn(&mut self, other: $prim) {
77                let mut value = self.0;
78                value.$fn(other);
79                *self = Self(value);
80            }
81        }
82
83        impl ::core::ops::$trait<$name> for $name {
84            #[inline]
85            fn $fn(&mut self, other: $name) {
86                let mut value = self.0;
87                value.$fn(other.0);
88                *self = Self(value);
89            }
90        }
91
92        impl ::core::ops::$trait<&'_ $prim> for $name {
93            #[inline]
94            fn $fn(&mut self, other: &'_ $prim) {
95                let mut value = self.0;
96                value.$fn(other);
97                *self = Self(value);
98            }
99        }
100
101        impl ::core::ops::$trait<&'_ $name> for $name {
102            #[inline]
103            fn $fn(&mut self, other: &'_ $name) {
104                let mut value = self.0;
105                value.$fn(other.0);
106                *self = Self(value);
107            }
108        }
109    };
110}
111
112macro_rules! impl_clone_and_copy {
113    (for $name:ident) => {
114        impl Clone for $name {
115            #[inline]
116            fn clone(&self) -> Self {
117                *self
118            }
119        }
120
121        impl Copy for $name {}
122    };
123}
124
125macro_rules! impl_fmt {
126    ($trait:ident for $name:ident) => {
127        impl ::core::fmt::$trait for $name {
128            #[inline]
129            fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
130                ::core::fmt::$trait::fmt(&self.0, f)
131            }
132        }
133    };
134}
135
136macro_rules! impl_default {
137    (for $name:ident : $prim:ty) => {
138        impl Default for $name {
139            #[inline]
140            fn default() -> Self {
141                Self(<$prim>::default())
142            }
143        }
144    };
145}
146
147macro_rules! impl_from {
148    (for $name:ident : $prim:ty) => {
149        impl From<$prim> for $name {
150            fn from(value: $prim) -> Self {
151                Self(value)
152            }
153        }
154
155        impl<'a> From<&'a $prim> for $name {
156            fn from(value: &'a $prim) -> Self {
157                Self(*value)
158            }
159        }
160
161        impl From<$name> for $prim {
162            fn from(value: $name) -> Self {
163                value.0
164            }
165        }
166
167        impl<'a> From<&'a $name> for $prim {
168            fn from(value: &'a $name) -> Self {
169                value.0
170            }
171        }
172    };
173}
174
175macro_rules! impl_try_from_ptr_size {
176    ($size:ident for $name:ident: $prim:ident) => {
177        impl TryFrom<$size> for $name {
178            type Error = <$prim as TryFrom<$size>>::Error;
179
180            #[inline]
181            fn try_from(value: $size) -> Result<Self, Self::Error> {
182                Ok(Self(<$prim>::try_from(value)?))
183            }
184        }
185
186        impl_try_into_ptr_size!($size for $name: $prim);
187    };
188}
189
190macro_rules! impl_try_into_ptr_size {
191    (isize for $name:ident: i16) => {
192        impl_into_ptr_size!(isize for $name);
193    };
194
195    (usize for $name:ident: u16) => {
196        impl_into_ptr_size!(usize for $name);
197    };
198
199    ($size:ident for $name:ident: $prim:ident) => {
200        impl TryFrom<$name> for $size {
201            type Error = <$size as TryFrom<$prim>>::Error;
202
203            #[inline]
204            fn try_from(value: $name) -> Result<Self, Self::Error> {
205                <$size>::try_from(value.0)
206            }
207        }
208    };
209}
210
211macro_rules! impl_into_ptr_size {
212    ($size:ident for $name:ident) => {
213        impl From<$name> for $size {
214            #[inline]
215            fn from(value: $name) -> Self {
216                <$size>::from(value.0)
217            }
218        }
219    };
220}
221
222macro_rules! impl_hash {
223    (for $name:ident) => {
224        impl core::hash::Hash for $name {
225            fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
226                self.0.hash(state);
227            }
228        }
229    };
230}
231
232macro_rules! impl_partial_ord_and_ord {
233    (for $name:ident : $prim:ty) => {
234        impl PartialOrd for $name {
235            #[inline]
236            fn partial_cmp(&self, other: &Self) -> Option<::core::cmp::Ordering> {
237                Some(self.cmp(other))
238            }
239        }
240
241        impl PartialOrd<$prim> for $name {
242            #[inline]
243            fn partial_cmp(&self, other: &$prim) -> Option<::core::cmp::Ordering> {
244                self.0.partial_cmp(other)
245            }
246        }
247
248        impl Ord for $name {
249            #[inline]
250            fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
251                self.0.cmp(&other.0)
252            }
253        }
254    };
255}
256
257macro_rules! impl_partial_eq_and_eq {
258    (for $name:ident : $prim:ty) => {
259        impl PartialEq for $name {
260            #[inline]
261            fn eq(&self, other: &Self) -> bool {
262                let lhs = self.0;
263                let rhs = other.0;
264                lhs.eq(&rhs)
265            }
266        }
267
268        impl PartialEq<$prim> for $name {
269            #[inline]
270            fn eq(&self, other: &$prim) -> bool {
271                self.0.eq(other)
272            }
273        }
274
275        impl Eq for $name {}
276    };
277}
278
279macro_rules! impl_partial_ord {
280    (for $name:ident : $prim:ty) => {
281        impl PartialOrd for $name {
282            #[inline]
283            fn partial_cmp(&self, other: &Self) -> Option<::core::cmp::Ordering> {
284                self.0.partial_cmp(&other.0)
285            }
286        }
287
288        impl PartialOrd<$prim> for $name {
289            #[inline]
290            fn partial_cmp(&self, other: &$prim) -> Option<::core::cmp::Ordering> {
291                self.0.partial_cmp(other)
292            }
293        }
294    };
295}
296
297macro_rules! impl_product_and_sum {
298    (for $name:ident) => {
299        impl ::core::iter::Product for $name {
300            #[inline]
301            fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
302                Self(iter.map(|x| x.0).product())
303            }
304        }
305
306        impl ::core::iter::Sum for $name {
307            #[inline]
308            fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
309                Self(iter.map(|x| x.0).sum())
310            }
311        }
312    };
313}
314
315macro_rules! impl_fidl_convert {
316    (for $name:ty : $prim:ty) => {
317        impl $crate::FromWire<$name> for $prim {
318            const COPY_OPTIMIZATION: $crate::CopyOptimization<$name, $prim> =
319                $crate::CopyOptimization::<$name, $prim>::PRIMITIVE;
320
321            #[inline]
322            fn from_wire(wire: $name) -> Self {
323                wire.into()
324            }
325        }
326
327        impl $crate::FromWireRef<$name> for $prim {
328            #[inline]
329            fn from_wire_ref(wire: &$name) -> Self {
330                (*wire).into()
331            }
332        }
333
334        impl $crate::IntoNatural for $name {
335            type Natural = $prim;
336        }
337    };
338}
339
340macro_rules! impl_fidl_constrained {
341    (for $name:ty) => {
342        impl $crate::Constrained for $name {
343            type Constraint = ();
344
345            fn validate(
346                _: $crate::Slot<'_, Self>,
347                _: Self::Constraint,
348            ) -> Result<(), $crate::ValidationError> {
349                Ok(())
350            }
351        }
352    };
353}
354
355macro_rules! impl_fidl_copy_optimize {
356    (for $name:ty) => {
357        impl $crate::CopyOptimization<$name, $name> {
358            /// Whether copy optimization between the two primitive types is
359            /// enabled.
360            pub const PRIMITIVE: Self = Self::identity();
361        }
362    };
363
364    (for $name:ty : $prim:ty) => {
365        impl_fidl_copy_optimize!(for $name);
366
367        impl $crate::CopyOptimization<$prim, $name> {
368            /// Whether copy optimization between the two primitive types is
369            /// enabled.
370            pub const PRIMITIVE: Self =
371                // SAFETY: Copy optimization for primitives is enabled if their
372                // size <= 1 or the target is little-endian.
373                unsafe {
374                    $crate::CopyOptimization::enable_if(
375                        size_of::<Self>() <= 1 || cfg!(target_endian = "little"),
376                    )
377                };
378        }
379
380        impl $crate::CopyOptimization<$name, $prim> {
381            /// Whether copy optimization between the two primitive types is
382            /// enabled.
383            pub const PRIMITIVE: Self =
384                // SAFETY: Copy optimization between these two primitives is
385                // commutative.
386                unsafe {
387                    $crate::CopyOptimization::enable_if(
388                        $crate::CopyOptimization::<$prim, $name>::PRIMITIVE.is_enabled(),
389                    )
390                };
391        }
392    }
393}
394
395macro_rules! impl_fidl_decode {
396    (for $name:ty) => {
397        // SAFETY: Primitives have no validation constraints and their wire representation
398        // is identical to their Rust representation, so decoding is a no-op.
399        unsafe impl<D: ?Sized> $crate::Decode<D> for $name {
400            #[inline]
401            fn decode(
402                _: $crate::Slot<'_, Self>,
403                _: &mut D,
404                _: (),
405            ) -> Result<(), $crate::DecodeError> {
406                Ok(())
407            }
408        }
409    };
410}
411
412macro_rules! impl_fidl_encode {
413    (for $name:ty : $prim:ty) => {
414        // SAFETY: Encoding a primitive writes its value directly to the output slot.
415        unsafe impl<E: ?Sized> $crate::Encode<$name, E> for $prim {
416            const COPY_OPTIMIZATION: $crate::CopyOptimization<$prim, $name> =
417                $crate::CopyOptimization::<$prim, $name>::PRIMITIVE;
418
419            #[inline]
420            fn encode(
421                self,
422                encoder: &mut E,
423                out: &mut ::core::mem::MaybeUninit<$name>,
424                constraint: <$name as $crate::Constrained>::Constraint,
425            ) -> Result<(), $crate::EncodeError> {
426                $crate::Encode::encode(&self, encoder, out, constraint)
427            }
428        }
429
430        // SAFETY: Encoding a primitive reference writes its value directly to the output slot.
431        unsafe impl<E: ?Sized> $crate::Encode<$name, E> for &$prim {
432            #[inline]
433            fn encode(
434                self,
435                _: &mut E,
436                out: &mut ::core::mem::MaybeUninit<$name>,
437                _: <$name as $crate::Constrained>::Constraint,
438            ) -> Result<(), $crate::EncodeError> {
439                out.write(<$name>::from(*self));
440                Ok(())
441            }
442        }
443
444        // SAFETY: Encoding an optional primitive delegates to `Box::encode_present` or
445        // `Box::encode_absent` which are safe.
446        unsafe impl<E> $crate::EncodeOption<$crate::wire::Box<'static, $name>, E> for $prim
447        where
448            E: $crate::Encoder + ?Sized,
449        {
450            #[inline]
451            fn encode_option(
452                this: Option<Self>,
453                encoder: &mut E,
454                out: &mut ::core::mem::MaybeUninit<$crate::wire::Box<'static, $name>>,
455                constraint: <$name as $crate::Constrained>::Constraint,
456            ) -> Result<(), $crate::EncodeError> {
457                if let Some(value) = this {
458                    $crate::EncoderExt::encode_next_with_constraint(encoder, value, constraint)?;
459                    $crate::wire::Box::encode_present(out);
460                } else {
461                    $crate::wire::Box::encode_absent(out);
462                }
463
464                Ok(())
465            }
466        }
467
468        // SAFETY: Encoding an optional primitive reference delegates to the value implementation.
469        unsafe impl<E> $crate::EncodeOption<$crate::wire::Box<'static, $name>, E> for &$prim
470        where
471            E: $crate::Encoder + ?Sized,
472        {
473            #[inline]
474            fn encode_option(
475                this: Option<Self>,
476                encoder: &mut E,
477                out: &mut ::core::mem::MaybeUninit<$crate::wire::Box<'static, $name>>,
478                constraint: <$name as $crate::Constrained>::Constraint,
479            ) -> Result<(), $crate::EncodeError> {
480                <$prim>::encode_option(this.cloned(), encoder, out, constraint)
481            }
482        }
483    };
484}
485
486macro_rules! impl_fidl_wire {
487    (for $name:ty) => {
488        // SAFETY: Primitives have stable layout and no padding.
489        unsafe impl $crate::Wire for $name {
490            type Narrowed<'de> = Self;
491
492            #[inline]
493            fn zero_padding(_: &mut ::core::mem::MaybeUninit<Self>) {}
494        }
495    };
496}
497
498// Builtins
499
500macro_rules! impl_builtin_primitive {
501    (for $name:ty) => {
502        impl_fidl_convert!(for $name : $name);
503        impl_fidl_constrained!(for $name);
504        impl_fidl_copy_optimize!(for $name);
505        impl_fidl_decode!(for $name);
506        impl_fidl_encode!(for $name : $name);
507        impl_fidl_wire!(for $name);
508    };
509}
510
511impl_builtin_primitive!(for u8);
512impl_builtin_primitive!(for i8);
513
514// Bool
515
516impl_fidl_convert!(for bool: bool);
517impl_fidl_constrained!(for bool);
518impl_fidl_copy_optimize!(for bool);
519
520// SAFETY: `bool` is decoded by reading a byte and validating it is 0 or 1.
521unsafe impl<D: ?Sized> crate::Decode<D> for bool {
522    #[inline]
523    fn decode(slot: crate::Slot<'_, Self>, _: &mut D, _: ()) -> Result<(), crate::DecodeError> {
524        // SAFETY: `slot` is guaranteed to contain a valid `bool` (1 byte).
525        let value = unsafe { slot.as_ptr().cast::<u8>().read() };
526        match value {
527            0 | 1 => Ok(()),
528            invalid => Err(crate::DecodeError::InvalidBool(invalid)),
529        }
530    }
531}
532
533impl_fidl_encode!(for bool: bool);
534impl_fidl_wire!(for bool);
535
536// Integers
537
538macro_rules! impl_signed_integer_traits {
539    ($name:ident: $prim:ident) => {
540        impl_binop!(Add::add for $name: $prim);
541        impl_binassign!(AddAssign::add_assign for $name: $prim);
542        impl_clone_and_copy!(for $name);
543        impl_fmt!(Binary for $name);
544        impl_binop!(BitAnd::bitand for $name: $prim);
545        impl_binassign!(BitAndAssign::bitand_assign for $name: $prim);
546        impl_binop!(BitOr::bitor for $name: $prim);
547        impl_binassign!(BitOrAssign::bitor_assign for $name: $prim);
548        impl_binop!(BitXor::bitxor for $name: $prim);
549        impl_binassign!(BitXorAssign::bitxor_assign for $name: $prim);
550        impl_fmt!(Debug for $name);
551        impl_default!(for $name: $prim);
552        impl_fmt!(Display for $name);
553        impl_binop!(Div::div for $name: $prim);
554        impl_binassign!(DivAssign::div_assign for $name: $prim);
555        impl_from!(for $name: $prim);
556        impl_try_from_ptr_size!(isize for $name: $prim);
557        impl_hash!(for $name);
558        impl_fmt!(LowerExp for $name);
559        impl_fmt!(LowerHex for $name);
560        impl_binop!(Mul::mul for $name: $prim);
561        impl_binassign!(MulAssign::mul_assign for $name: $prim);
562        impl_unop!(Neg::neg for $name: $prim);
563        impl_unop!(Not::not for $name: $prim);
564        impl_fmt!(Octal for $name);
565        impl_partial_eq_and_eq!(for $name: $prim);
566        impl_partial_ord_and_ord!(for $name: $prim);
567        impl_product_and_sum!(for $name);
568        impl_binop!(Rem::rem for $name: $prim);
569        impl_binassign!(RemAssign::rem_assign for $name: $prim);
570        impl_binop!(Shl::shl for $name: $prim);
571        impl_binassign!(ShlAssign::shl_assign for $name: $prim);
572        impl_binop!(Shr::shr for $name: $prim);
573        impl_binassign!(ShrAssign::shr_assign for $name: $prim);
574        impl_binop!(Sub::sub for $name: $prim);
575        impl_binassign!(SubAssign::sub_assign for $name: $prim);
576        impl_fmt!(UpperExp for $name);
577        impl_fmt!(UpperHex for $name);
578
579        impl_fidl_convert!(for $name: $prim);
580        impl_fidl_constrained!(for $name);
581        impl_fidl_copy_optimize!(for $name: $prim);
582        impl_fidl_decode!(for $name);
583        impl_fidl_encode!(for $name: $prim);
584        impl_fidl_encode!(for $name: $name);
585        impl_fidl_wire!(for $name);
586    };
587}
588
589macro_rules! impl_unsigned_integer_traits {
590    ($name:ident: $prim:ident) => {
591        impl_binop!(Add::add for $name: $prim);
592        impl_binassign!(AddAssign::add_assign for $name: $prim);
593        impl_clone_and_copy!(for $name);
594        impl_fmt!(Binary for $name);
595        impl_binop!(BitAnd::bitand for $name: $prim);
596        impl_binassign!(BitAndAssign::bitand_assign for $name: $prim);
597        impl_binop!(BitOr::bitor for $name: $prim);
598        impl_binassign!(BitOrAssign::bitor_assign for $name: $prim);
599        impl_binop!(BitXor::bitxor for $name: $prim);
600        impl_binassign!(BitXorAssign::bitxor_assign for $name: $prim);
601        impl_fmt!(Debug for $name);
602        impl_default!(for $name: $prim);
603        impl_fmt!(Display for $name);
604        impl_binop!(Div::div for $name: $prim);
605        impl_binassign!(DivAssign::div_assign for $name: $prim);
606        impl_from!(for $name: $prim);
607        impl_try_from_ptr_size!(usize for $name: $prim);
608        impl_hash!(for $name);
609        impl_fmt!(LowerExp for $name);
610        impl_fmt!(LowerHex for $name);
611        impl_binop!(Mul::mul for $name: $prim);
612        impl_binassign!(MulAssign::mul_assign for $name: $prim);
613        impl_unop!(Not::not for $name: $prim);
614        impl_fmt!(Octal for $name);
615        impl_partial_eq_and_eq!(for $name: $prim);
616        impl_partial_ord_and_ord!(for $name: $prim);
617        impl_product_and_sum!(for $name);
618        impl_binop!(Rem::rem for $name: $prim);
619        impl_binassign!(RemAssign::rem_assign for $name: $prim);
620        impl_binop!(Shl::shl for $name: $prim);
621        impl_binassign!(ShlAssign::shl_assign for $name: $prim);
622        impl_binop!(Shr::shr for $name: $prim);
623        impl_binassign!(ShrAssign::shr_assign for $name: $prim);
624        impl_binop!(Sub::sub for $name: $prim);
625        impl_binassign!(SubAssign::sub_assign for $name: $prim);
626        impl_fmt!(UpperExp for $name);
627        impl_fmt!(UpperHex for $name);
628
629        impl_fidl_convert!(for $name: $prim);
630        impl_fidl_constrained!(for $name);
631        impl_fidl_copy_optimize!(for $name: $prim);
632        impl_fidl_decode!(for $name);
633        impl_fidl_encode!(for $name: $prim);
634        impl_fidl_encode!(for $name: $name);
635        impl_fidl_wire!(for $name);
636    };
637}
638
639macro_rules! impl_float_traits {
640    ($name:ident: $prim:ty) => {
641        impl_binop!(Add::add for $name: $prim);
642        impl_binassign!(AddAssign::add_assign for $name: $prim);
643        impl_clone_and_copy!(for $name);
644        impl_fmt!(Debug for $name);
645        impl_default!(for $name: $prim);
646        impl_fmt!(Display for $name);
647        impl_binop!(Div::div for $name: $prim);
648        impl_binassign!(DivAssign::div_assign for $name: $prim);
649        impl_from!(for $name: $prim);
650        impl_fmt!(LowerExp for $name);
651        impl_binop!(Mul::mul for $name: $prim);
652        impl_binassign!(MulAssign::mul_assign for $name: $prim);
653        impl_unop!(Neg::neg for $name: $prim);
654        impl_partial_eq_and_eq!(for $name: $prim);
655        impl_partial_ord!(for $name: $prim);
656        impl_product_and_sum!(for $name);
657        impl_binop!(Rem::rem for $name: $prim);
658        impl_binassign!(RemAssign::rem_assign for $name: $prim);
659        impl_binop!(Sub::sub for $name: $prim);
660        impl_binassign!(SubAssign::sub_assign for $name: $prim);
661        impl_fmt!(UpperExp for $name);
662
663        impl_fidl_convert!(for $name: $prim);
664        impl_fidl_constrained!(for $name);
665        impl_fidl_copy_optimize!(for $name: $prim);
666        impl_fidl_decode!(for $name);
667        impl_fidl_encode!(for $name: $prim);
668        impl_fidl_encode!(for $name: $name);
669        impl_fidl_wire!(for $name);
670    };
671}
672
673macro_rules! define_newtype {
674    ($name:ident: $prim:ty, $align:expr) => {
675        #[doc = concat!("A wire-encoded `", stringify!($prim), "`")]
676        #[repr(C, align($align))]
677        #[derive(zerocopy::FromBytes, zerocopy::IntoBytes)]
678        pub struct $name(pub $prim);
679
680        impl ::core::ops::Deref for $name {
681            type Target = $prim;
682
683            fn deref(&self) -> &Self::Target {
684                &self.0
685            }
686        }
687
688        impl ::core::ops::DerefMut for $name {
689            fn deref_mut(&mut self) -> &mut Self::Target {
690                &mut self.0
691            }
692        }
693    };
694}
695
696macro_rules! define_signed_integer {
697    ($name:ident: $prim:ident, $align:expr) => {
698        define_newtype!($name: $prim, $align);
699        impl_signed_integer_traits!($name: $prim);
700    }
701}
702
703define_signed_integer!(Int16: i16, 2);
704define_signed_integer!(Int32: i32, 4);
705define_signed_integer!(Int64: i64, 8);
706
707macro_rules! define_unsigned_integer {
708    ($name:ident: $prim:ident, $align:expr) => {
709        define_newtype!($name: $prim, $align);
710        impl_unsigned_integer_traits!($name: $prim);
711    }
712}
713
714define_unsigned_integer!(Uint16: u16, 2);
715define_unsigned_integer!(Uint32: u32, 4);
716define_unsigned_integer!(Uint64: u64, 8);
717
718macro_rules! define_float {
719    ($name:ident: $prim:ident, $align:expr) => {
720        define_newtype!($name: $prim, $align);
721        impl_float_traits!($name: $prim);
722    }
723}
724
725define_float!(Float32: f32, 4);
726define_float!(Float64: f64, 8);
727
728#[cfg(test)]
729mod tests {
730    use crate::{DecoderExt as _, EncoderExt as _, chunks, wire};
731
732    #[test]
733    fn decode_bool() {
734        #![allow(clippy::bool_assert_comparison)]
735
736        assert_eq!(
737            chunks![0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
738                .as_mut_slice()
739                .decode::<bool>()
740                .unwrap(),
741            true,
742        );
743        assert_eq!(
744            chunks![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
745                .as_mut_slice()
746                .decode::<bool>()
747                .unwrap(),
748            false,
749        );
750    }
751
752    #[test]
753    fn encode_bool() {
754        assert_eq!(
755            Vec::encode(true).unwrap(),
756            chunks![0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
757        );
758        assert_eq!(
759            Vec::encode(false).unwrap(),
760            chunks![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
761        );
762    }
763
764    #[test]
765    fn decode_ints() {
766        assert_eq!(
767            chunks![0xa3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
768                .as_mut_slice()
769                .decode::<u8>()
770                .unwrap(),
771            0xa3u8,
772        );
773        assert_eq!(
774            chunks![0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
775                .as_mut_slice()
776                .decode::<i8>()
777                .unwrap(),
778            -0x45i8,
779        );
780
781        assert_eq!(
782            chunks![0x34, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
783                .as_mut_slice()
784                .decode::<wire::Uint16>()
785                .unwrap(),
786            0x1234u16,
787        );
788        assert_eq!(
789            chunks![0xcc, 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
790                .as_mut_slice()
791                .decode::<wire::Int16>()
792                .unwrap(),
793            -0x1234i16,
794        );
795
796        assert_eq!(
797            chunks![0x78, 0x56, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00]
798                .as_mut_slice()
799                .decode::<wire::Uint32>()
800                .unwrap(),
801            0x12345678u32,
802        );
803        assert_eq!(
804            chunks![0x88, 0xa9, 0xcb, 0xed, 0x00, 0x00, 0x00, 0x00]
805                .as_mut_slice()
806                .decode::<wire::Int32>()
807                .unwrap(),
808            -0x12345678i32,
809        );
810
811        assert_eq!(
812            chunks![0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12]
813                .as_mut_slice()
814                .decode::<wire::Uint64>()
815                .unwrap(),
816            0x123456789abcdef0u64,
817        );
818        assert_eq!(
819            chunks![0x10, 0x21, 0x43, 0x65, 0x87, 0xa9, 0xcb, 0xed]
820                .as_mut_slice()
821                .decode::<wire::Int64>()
822                .unwrap(),
823            -0x123456789abcdef0i64,
824        );
825    }
826
827    #[test]
828    fn encode_ints() {
829        assert_eq!(
830            Vec::encode(0xa3u8).unwrap(),
831            chunks![0xa3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
832        );
833        assert_eq!(
834            Vec::encode(-0x45i8).unwrap(),
835            chunks![0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
836        );
837
838        assert_eq!(
839            Vec::encode(0x1234u16).unwrap(),
840            chunks![0x34, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
841        );
842        assert_eq!(
843            Vec::encode(-0x1234i16).unwrap(),
844            chunks![0xcc, 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
845        );
846
847        assert_eq!(
848            Vec::encode(0x12345678u32).unwrap(),
849            chunks![0x78, 0x56, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00]
850        );
851        assert_eq!(
852            Vec::encode(-0x12345678i32).unwrap(),
853            chunks![0x88, 0xa9, 0xcb, 0xed, 0x00, 0x00, 0x00, 0x00]
854        );
855
856        assert_eq!(
857            Vec::encode(0x123456789abcdef0u64).unwrap(),
858            chunks![0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12],
859        );
860        assert_eq!(
861            Vec::encode(-0x123456789abcdef0i64).unwrap(),
862            chunks![0x10, 0x21, 0x43, 0x65, 0x87, 0xa9, 0xcb, 0xed],
863        );
864    }
865
866    #[test]
867    fn decode_floats() {
868        assert_eq!(
869            chunks![0xdb, 0x0f, 0x49, 0x40, 0x00, 0x00, 0x00, 0x00]
870                .as_mut_slice()
871                .decode::<wire::Float32>()
872                .unwrap(),
873            ::core::f32::consts::PI,
874        );
875        assert_eq!(
876            chunks![0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40]
877                .as_mut_slice()
878                .decode::<wire::Float64>()
879                .unwrap(),
880            ::core::f64::consts::PI,
881        );
882    }
883
884    #[test]
885    fn encode_floats() {
886        assert_eq!(
887            Vec::encode(::core::f32::consts::PI).unwrap(),
888            chunks![0xdb, 0x0f, 0x49, 0x40, 0x00, 0x00, 0x00, 0x00],
889        );
890        assert_eq!(
891            Vec::encode(::core::f64::consts::PI).unwrap(),
892            chunks![0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40],
893        );
894    }
895}