core/ptr/
alignment.rs

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