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