memapi2/data/
type_props.rs

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