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.
41    #[doc(hidden)]
42    const MAX: Self;
43
44    /// The max size of a pointer in usize.
45    #[doc(hidden)]
46    const MAX_USIZE: usize;
47
48    #[doc(hidden)]
49    const ONE: Self;
50
51    #[doc(hidden)]
52    const N2: Self;
53
54    #[doc(hidden)]
55    const N4: Self;
56
57    #[doc(hidden)]
58    const N8: Self;
59
60    #[doc(hidden)]
61    const N16: Self;
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    /// Try to construct this value from usize.
81    fn try_from_usize(value: usize) -> Result<Self, CoerceError>;
82
83    /// Convert the pointer to a usize.
84    #[doc(hidden)]
85    fn as_usize(self) -> usize;
86
87    /// Test if the value is zero.
88    #[doc(hidden)]
89    fn is_zero(self) -> bool;
90}
91
92macro_rules! impl_size {
93    ($ty:ty) => {
94        #[doc = concat!("Size implementation for `", stringify!($ty), "`")]
95        ///
96        /// # Examples
97        ///
98        /// ```
99        /// use musli_zerocopy::{endian, Size};
100        ///
101        #[doc = concat!("let max = ", stringify!($ty), "::MAX;")]
102        /// ```
103        impl Size for $ty {
104            const ZERO: Self = 0;
105            const MAX: Self = <$ty>::MAX;
106            const MAX_USIZE: usize = <$ty>::MAX as usize;
107            const ONE: Self = 1;
108            const N2: Self = 2;
109            const N4: Self = 4;
110            const N8: Self = 8;
111            const N16: Self = 16;
112
113            #[inline(always)]
114            fn wrapping_mul(self, other: Self) -> Self {
115                self.wrapping_mul(other)
116            }
117
118            #[inline(always)]
119            fn checked_mul(self, other: Self) -> Option<Self> {
120                self.checked_mul(other)
121            }
122
123            #[inline]
124            fn try_from_usize(value: usize) -> Result<Self, CoerceError> {
125                if value > <$ty>::MAX as usize {
126                    Err(CoerceError::new(CoerceErrorKind::LengthOverflow {
127                        len: value,
128                        size: <$ty>::MAX as usize,
129                    }))
130                } else {
131                    Ok(value as $ty)
132                }
133            }
134
135            #[inline]
136            fn as_usize(self) -> usize {
137                debug_assert!(
138                    <usize as TryFrom<_>>::try_from(self).is_ok(),
139                    "Value {self} cannot be represented on this platform"
140                );
141                self as usize
142            }
143
144            #[inline]
145            fn is_zero(self) -> bool {
146                self == 0
147            }
148        }
149    };
150}
151
152impl_size!(u8);
153impl_size!(u16);
154#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
155impl_size!(u32);
156#[cfg(target_pointer_width = "64")]
157impl_size!(u64);
158impl_size!(usize);