memapi2/data/
type_props.rs

1use {
2    crate::helpers::dangling_nonnull,
3    core::{
4        alloc::Layout,
5        mem::{align_of, align_of_val, size_of, size_of_val},
6        ptr::NonNull
7    }
8};
9
10/// The maximum value of a `usize` with no high bit.
11///
12/// Equivalent to `usize::MAX >> 1` or `isize::MAX as usize`.
13pub const USIZE_MAX_NO_HIGH_BIT: usize = usize::MAX >> 1;
14
15/// A `usize` in which only the high bit is set.
16///
17/// Equivalent to `usize::MAX ^ (usize::MAX >> 1)` or `usize::MAX << usize::BITS - 1`.
18pub const USIZE_HIGH_BIT: usize = usize::MAX ^ (usize::MAX >> 1);
19
20/// A small helper to generate a `usize` in which only the bit at the given index is set.
21#[must_use]
22#[inline]
23pub const fn usize_bit(bit: u8) -> usize {
24    USIZE_HIGH_BIT >> bit
25}
26
27/// A trait containing constants for sized types.
28pub trait SizedProps: Sized {
29    /// The size of the type.
30    const SZ: usize = size_of::<Self>();
31    /// The alignment of the type.
32    const ALN: usize = align_of::<Self>();
33    /// The memory layout for the type.
34    // SAFETY: this is the same as Layout::new::<T>().
35    const LAYOUT: Layout = unsafe { Layout::from_size_align_unchecked(Self::SZ, Self::ALN) };
36
37    /// Whether the type is zero-sized.
38    const IS_ZST: bool = Self::SZ == 0;
39
40    /// The largest safe length for a `[Self]`.
41    const MAX_SLICE_LEN: usize = match Self::SZ {
42        0 => usize::MAX,
43        sz => USIZE_MAX_NO_HIGH_BIT / sz
44    };
45}
46
47impl<T> SizedProps for T {}
48
49/// A trait providing methods for pointers to provide the properties of their pointees.
50pub trait PtrProps<T: ?Sized> {
51    /// Gets the size of the value.
52    ///
53    /// # Safety
54    ///
55    /// Callers must ensure the pointer is:
56    /// - non-null
57    /// - non-dangling
58    /// - aligned
59    ///
60    /// References are always valid.
61    unsafe fn sz(&self) -> usize;
62    /// Gets the alignment of the value.
63    ///
64    /// # Safety
65    ///
66    /// Callers must ensure the pointer is:
67    /// - non-null
68    /// - non-dangling
69    /// - aligned
70    ///
71    /// References are always valid.
72    unsafe fn aln(&self) -> usize;
73    /// Gets the memory layout for the value.
74    ///
75    /// # Safety
76    ///
77    /// Callers must ensure the pointer is:
78    /// - non-null
79    /// - non-dangling
80    /// - aligned
81    ///
82    /// References are always valid.
83    #[inline]
84    unsafe fn layout(&self) -> Layout {
85        Layout::from_size_align_unchecked(self.sz(), self.aln())
86    }
87
88    #[cfg(feature = "metadata")]
89    /// Gets the metadata of the value.
90    ///
91    /// # Safety
92    ///
93    /// Callers must ensure the pointer is:
94    /// - non-null
95    /// - non-dangling
96    /// - aligned
97    ///
98    /// References are always valid.
99    unsafe fn metadata(&self) -> <T as core::ptr::Pointee>::Metadata;
100
101    /// Checks whether the value is zero-sized.
102    ///
103    /// # Safety
104    ///
105    /// Callers must ensure the pointer is:
106    /// - non-null
107    /// - non-dangling
108    /// - aligned
109    ///
110    /// References are always valid.
111    unsafe fn is_zst(&self) -> bool {
112        self.sz() == 0
113    }
114
115    /// Gets the largest safe length for a slice containing copies of `self`.
116    ///
117    /// # Safety
118    ///
119    /// Callers must ensure the pointer is:
120    /// - non-null
121    /// - non-dangling
122    /// - aligned
123    ///
124    /// References are always valid.
125    unsafe fn max_slice_len(&self) -> usize {
126        match self.sz() {
127            0 => usize::MAX,
128            sz => USIZE_MAX_NO_HIGH_BIT / sz
129        }
130    }
131}
132
133macro_rules! impl_ptr_props_raw {
134    ($($name:ty),* $(,)?) => {
135        $(
136            impl<T: ?Sized> PtrProps<T> for $name {
137                #[inline]
138                unsafe fn sz(&self) -> usize {
139                    size_of_val::<T>(&**self)
140                }
141                #[inline]
142                unsafe fn aln(&self) -> usize {
143                    align_of_val::<T>(&**self)
144                }
145                #[cfg(feature = "metadata")]
146                unsafe fn metadata(&self) -> <T as core::ptr::Pointee>::Metadata {
147                    core::ptr::metadata(&*(*self))
148                }
149            }
150        )*
151    };
152}
153
154macro_rules! impl_ptr_props_identity {
155    ($($name:ty),* $(,)?) => {
156        $(
157            impl<T: ?Sized> PtrProps<T> for $name {
158                #[inline]
159                unsafe fn sz(&self) -> usize {
160                    size_of_val::<T>(*self)
161                }
162                #[inline]
163                unsafe fn aln(&self) -> usize {
164                    align_of_val::<T>(*self)
165                }
166                #[cfg(feature = "metadata")]
167                unsafe fn metadata(&self) -> <T as core::ptr::Pointee>::Metadata {
168                    core::ptr::metadata(*self)
169                }
170            }
171        )*
172    };
173}
174
175macro_rules! impl_ptr_props_as_ref {
176    ($($name:ty),* $(,)?) => {
177        $(
178            impl<T: ?Sized> PtrProps<T> for $name {
179                #[inline]
180                unsafe fn sz(&self) -> usize {
181                    size_of_val::<T>(self.as_ref())
182                }
183                #[inline]
184                unsafe fn aln(&self) -> usize {
185                    align_of_val::<T>(self.as_ref())
186                }
187                #[cfg(feature = "metadata")]
188                unsafe fn metadata(&self) -> <T as core::ptr::Pointee>::Metadata {
189                    core::ptr::metadata(self.as_ref())
190                }
191            }
192        )*
193    };
194}
195
196impl_ptr_props_raw! { *const T, *mut T }
197impl_ptr_props_identity! { &T, &mut T }
198impl_ptr_props_as_ref! {
199    alloc::boxed::Box<T>,
200    alloc::rc::Rc<T>,
201    alloc::sync::Arc<T>
202}
203
204impl<T: ?Sized> PtrProps<T> for NonNull<T> {
205    #[inline]
206    unsafe fn sz(&self) -> usize {
207        size_of_val::<T>(&*self.as_ptr())
208    }
209
210    #[inline]
211    unsafe fn aln(&self) -> usize {
212        align_of_val::<T>(&*self.as_ptr())
213    }
214
215    #[cfg(feature = "metadata")]
216    unsafe fn metadata(&self) -> <T as core::ptr::Pointee>::Metadata {
217        core::ptr::metadata(&*self.as_ptr())
218    }
219}
220
221#[cfg(not(feature = "metadata"))]
222/// Trait for unsized types that use `usize` metadata (for example, slices and `str`).
223///
224/// # Safety
225///
226/// Implementors must ensure that `Subtype` is the actual element type contained, that the `ALN`
227/// constant accurately reflects the type's alignment requirement in all safe contexts, and that
228/// this type has `usize` metadata (`<Self as Pointee>::Metadata = usize`).
229pub unsafe trait VarSized {
230    /// The element type.
231    ///
232    /// [`VarSized`] types are either slices of another type or include a slice tail; this is that
233    /// element type.
234    type Subtype: Sized + SizedProps;
235
236    /// The alignment of the type.
237    ///
238    /// Override this if the type contains more than just a slice of its
239    /// [`Subtype`](VarSized::Subtype).
240    const ALN: usize = Self::Subtype::ALN;
241}
242
243#[cfg(feature = "metadata")]
244/// Trait for unsized types that use `usize` metadata (for example, slices and `str`).
245///
246/// # Safety
247///
248/// Implementors must ensure that `Subtype` is the actual element type contained and that the `ALN`
249/// constant accurately reflects the type's alignment requirement in all safe contexts.
250pub unsafe trait VarSized: core::ptr::Pointee<Metadata = usize> {
251    /// The element type.
252    ///
253    /// [`VarSized`] types are either slices of another type or include a slice tail; this is that
254    /// element type.
255    type Subtype: Sized + SizedProps;
256
257    /// The alignment of the type.
258    ///
259    /// Override this if the type contains more than just a slice of its
260    /// [`Subtype`](VarSized::Subtype).
261    const ALN: usize = Self::Subtype::ALN;
262}
263
264// SAFETY: `[T]: Pointee<Metadata = usize> + MetaSized`
265unsafe impl<T> VarSized for [T] {
266    type Subtype = T;
267}
268
269// SAFETY: `str = [u8]`
270unsafe impl VarSized for str {
271    type Subtype = u8;
272}
273
274#[cfg(feature = "c_str")]
275// SAFETY: `CStr = [u8]`
276unsafe impl VarSized for core::ffi::CStr {
277    type Subtype = u8;
278}
279#[cfg(feature = "std")]
280// SAFETY: `OsStr = [u8]`
281unsafe impl VarSized for std::ffi::OsStr {
282    type Subtype = u8;
283}
284
285#[cfg(feature = "std")]
286// SAFETY: `Path = OsStr = [u8]`
287unsafe impl VarSized for std::path::Path {
288    type Subtype = u8;
289}
290
291// not associated to reduce clutter, and so they can be const
292
293const_if! {
294    "const_extras",
295    "Creates a dangling, zero-length, [`NonNull`] pointer with the proper alignment.",
296    #[must_use]
297    pub const fn varsized_dangling_nonnull<T: ?Sized + VarSized>() -> NonNull<T> {
298        // SAFETY: the implementor of VarSized guarantees the ALN is valid.
299        varsized_nonnull_from_raw_parts(unsafe { dangling_nonnull(T::ALN) }, 0)
300    }
301}
302
303const_if! {
304    "const_extras",
305    "Creates a dangling, zero-length [`NonNull`] pointer with the proper alignment.",
306    #[must_use]
307    pub const fn varsized_dangling_pointer<T: ?Sized + VarSized>() -> *mut T {
308        // SAFETY: the implementor of VarSized guarantees the ALN is valid.
309        varsized_pointer_from_raw_parts(unsafe { dangling_nonnull(T::ALN).as_ptr() }, 0)
310    }
311}
312
313const_if! {
314    "const_extras",
315    "Creates a `NonNull<T>` from a pointer and a `usize` size metadata.",
316    #[must_use]
317    #[inline]
318    pub const fn varsized_nonnull_from_raw_parts<T: ?Sized + VarSized>(
319        p: NonNull<u8>,
320        meta: usize,
321    ) -> NonNull<T> {
322        // SAFETY: `p` was already non-null, so it with different meta must also be nn.
323        unsafe { NonNull::new_unchecked(varsized_pointer_from_raw_parts(p.as_ptr(), meta)) }
324    }
325}
326
327const_if! {
328    "const_extras",
329    "Creates a `*mut T` from a pointer and a `usize` size metadata.",
330    #[must_use]
331    #[inline]
332    pub const fn varsized_pointer_from_raw_parts<T: ?Sized + VarSized>(
333        p: *mut u8,
334        meta: usize,
335    ) -> *mut T {
336        // SAFETY: VarSized trait requires T::Metadata == usize
337        unsafe {
338            // i hate this so much
339            *((&(p, meta)) as *const (*mut u8, usize)).cast::<*mut T>()
340        }
341    }
342}