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.