core/ptr/
alignment.rs

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