core/ptr/
alignment.rs

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