Skip to main content

core/ptr/
alignment.rs

1#![allow(clippy::enum_clike_unportable_variant)]
2
3#[cfg(not(feature = "ferrocene_subset"))]
4use crate::marker::MetaSized;
5use crate::num::NonZero;
6use crate::ub_checks::assert_unsafe_precondition;
7#[cfg(not(feature = "ferrocene_subset"))]
8use crate::{cmp, fmt, hash, mem, num};
9
10// Ferrocene addition: imports for certified subset
11#[cfg(feature = "ferrocene_subset")]
12#[rustfmt::skip]
13use crate::{fmt, hash, mem};
14
15/// A type storing a `usize` which is a power of two, and thus
16/// represents a possible alignment in the Rust abstract machine.
17///
18/// Note that particularly large alignments, while representable in this type,
19/// are likely not to be supported by actual allocators and linkers.
20#[unstable(feature = "ptr_alignment_type", issue = "102070")]
21#[derive(Copy, Clone, PartialEq, Eq)]
22#[repr(transparent)]
23pub struct Alignment {
24    // This field is never used directly (nor is the enum),
25    // as it's just there to convey the validity invariant.
26    // (Hopefully it'll eventually be a pattern type instead.)
27    _inner_repr_trick: AlignmentEnum,
28}
29
30// Alignment is `repr(usize)`, but via extra steps.
31const _: () = assert!(size_of::<Alignment>() == size_of::<usize>());
32const _: () = assert!(align_of::<Alignment>() == align_of::<usize>());
33
34#[cfg(not(feature = "ferrocene_subset"))]
35fn _alignment_can_be_structurally_matched(a: Alignment) -> bool {
36    matches!(a, Alignment::MIN)
37}
38
39impl Alignment {
40    /// The smallest possible alignment, 1.
41    ///
42    /// All addresses are always aligned at least this much.
43    ///
44    /// # Examples
45    ///
46    /// ```
47    /// #![feature(ptr_alignment_type)]
48    /// use std::ptr::Alignment;
49    ///
50    /// assert_eq!(Alignment::MIN.as_usize(), 1);
51    /// ```
52    #[unstable(feature = "ptr_alignment_type", issue = "102070")]
53    #[cfg(not(feature = "ferrocene_subset"))]
54    pub const MIN: Self = Self::new(1).unwrap();
55
56    /// Returns the alignment for a type.
57    ///
58    /// This provides the same numerical value as [`align_of`],
59    /// but in an `Alignment` instead of a `usize`.
60    #[unstable(feature = "ptr_alignment_type", issue = "102070")]
61    #[inline]
62    #[must_use]
63    #[cfg(not(feature = "ferrocene_subset"))]
64    pub const fn of<T>() -> Self {
65        <T as mem::SizedTypeProperties>::ALIGNMENT
66    }
67
68    /// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to.
69    ///
70    /// Every reference to a value of the type `T` must be a multiple of this number.
71    ///
72    /// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface
73    ///
74    /// # Examples
75    ///
76    /// ```
77    /// #![feature(ptr_alignment_type)]
78    /// use std::ptr::Alignment;
79    ///
80    /// assert_eq!(Alignment::of_val(&5i32).as_usize(), 4);
81    /// ```
82    #[cfg(not(feature = "ferrocene_subset"))]
83    #[inline]
84    #[must_use]
85    #[unstable(feature = "ptr_alignment_type", issue = "102070")]
86    pub const fn of_val<T: MetaSized>(val: &T) -> Self {
87        let align = mem::align_of_val(val);
88        // SAFETY: `align_of_val` returns valid alignment
89        unsafe { Alignment::new_unchecked(align) }
90    }
91
92    /// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to.
93    ///
94    /// Every reference to a value of the type `T` must be a multiple of this number.
95    ///
96    /// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface
97    ///
98    /// # Safety
99    ///
100    /// This function is only safe to call if the following conditions hold:
101    ///
102    /// - If `T` is `Sized`, this function is always safe to call.
103    /// - If the unsized tail of `T` is:
104    ///     - a [slice], then the length of the slice tail must be an initialized
105    ///       integer, and the size of the *entire value*
106    ///       (dynamic tail length + statically sized prefix) must fit in `isize`.
107    ///       For the special case where the dynamic tail length is 0, this function
108    ///       is safe to call.
109    ///     - a [trait object], then the vtable part of the pointer must point
110    ///       to a valid vtable acquired by an unsizing coercion, and the size
111    ///       of the *entire value* (dynamic tail length + statically sized prefix)
112    ///       must fit in `isize`.
113    ///     - an (unstable) [extern type], then this function is always safe to
114    ///       call, but may panic or otherwise return the wrong value, as the
115    ///       extern type's layout is not known. This is the same behavior as
116    ///       [`Alignment::of_val`] on a reference to a type with an extern type tail.
117    ///     - otherwise, it is conservatively not allowed to call this function.
118    ///
119    /// [trait object]: ../../book/ch17-02-trait-objects.html
120    /// [extern type]: ../../unstable-book/language-features/extern-types.html
121    ///
122    /// # Examples
123    ///
124    /// ```
125    /// #![feature(ptr_alignment_type)]
126    /// use std::ptr::Alignment;
127    ///
128    /// assert_eq!(unsafe { Alignment::of_val_raw(&5i32) }.as_usize(), 4);
129    /// ```
130    #[cfg(not(feature = "ferrocene_subset"))]
131    #[inline]
132    #[must_use]
133    #[unstable(feature = "ptr_alignment_type", issue = "102070")]
134    // #[unstable(feature = "layout_for_ptr", issue = "69835")]
135    pub const unsafe fn of_val_raw<T: MetaSized>(val: *const T) -> Self {
136        // SAFETY: precondition propagated to the caller
137        let align = unsafe { mem::align_of_val_raw(val) };
138        // SAFETY: `align_of_val_raw` returns valid alignment
139        unsafe { Alignment::new_unchecked(align) }
140    }
141
142    /// Creates an `Alignment` from a `usize`, or returns `None` if it's
143    /// not a power of two.
144    ///
145    /// Note that `0` is not a power of two, nor a valid alignment.
146    #[unstable(feature = "ptr_alignment_type", issue = "102070")]
147    #[inline]
148    pub const fn new(align: usize) -> Option<Self> {
149        if align.is_power_of_two() {
150            // SAFETY: Just checked it only has one bit set
151            Some(unsafe { Self::new_unchecked(align) })
152        } else {
153            None
154        }
155    }
156
157    /// Creates an `Alignment` from a power-of-two `usize`.
158    ///
159    /// # Safety
160    ///
161    /// `align` must be a power of two.
162    ///
163    /// Equivalently, it must be `1 << exp` for some `exp` in `0..usize::BITS`.
164    /// It must *not* be zero.
165    #[unstable(feature = "ptr_alignment_type", issue = "102070")]
166    #[inline]
167    #[track_caller]
168    pub const unsafe fn new_unchecked(align: usize) -> Self {
169        assert_unsafe_precondition!(
170            check_language_ub,
171            "Alignment::new_unchecked requires a power of two",
172            (align: usize = align) => align.is_power_of_two()
173        );
174
175        // SAFETY: By precondition, this must be a power of two, and
176        // our variants encompass all possible powers of two.
177        unsafe { mem::transmute::<usize, Alignment>(align) }
178    }
179
180    /// Returns the alignment as a [`usize`].
181    #[unstable(feature = "ptr_alignment_type", issue = "102070")]
182    #[inline]
183    pub const fn as_usize(self) -> usize {
184        // Going through `as_nonzero` helps this be more clearly the inverse of
185        // `new_unchecked`, letting MIR optimizations fold it away.
186
187        self.as_nonzero().get()
188    }
189
190    /// Returns the alignment as a <code>[NonZero]<[usize]></code>.
191    #[unstable(feature = "ptr_alignment_type", issue = "102070")]
192    #[inline]
193    pub const fn as_nonzero(self) -> NonZero<usize> {
194        // This transmutes directly to avoid the UbCheck in `NonZero::new_unchecked`
195        // since there's no way for the user to trip that check anyway -- the
196        // validity invariant of the type would have to have been broken earlier --
197        // and emitting it in an otherwise simple method is bad for compile time.
198
199        // SAFETY: All the discriminants are non-zero.
200        unsafe { mem::transmute::<Alignment, NonZero<usize>>(self) }
201    }
202
203    /// Returns the base-2 logarithm of the alignment.
204    ///
205    /// This is always exact, as `self` represents a power of two.
206    ///
207    /// # Examples
208    ///
209    /// ```
210    /// #![feature(ptr_alignment_type)]
211    /// use std::ptr::Alignment;
212    ///
213    /// assert_eq!(Alignment::of::<u8>().log2(), 0);
214    /// assert_eq!(Alignment::new(1024).unwrap().log2(), 10);
215    /// ```
216    #[unstable(feature = "ptr_alignment_type", issue = "102070")]
217    #[inline]
218    pub const fn log2(self) -> u32 {
219        self.as_nonzero().trailing_zeros()
220    }
221
222    /// Returns a bit mask that can be used to match this alignment.
223    ///
224    /// This is equivalent to `!(self.as_usize() - 1)`.
225    ///
226    /// # Examples
227    ///
228    /// ```
229    /// #![feature(ptr_alignment_type)]
230    /// #![feature(ptr_mask)]
231    /// use std::ptr::{Alignment, NonNull};
232    ///
233    /// #[repr(align(1))] struct Align1(u8);
234    /// #[repr(align(2))] struct Align2(u16);
235    /// #[repr(align(4))] struct Align4(u32);
236    /// let one = <NonNull<Align1>>::dangling().as_ptr();
237    /// let two = <NonNull<Align2>>::dangling().as_ptr();
238    /// let four = <NonNull<Align4>>::dangling().as_ptr();
239    ///
240    /// assert_eq!(four.mask(Alignment::of::<Align1>().mask()), four);
241    /// assert_eq!(four.mask(Alignment::of::<Align2>().mask()), four);
242    /// assert_eq!(four.mask(Alignment::of::<Align4>().mask()), four);
243    /// assert_ne!(one.mask(Alignment::of::<Align4>().mask()), one);
244    /// ```
245    #[unstable(feature = "ptr_alignment_type", issue = "102070")]
246    #[inline]
247    #[cfg(not(feature = "ferrocene_subset"))]
248    pub const fn mask(self) -> usize {
249        // SAFETY: The alignment is always nonzero, and therefore decrementing won't overflow.
250        !(unsafe { self.as_usize().unchecked_sub(1) })
251    }
252
253    // FIXME(const-hack) Remove me once `Ord::max` is usable in const
254    #[cfg(not(feature = "ferrocene_subset"))]
255    pub(crate) const fn max(a: Self, b: Self) -> Self {
256        if a.as_usize() > b.as_usize() { a } else { b }
257    }
258}
259
260#[unstable(feature = "ptr_alignment_type", issue = "102070")]
261impl fmt::Debug for Alignment {
262    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
263        write!(f, "{:?} (1 << {:?})", self.as_nonzero(), self.log2())
264    }
265}
266
267#[unstable(feature = "ptr_alignment_type", issue = "102070")]
268#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
269#[cfg(not(feature = "ferrocene_subset"))]
270impl const TryFrom<NonZero<usize>> for Alignment {
271    type Error = num::TryFromIntError;
272
273    #[inline]
274    fn try_from(align: NonZero<usize>) -> Result<Alignment, Self::Error> {
275        align.get().try_into()
276    }
277}
278
279#[unstable(feature = "ptr_alignment_type", issue = "102070")]
280#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
281#[cfg(not(feature = "ferrocene_subset"))]
282impl const TryFrom<usize> for Alignment {
283    type Error = num::TryFromIntError;
284
285    #[inline]
286    fn try_from(align: usize) -> Result<Alignment, Self::Error> {
287        Self::new(align).ok_or(num::TryFromIntError(()))
288    }
289}
290
291#[unstable(feature = "ptr_alignment_type", issue = "102070")]
292#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
293#[cfg(not(feature = "ferrocene_subset"))]
294impl const From<Alignment> for NonZero<usize> {
295    #[inline]
296    fn from(align: Alignment) -> NonZero<usize> {
297        align.as_nonzero()
298    }
299}
300
301#[unstable(feature = "ptr_alignment_type", issue = "102070")]
302#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
303#[cfg(not(feature = "ferrocene_subset"))]
304impl const From<Alignment> for usize {
305    #[inline]
306    fn from(align: Alignment) -> usize {
307        align.as_usize()
308    }
309}
310
311#[unstable(feature = "ptr_alignment_type", issue = "102070")]
312#[cfg(not(feature = "ferrocene_subset"))]
313impl cmp::Ord for Alignment {
314    #[inline]
315    fn cmp(&self, other: &Self) -> cmp::Ordering {
316        self.as_nonzero().get().cmp(&other.as_nonzero().get())
317    }
318}
319
320#[unstable(feature = "ptr_alignment_type", issue = "102070")]
321#[cfg(not(feature = "ferrocene_subset"))]
322impl cmp::PartialOrd for Alignment {
323    #[inline]
324    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
325        Some(self.cmp(other))
326    }
327}
328
329#[unstable(feature = "ptr_alignment_type", issue = "102070")]
330impl hash::Hash for Alignment {
331    #[inline]
332    fn hash<H: hash::Hasher>(&self, state: &mut H) {
333        self.as_nonzero().hash(state)
334    }
335}
336
337/// Returns [`Alignment::MIN`], which is valid for any type.
338#[unstable(feature = "ptr_alignment_type", issue = "102070")]
339#[rustc_const_unstable(feature = "const_default", issue = "143894")]
340#[cfg(not(feature = "ferrocene_subset"))]
341impl const Default for Alignment {
342    fn default() -> Alignment {
343        Alignment::MIN
344    }
345}
346
347#[cfg(target_pointer_width = "16")]
348#[derive(Copy, Clone, PartialEq, Eq)]
349#[repr(usize)]
350enum AlignmentEnum {
351    _Align1Shl0 = 1 << 0,
352    _Align1Shl1 = 1 << 1,
353    _Align1Shl2 = 1 << 2,
354    _Align1Shl3 = 1 << 3,
355    _Align1Shl4 = 1 << 4,
356    _Align1Shl5 = 1 << 5,
357    _Align1Shl6 = 1 << 6,
358    _Align1Shl7 = 1 << 7,
359    _Align1Shl8 = 1 << 8,
360    _Align1Shl9 = 1 << 9,
361    _Align1Shl10 = 1 << 10,
362    _Align1Shl11 = 1 << 11,
363    _Align1Shl12 = 1 << 12,
364    _Align1Shl13 = 1 << 13,
365    _Align1Shl14 = 1 << 14,
366    _Align1Shl15 = 1 << 15,
367}
368
369#[cfg(target_pointer_width = "32")]
370#[derive(Copy, Clone, PartialEq, Eq)]
371#[repr(usize)]
372enum AlignmentEnum {
373    _Align1Shl0 = 1 << 0,
374    _Align1Shl1 = 1 << 1,
375    _Align1Shl2 = 1 << 2,
376    _Align1Shl3 = 1 << 3,
377    _Align1Shl4 = 1 << 4,
378    _Align1Shl5 = 1 << 5,
379    _Align1Shl6 = 1 << 6,
380    _Align1Shl7 = 1 << 7,
381    _Align1Shl8 = 1 << 8,
382    _Align1Shl9 = 1 << 9,
383    _Align1Shl10 = 1 << 10,
384    _Align1Shl11 = 1 << 11,
385    _Align1Shl12 = 1 << 12,
386    _Align1Shl13 = 1 << 13,
387    _Align1Shl14 = 1 << 14,
388    _Align1Shl15 = 1 << 15,
389    _Align1Shl16 = 1 << 16,
390    _Align1Shl17 = 1 << 17,
391    _Align1Shl18 = 1 << 18,
392    _Align1Shl19 = 1 << 19,
393    _Align1Shl20 = 1 << 20,
394    _Align1Shl21 = 1 << 21,
395    _Align1Shl22 = 1 << 22,
396    _Align1Shl23 = 1 << 23,
397    _Align1Shl24 = 1 << 24,
398    _Align1Shl25 = 1 << 25,
399    _Align1Shl26 = 1 << 26,
400    _Align1Shl27 = 1 << 27,
401    _Align1Shl28 = 1 << 28,
402    _Align1Shl29 = 1 << 29,
403    _Align1Shl30 = 1 << 30,
404    _Align1Shl31 = 1 << 31,
405}
406
407#[cfg(target_pointer_width = "64")]
408#[derive(Copy, Clone, PartialEq, Eq)]
409#[repr(usize)]
410enum AlignmentEnum {
411    _Align1Shl0 = 1 << 0,
412    _Align1Shl1 = 1 << 1,
413    _Align1Shl2 = 1 << 2,
414    _Align1Shl3 = 1 << 3,
415    _Align1Shl4 = 1 << 4,
416    _Align1Shl5 = 1 << 5,
417    _Align1Shl6 = 1 << 6,
418    _Align1Shl7 = 1 << 7,
419    _Align1Shl8 = 1 << 8,
420    _Align1Shl9 = 1 << 9,
421    _Align1Shl10 = 1 << 10,
422    _Align1Shl11 = 1 << 11,
423    _Align1Shl12 = 1 << 12,
424    _Align1Shl13 = 1 << 13,
425    _Align1Shl14 = 1 << 14,
426    _Align1Shl15 = 1 << 15,
427    _Align1Shl16 = 1 << 16,
428    _Align1Shl17 = 1 << 17,
429    _Align1Shl18 = 1 << 18,
430    _Align1Shl19 = 1 << 19,
431    _Align1Shl20 = 1 << 20,
432    _Align1Shl21 = 1 << 21,
433    _Align1Shl22 = 1 << 22,
434    _Align1Shl23 = 1 << 23,
435    _Align1Shl24 = 1 << 24,
436    _Align1Shl25 = 1 << 25,
437    _Align1Shl26 = 1 << 26,
438    _Align1Shl27 = 1 << 27,
439    _Align1Shl28 = 1 << 28,
440    _Align1Shl29 = 1 << 29,
441    _Align1Shl30 = 1 << 30,
442    _Align1Shl31 = 1 << 31,
443    _Align1Shl32 = 1 << 32,
444    _Align1Shl33 = 1 << 33,
445    _Align1Shl34 = 1 << 34,
446    _Align1Shl35 = 1 << 35,
447    _Align1Shl36 = 1 << 36,
448    _Align1Shl37 = 1 << 37,
449    _Align1Shl38 = 1 << 38,
450    _Align1Shl39 = 1 << 39,
451    _Align1Shl40 = 1 << 40,
452    _Align1Shl41 = 1 << 41,
453    _Align1Shl42 = 1 << 42,
454    _Align1Shl43 = 1 << 43,
455    _Align1Shl44 = 1 << 44,
456    _Align1Shl45 = 1 << 45,
457    _Align1Shl46 = 1 << 46,
458    _Align1Shl47 = 1 << 47,
459    _Align1Shl48 = 1 << 48,
460    _Align1Shl49 = 1 << 49,
461    _Align1Shl50 = 1 << 50,
462    _Align1Shl51 = 1 << 51,
463    _Align1Shl52 = 1 << 52,
464    _Align1Shl53 = 1 << 53,
465    _Align1Shl54 = 1 << 54,
466    _Align1Shl55 = 1 << 55,
467    _Align1Shl56 = 1 << 56,
468    _Align1Shl57 = 1 << 57,
469    _Align1Shl58 = 1 << 58,
470    _Align1Shl59 = 1 << 59,
471    _Align1Shl60 = 1 << 60,
472    _Align1Shl61 = 1 << 61,
473    _Align1Shl62 = 1 << 62,
474    _Align1Shl63 = 1 << 63,
475}