memapi2/data/
type_props.rs

1use {
2    crate::{Layout, helpers::USIZE_MAX_NO_HIGH_BIT},
3    core::{
4        mem::{align_of, align_of_val, size_of, size_of_val},
5        ptr::NonNull
6    }
7};
8
9/// A trait containing constants for sized types.
10pub trait SizedProps: Sized {
11    /// The size of the type.
12    const SZ: usize = size_of::<Self>();
13    /// The alignment of the type.
14    const ALN: usize = align_of::<Self>();
15    /// The memory layout for the type.
16    // SAFETY: this is the same as Layout::new::<T>().
17    const LAYOUT: Layout = unsafe { Layout::from_size_align_unchecked(Self::SZ, Self::ALN) };
18
19    /// Whether the type is zero-sized.
20    const IS_ZST: bool = Self::SZ == 0;
21
22    /// The largest safe length for a `[Self]`.
23    const MAX_SLICE_LEN: usize = match Self::SZ {
24        0 => usize::MAX,
25        sz => USIZE_MAX_NO_HIGH_BIT / sz
26    };
27}
28
29impl<T> SizedProps for T {}
30
31/// A trait providing methods for pointers to provide the properties of their pointees.
32pub trait PtrProps<T: ?Sized> {
33    /// Gets the size of the value.
34    ///
35    /// # Safety
36    ///
37    /// The caller must ensure `self` is:
38    /// - non-null
39    /// - non-dangling
40    /// - aligned
41    ///
42    /// References are always valid.
43    unsafe fn sz(&self) -> usize;
44    /// Gets the alignment of the value.
45    ///
46    /// # Safety
47    ///
48    /// The caller must ensure `self` is:
49    /// - non-null
50    /// - non-dangling
51    /// - aligned
52    ///
53    /// References are always valid.
54    unsafe fn aln(&self) -> usize;
55    /// Gets the memory layout for the value.
56    ///
57    /// # Safety
58    ///
59    /// The caller must ensure `self` is:
60    /// - non-null
61    /// - non-dangling
62    /// - aligned
63    ///
64    /// References are always valid.
65    #[inline]
66    unsafe fn layout(&self) -> Layout {
67        Layout::from_size_align_unchecked(self.sz(), self.aln())
68    }
69
70    #[cfg(feature = "metadata")]
71    /// Gets the metadata of the value.
72    ///
73    /// # Safety
74    ///
75    /// The caller must ensure `self` is:
76    /// - non-null
77    /// - non-dangling
78    /// - aligned
79    ///
80    /// References are always valid.
81    unsafe fn metadata(&self) -> <T as core::ptr::Pointee>::Metadata;
82
83    /// Checks whether the value is zero-sized.
84    ///
85    /// # Safety
86    ///
87    /// The caller must ensure `self` is:
88    /// - non-null
89    /// - non-dangling
90    /// - aligned
91    ///
92    /// References are always valid.
93    unsafe fn is_zst(&self) -> bool {
94        self.sz() == 0
95    }
96
97    /// Gets the largest safe length for a slice containing copies of `self`.
98    ///
99    /// # Safety
100    ///
101    /// The caller must ensure `self` is:
102    /// - non-null
103    /// - non-dangling
104    /// - aligned
105    ///
106    /// References are always valid.
107    unsafe fn max_slice_len(&self) -> usize {
108        match self.sz() {
109            0 => usize::MAX,
110            sz => USIZE_MAX_NO_HIGH_BIT / sz
111        }
112    }
113}
114
115/// Implements `PtrProps` for raw pointers.
116macro_rules! impl_ptr_props_raw {
117    ($($name:ty),* $(,)?) => {
118        $(
119            impl<T: ?Sized> PtrProps<T> for $name {
120                #[inline]
121                unsafe fn sz(&self) -> usize {
122                    size_of_val::<T>(&**self)
123                }
124                #[inline]
125                unsafe fn aln(&self) -> usize {
126                    align_of_val::<T>(&**self)
127                }
128                #[cfg(feature = "metadata")]
129                unsafe fn metadata(&self) -> <T as core::ptr::Pointee>::Metadata {
130                    core::ptr::metadata(&*(*self))
131                }
132            }
133        )*
134    };
135}
136
137macro_rules! impl_ptr_props_identity {
138    ($($name:ty),* $(,)?) => {
139        $(
140            impl<T: ?Sized> PtrProps<T> for $name {
141                #[inline]
142                unsafe fn sz(&self) -> usize {
143                    size_of_val::<T>(*self)
144                }
145                #[inline]
146                unsafe fn aln(&self) -> usize {
147                    align_of_val::<T>(*self)
148                }
149                #[cfg(feature = "metadata")]
150                unsafe fn metadata(&self) -> <T as core::ptr::Pointee>::Metadata {
151                    core::ptr::metadata(*self)
152                }
153            }
154        )*
155    };
156}
157
158macro_rules! impl_ptr_props_as_ref {
159    ($($name:ty),* $(,)?) => {
160        $(
161            #[allow(unused_qualifications)]
162            impl<T: ?Sized> PtrProps<T> for $name {
163                #[inline]
164                unsafe fn sz(&self) -> usize {
165                    size_of_val::<T>(self.as_ref())
166                }
167                #[inline]
168                unsafe fn aln(&self) -> usize {
169                    align_of_val::<T>(self.as_ref())
170                }
171                #[cfg(feature = "metadata")]
172                unsafe fn metadata(&self) -> <T as core::ptr::Pointee>::Metadata {
173                    core::ptr::metadata(self.as_ref())
174                }
175            }
176        )*
177    };
178}
179
180impl_ptr_props_raw! { *const T, *mut T }
181impl_ptr_props_identity! { &T, &mut T }
182impl_ptr_props_as_ref! {
183    alloc::boxed::Box<T>,
184    alloc::rc::Rc<T>,
185    alloc::sync::Arc<T>,
186}
187impl<T: Clone> PtrProps<T> for alloc::borrow::Cow<'_, T> {
188    #[inline]
189    unsafe fn sz(&self) -> usize {
190        T::SZ
191    }
192    #[inline]
193    unsafe fn aln(&self) -> usize {
194        T::ALN
195    }
196    #[cfg(feature = "metadata")]
197    unsafe fn metadata(&self) {}
198}
199
200impl<T: ?Sized> PtrProps<T> for NonNull<T> {
201    #[inline]
202    unsafe fn sz(&self) -> usize {
203        size_of_val::<T>(&*self.as_ptr())
204    }
205
206    #[inline]
207    unsafe fn aln(&self) -> usize {
208        align_of_val::<T>(&*self.as_ptr())
209    }
210
211    #[cfg(feature = "metadata")]
212    unsafe fn metadata(&self) -> <T as core::ptr::Pointee>::Metadata {
213        core::ptr::metadata(&*self.as_ptr())
214    }
215}
216
217#[cfg(not(feature = "metadata"))]
218/// Trait for unsized types that use `usize` metadata (for example, slices and `str`).
219///
220/// # Safety
221///
222/// The implementor must ensure that [`SubType`](VarSized::SubType) is the actual element type
223/// contained, that the [`ALN`](VarSized::ALN) constant accurately reflects the type's alignment
224/// requirement in all safe contexts, and that this type has `usize` metadata (`<Self as
225/// Pointee>::Metadata = usize`).
226pub unsafe trait VarSized {
227    /// The element type.
228    ///
229    /// [`VarSized`] types are either slices of another type or include a slice tail; this is that
230    /// element type.
231    type SubType: Sized;
232
233    /// The alignment of the type.
234    ///
235    /// Override this if the type contains more than just a slice of its
236    /// [`SubType`](VarSized::SubType).
237    const ALN: usize = Self::SubType::ALN;
238}
239
240#[cfg(feature = "metadata")]
241/// Trait for unsized types that use `usize` metadata (for example, slices and `str`).
242///
243/// # Safety
244///
245/// The implementor must ensure that [`SubType`](VarSized::SubType) is the actual element type
246/// contained, and that the [`ALN`](VarSized::ALN) constant accurately reflects the type's alignment
247/// requirement in all safe contexts.
248pub unsafe trait VarSized: core::ptr::Pointee<Metadata = usize> {
249    /// The element type.
250    ///
251    /// [`VarSized`] types are either slices of another type or include a slice tail; this is that
252    /// element type.
253    type SubType: Sized + SizedProps;
254
255    /// The alignment of the type.
256    ///
257    /// Override this if the type contains more than just a slice of its
258    /// [`SubType`](VarSized::SubType).
259    const ALN: usize = Self::SubType::ALN;
260}
261
262#[cfg(not(feature = "metadata"))]
263/// Trait for unsized _structs_ that have a [`VarSized`] tail.
264///
265/// # Safety
266///
267/// The implementor must ensure that [`Tail`](VarSizedStruct::Tail) is the actual tail type
268/// contained, that the [`ALN`](VarSizedStruct::ALN) constant accurately reflects the type's
269/// alignment requirement in all safe contexts, and that this type has `usize` metadata (`<Self as
270/// Pointee>::Metadata = usize`).
271pub unsafe trait VarSizedStruct {
272    /// The [`VarSized`] tail type.
273    ///
274    /// [`VarSizedStruct`] types are unsized structs that contain a [`VarSized`] tail; this is that
275    /// tail type.
276    type Tail: VarSized;
277
278    /// The alignment of the type.
279    ///
280    /// # How to determine
281    ///
282    /// The alignment of a [`VarSizedStruct`] is determined by its fields and its `repr` attribute.
283    ///
284    /// ## Fields
285    ///
286    /// Consider all fields of the struct, including the unsized tail. For the tail field, use
287    /// its [`VarSized::ALN`] as its alignment.
288    ///
289    /// ## Determination based on `#[repr]`
290    ///
291    /// ### Rust default / `#[repr(Rust)]` / `#[repr(C)]`
292    ///
293    /// The alignment of the struct is the maximum alignment of all of its fields. (<code>ALN =
294    /// max([align_of]::\<Field1\>(), [align_of]::\<Field2\>(), ...,
295    /// <[Self::Tail](VarSizedStruct::Tail) as [VarSized]>::[ALN](VarSized::ALN))</code>)
296    ///
297    /// ### `#[repr(packed)]`
298    ///
299    /// The alignment of the struct is always 1.
300    ///
301    /// ### `#[repr(packed(N))]`
302    ///
303    /// The alignment of the struct is the minimum of `N` and the maximum alignment of all of its
304    /// fields. (<code>ALN = min(N, max([align_of]::\<Field1\>(), [align_of]::\<Field2\>(), ...,
305    /// <[Self::Tail](VarSizedStruct::Tail) as [VarSized]>::[ALN](VarSized::ALN)))</code>)
306    ///
307    /// ### `#[repr(align(N))]`
308    ///
309    /// If `#[repr(align(N))]` is used, the alignment of the struct is the maximum of `N` and the
310    /// alignment it would otherwise have. (<code>ALN = max(N, [align_of]::\<Field1\>(),
311    /// [align_of]::\<Field2\>(), ..., <[Self::Tail](VarSizedStruct::Tail) as
312    /// [VarSized]>::[ALN](VarSized::ALN))</code>).
313    const ALN: usize;
314}
315
316#[cfg(feature = "metadata")]
317/// Trait for unsized _structs_ that have a [`VarSized`] tail.
318///
319/// # Safety
320///
321/// The implementor must ensure that [`Tail`](VarSizedStruct::Tail) is the actual tail type
322/// contained, and that the [`ALN`](VarSizedStruct::ALN) constant accurately reflects the type's
323/// alignment requirement in all safe contexts.
324pub unsafe trait VarSizedStruct: core::ptr::Pointee<Metadata = usize> {
325    /// The [`VarSized`] tail type.
326    ///
327    /// [`VarSizedStruct`] types are unsized structs that contain a [`VarSized`] tail; this is that
328    /// tail type.
329    type Tail: VarSized;
330
331    /// The alignment of the type.
332    ///
333    /// # How to determine
334    ///
335    /// The alignment of a [`VarSizedStruct`] is determined by its fields and its `repr` attribute.
336    ///
337    /// ## Fields
338    ///
339    /// Consider all fields of the struct, including the unsized tail. For the tail field, use
340    /// its [`VarSized::ALN`] as its alignment.
341    ///
342    /// ## Determination based on `#[repr]`
343    ///
344    /// ### Rust default / `#[repr(Rust)]` / `#[repr(C)]`
345    ///
346    /// The alignment of the struct is the maximum alignment of all of its fields. (<code>ALN =
347    /// max([align_of]::\<Field1\>(), [align_of]::\<Field2\>(), ...,
348    /// <[Self::Tail](VarSizedStruct::Tail) as [VarSized]>::[ALN](VarSized::ALN))</code>)
349    ///
350    /// ### `#[repr(packed)]`
351    ///
352    /// The alignment of the struct is always 1.
353    ///
354    /// ### `#[repr(packed(N))]`
355    ///
356    /// The alignment of the struct is the minimum of `N` and the maximum alignment of all of its
357    /// fields. (<code>ALN = min(N, max([align_of]::\<Field1\>(), [align_of]::\<Field2\>(), ...,
358    /// <[Self::Tail](VarSizedStruct::Tail) as [VarSized]>::[ALN](VarSized::ALN)))</code>)
359    ///
360    /// ### `#[repr(align(N))]`
361    ///
362    /// If `#[repr(align(N))]` is used, the alignment of the struct is the maximum of `N` and the
363    /// alignment it would otherwise have. (<code>ALN = max(N, [align_of]::\<Field1\>(),
364    /// [align_of]::\<Field2\>(), ..., <[Self::Tail](VarSizedStruct::Tail) as
365    /// [VarSized]>::[ALN](VarSized::ALN))</code>).
366    const ALN: usize;
367}
368
369// SAFETY: `[T]: Pointee<Metadata = usize> + MetaSized`
370unsafe impl<T> VarSized for [T] {
371    type SubType = T;
372}
373
374// SAFETY: `str = [u8]`
375unsafe impl VarSized for str {
376    type SubType = u8;
377}
378
379#[cfg(all(feature = "c_str", not(feature = "std")))]
380// SAFETY: `CStr = [u8]`
381unsafe impl VarSized for core::ffi::CStr {
382    type SubType = u8;
383}
384#[cfg(feature = "std")]
385// SAFETY: `OsStr = [u8]`
386unsafe impl VarSized for std::ffi::OsStr {
387    type SubType = u8;
388}
389
390#[cfg(feature = "std")]
391// SAFETY: `Path = OsStr = [u8]`
392unsafe impl VarSized for std::path::Path {
393    type SubType = u8;
394}
395
396#[allow(clippy::undocumented_unsafe_blocks)]
397unsafe impl<T: VarSizedStruct> VarSized for T {
398    type SubType = <T::Tail as VarSized>::SubType;
399
400    const ALN: usize = <T as VarSizedStruct>::ALN;
401}
402
403// anysized system didn't work well enough for me to actually keep it.