core/ptr/
alignment.rs

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

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy