musli_zerocopy/pointer/
size.rs

1use core::fmt;
2
3use crate::endian::ByteOrder;
4use crate::error::IntoRepr;
5use crate::traits::ZeroCopy;
6
7/// The default [`Size`] to use.
8pub type DefaultSize = u32;
9
10#[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64",)))]
11compile_error!("musli-zerocopy is only supported on 32, 64-bit platforms");
12
13mod sealed {
14    pub trait Sealed {}
15    impl Sealed for u8 {}
16    impl Sealed for u16 {}
17    impl Sealed for u32 {}
18    #[cfg(target_pointer_width = "64")]
19    impl Sealed for u64 {}
20    impl Sealed for usize {}
21}
22
23/// Trait which defines the size of a pointer.
24///
25/// Some of the available [`Size`] implementations are:
26/// * `u8`, `u16`, and `u32` for sized pointers matching the width of the
27///   specified type.
28/// * `usize` for target-dependently sized pointers.
29///
30/// The default size is defined by the [`DefaultSize`] type alias.
31///
32/// This trait is sealed and its internals hidden. Publicly it's only used as a
33/// marker trait.
34pub trait Size:
35    'static
36    + Sized
37    + TryFrom<usize>
38    + Copy
39    + fmt::Display
40    + fmt::Debug
41    + ZeroCopy
42    + IntoRepr
43    + self::sealed::Sealed
44{
45    /// The default zero pointer.
46    #[doc(hidden)]
47    const ZERO: Self;
48
49    /// The max size of a pointer.
50    #[doc(hidden)]
51    const MAX: Self;
52
53    #[doc(hidden)]
54    const ONE: Self;
55
56    #[doc(hidden)]
57    const N2: Self;
58
59    #[doc(hidden)]
60    const N4: Self;
61
62    #[doc(hidden)]
63    const N8: Self;
64
65    #[doc(hidden)]
66    const N16: Self;
67
68    #[doc(hidden)]
69    /// Perform wrapping multiplication over the type.
70    fn wrapping_mul(self, other: Self) -> Self;
71
72    #[doc(hidden)]
73    /// Perform checked multiplication over the type.
74    fn checked_mul(self, other: Self) -> Option<Self>;
75
76    /// Try to construct this value from usize.
77    fn try_from_usize(value: usize) -> Option<Self>;
78
79    /// Convert the pointer to a usize.
80    #[doc(hidden)]
81    fn as_usize<E>(self) -> usize
82    where
83        E: ByteOrder;
84
85    /// Test if the value is zero.
86    #[doc(hidden)]
87    fn is_zero(self) -> bool;
88}
89
90macro_rules! impl_size {
91    ($ty:ty, $swap:path) => {
92        #[doc = concat!("Size implementation for `", stringify!($ty), "`")]
93        ///
94        /// # Examples
95        ///
96        /// ```
97        /// use musli_zerocopy::{endian, Size};
98        ///
99        #[doc = concat!("let max = ", stringify!($ty), "::MAX.as_usize::<endian::Big>();")]
100        #[doc = concat!("let min = ", stringify!($ty), "::MIN.as_usize::<endian::Little>();")]
101        /// ```
102        impl Size for $ty {
103            const ZERO: Self = 0;
104            const MAX: Self = <$ty>::MAX;
105            const ONE: Self = 1;
106            const N2: Self = 2;
107            const N4: Self = 4;
108            const N8: Self = 8;
109            const N16: Self = 16;
110
111            #[inline(always)]
112            fn wrapping_mul(self, other: Self) -> Self {
113                self.wrapping_mul(other)
114            }
115
116            #[inline(always)]
117            fn checked_mul(self, other: Self) -> Option<Self> {
118                self.checked_mul(other)
119            }
120
121            #[inline]
122            fn try_from_usize(value: usize) -> Option<Self> {
123                if value > <$ty>::MAX as usize {
124                    None
125                } else {
126                    Some(value as $ty)
127                }
128            }
129
130            #[inline]
131            fn as_usize<E>(self) -> usize
132            where
133                E: ByteOrder,
134            {
135                if self > usize::MAX as $ty {
136                    usize::MAX
137                } else {
138                    $swap(self) as usize
139                }
140            }
141
142            #[inline]
143            fn is_zero(self) -> bool {
144                self == 0
145            }
146        }
147    };
148}
149
150impl_size!(u8, core::convert::identity);
151impl_size!(u16, E::swap_u16);
152impl_size!(u32, E::swap_u32);
153#[cfg(target_pointer_width = "64")]
154impl_size!(u64, E::swap_u64);
155impl_size!(usize, core::convert::identity);