Skip to main content

musli_zerocopy/pointer/
size.rs

1use crate::error::{CoerceError, CoerceErrorKind};
2use crate::traits::ZeroCopy;
3
4/// The default [`Size`] to use.
5pub type DefaultSize = u32;
6
7#[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))]
8compile_error!("musli-zerocopy is only supported on 32, 64-bit platforms");
9
10mod sealed {
11    pub trait Sealed {}
12    impl Sealed for u8 {}
13    impl Sealed for u16 {}
14    #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
15    impl Sealed for u32 {}
16    #[cfg(target_pointer_width = "64")]
17    impl Sealed for u64 {}
18    impl Sealed for usize {}
19}
20
21/// Trait which defines the size of a pointer.
22///
23/// Some of the available [`Size`] implementations are:
24/// * `u8`, `u16`, and `u32` for sized pointers matching the width of the
25///   specified type.
26/// * `usize` for target-dependently sized pointers.
27///
28/// The default size is defined by the [`DefaultSize`] type alias.
29///
30/// This trait is sealed and its internals hidden. Publicly it's only used as a
31/// marker trait.
32pub trait Size
33where
34    Self: 'static + Copy + ZeroCopy + self::sealed::Sealed,
35{
36    /// The default zero pointer.
37    #[doc(hidden)]
38    const ZERO: Self;
39
40    /// The max size of a pointer in usize.
41    #[doc(hidden)]
42    const MAX: usize;
43
44    #[doc(hidden)]
45    const ONE: Self;
46
47    #[doc(hidden)]
48    const N2: Self;
49
50    #[doc(hidden)]
51    const N4: Self;
52
53    #[doc(hidden)]
54    const N8: Self;
55
56    #[doc(hidden)]
57    const N16: Self;
58
59    #[doc(hidden)]
60    /// Test for equality between two sizes.
61    fn eq(self, other: Self) -> bool;
62
63    /// Try to perform a conversion from one `usize` type to another.
64    #[inline(always)]
65    fn try_from<U>(other: U) -> Result<Self, CoerceError>
66    where
67        U: Size,
68    {
69        Self::try_from_usize(other.as_usize())
70    }
71
72    #[doc(hidden)]
73    /// Perform wrapping multiplication over the type.
74    fn wrapping_mul(self, other: Self) -> Self;
75
76    #[doc(hidden)]
77    /// Perform checked multiplication over the type.
78    fn checked_mul(self, other: Self) -> Option<Self>;
79
80    #[doc(hidden)]
81    /// Perform checked addition over the type.
82    fn checked_add(self, other: Self) -> Option<Self>;
83
84    #[doc(hidden)]
85    /// Perform checked subtraction over the type.
86    fn checked_sub(self, other: Self) -> Option<Self>;
87
88    /// Construct this value from a usize.
89    fn from_usize(value: usize) -> Self;
90
91    /// Try to construct this value from usize.
92    fn try_from_usize(value: usize) -> Result<Self, CoerceError>;
93
94    /// Convert the pointer to a usize.
95    #[doc(hidden)]
96    fn as_usize(self) -> usize;
97
98    /// Test if the value is zero.
99    #[doc(hidden)]
100    fn is_zero(self) -> bool;
101}
102
103macro_rules! impl_size {
104    ($ty:ty) => {
105        #[doc = concat!("Size implementation for `", stringify!($ty), "`")]
106        ///
107        /// # Examples
108        ///
109        /// ```
110        /// use musli_zerocopy::{endian, Size};
111        ///
112        #[doc = concat!("let max = ", stringify!($ty), "::MAX;")]
113        /// ```
114        impl Size for $ty {
115            const ZERO: Self = 0;
116            const MAX: usize = <$ty>::MAX as usize;
117            const ONE: Self = 1;
118            const N2: Self = 2;
119            const N4: Self = 4;
120            const N8: Self = 8;
121            const N16: Self = 16;
122
123            #[inline(always)]
124            fn eq(self, other: Self) -> bool {
125                self == other
126            }
127
128            #[inline(always)]
129            fn wrapping_mul(self, other: Self) -> Self {
130                self.wrapping_mul(other)
131            }
132
133            #[inline(always)]
134            fn checked_mul(self, other: Self) -> Option<Self> {
135                self.checked_mul(other)
136            }
137
138            #[inline(always)]
139            fn checked_add(self, other: Self) -> Option<Self> {
140                self.checked_add(other)
141            }
142
143            #[inline(always)]
144            fn checked_sub(self, other: Self) -> Option<Self> {
145                self.checked_sub(other)
146            }
147
148            #[inline(always)]
149            fn from_usize(value: usize) -> Self {
150                debug_assert!(
151                    value <= <$ty>::MAX as usize,
152                    "Value {value} cannot be represented on this platform"
153                );
154                value as $ty
155            }
156
157            #[inline(always)]
158            fn try_from_usize(value: usize) -> Result<Self, CoerceError> {
159                if value > <$ty>::MAX as usize {
160                    Err(CoerceError::new(CoerceErrorKind::LengthOverflow {
161                        len: value,
162                        size: <$ty>::MAX as usize,
163                    }))
164                } else {
165                    Ok(value as $ty)
166                }
167            }
168
169            #[inline(always)]
170            fn as_usize(self) -> usize {
171                debug_assert!(
172                    <usize as TryFrom<_>>::try_from(self).is_ok(),
173                    "Value {self} cannot be represented on this platform"
174                );
175                self as usize
176            }
177
178            #[inline(always)]
179            fn is_zero(self) -> bool {
180                self == 0
181            }
182        }
183    };
184}
185
186impl_size!(u8);
187impl_size!(u16);
188#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
189impl_size!(u32);
190#[cfg(target_pointer_width = "64")]
191impl_size!(u64);
192impl_size!(usize);