enum_ptr/traits/
aligned.rs

1use core::mem::align_of;
2
3/// Types (may not be pointers) that can be used in [`EnumPtr`](crate::EnumPtr).
4///
5/// # Safety
6///
7/// - `T` must be exactly one-pointer wide.
8/// - `T`'s pointee must be aligned by `ALIGNMENT` (`T`'s low bits are zeros).
9///
10/// For example, raw pointers are not guaranteed to be aligned, so implementing
11/// this trait for them is unsound.
12///
13/// # Examples
14///
15/// ```
16/// use enum_ptr::{Aligned, Compact, EnumPtr};
17///
18/// // It's your responsibility to ensure `MyPtr` is always aligned.
19/// struct MyPtr<T>(*const T);
20///
21/// unsafe impl<T> Aligned for MyPtr<T> {
22///     const ALIGNMENT: usize = std::mem::align_of::<T>();
23/// }
24///
25/// #[derive(EnumPtr)]
26/// #[repr(C, usize)]
27/// enum Foo {
28///     A(MyPtr<i64>),
29///     B(MyPtr<u64>),
30/// }
31/// ```
32pub unsafe trait Aligned {
33    const ALIGNMENT: usize;
34}
35
36unsafe impl<T> Aligned for &T {
37    const ALIGNMENT: usize = align_of::<T>();
38}
39
40unsafe impl<T> Aligned for &mut T {
41    const ALIGNMENT: usize = align_of::<T>();
42}
43
44unsafe impl<T> Aligned for Option<&T> {
45    const ALIGNMENT: usize = align_of::<T>();
46}
47
48unsafe impl<T> Aligned for Option<&mut T> {
49    const ALIGNMENT: usize = align_of::<T>();
50}
51
52#[cfg(feature = "alloc")]
53mod alloc_impl {
54    use super::*;
55
56    use alloc::boxed::Box;
57    use alloc::rc::Rc;
58    use alloc::sync::Arc;
59
60    // TODO: remove it when `Ord::max` is made const
61    const fn max(a: usize, b: usize) -> usize {
62        if a > b {
63            a
64        } else {
65            b
66        }
67    }
68
69    unsafe impl<T> Aligned for Box<T> {
70        const ALIGNMENT: usize = align_of::<T>();
71    }
72
73    /// Implementing [`Aligned`] for [`Rc`] relies on some undocumented
74    /// assumptions on its internal representation. However, it's very unlikely
75    /// for these assumptions to be violated in practice.
76    /// [`RcBox` is marked as `repr(C)` and reference counters are typed as `usize`][1].
77    /// Thus, its alignment is defined as [the highest of its members][2] (i.e. among
78    /// max of `usize` and `T`). Lastly, it's unconceivable for the type to be
79    /// lifted with `repr(C)` as commented or to start to use shorter
80    /// integers as counters.
81    ///
82    /// [1]: https://doc.rust-lang.org/1.81.0/src/alloc/rc.rs.html#286-291
83    /// [2]: https://doc.rust-lang.org/reference/type-layout.html#reprc-structs
84    unsafe impl<T> Aligned for Rc<T> {
85        const ALIGNMENT: usize = max(align_of::<T>(), align_of::<usize>());
86    }
87
88    /// Implementing [`Aligned`] for [`Arc`] relies on some undocumented
89    /// assumptions on its internal representation. However, it's very unlikely
90    /// for these assumptions to be violated in practice.
91    /// [`ArcInner` is marked as `repr(C)` and reference counters are typed as `usize`][1].
92    /// Thus, its alignment is defined as [the highest of its members][2] (i.e. among
93    /// max of `usize` and `T`). Lastly, it's unconceivable for the type to be
94    /// lifted with `repr(C)` as commented or to start to use shorter
95    /// integers as counters.
96    ///
97    /// [1]: https://doc.rust-lang.org/1.81.0/src/alloc/sync.rs.html#349-359
98    /// [2]: https://doc.rust-lang.org/reference/type-layout.html#reprc-structs
99    unsafe impl<T> Aligned for Arc<T> {
100        const ALIGNMENT: usize = max(align_of::<T>(), align_of::<usize>());
101    }
102
103    unsafe impl<T> Aligned for Option<Box<T>> {
104        const ALIGNMENT: usize = align_of::<T>();
105    }
106
107    /// On top of the safety reasoning of `impl Align for Rc<T>`, implementing [`Aligned`]
108    /// for `Option<Rc<T>>` is safe as well. `Rc` holds [a pointer to its `RcBox` as
109    /// `NonNull<RcBox<T>>`][1]
110    /// And the `Option`-ed type (i.e. `Option<NonNull<RcBox<T>>>`) is explicitly guaranteed
111    /// to be [same as the original type in terms of size and alignment][2].
112    ///
113    /// [1]: https://doc.rust-lang.org/1.81.0/src/alloc/rc.rs.html#315-322
114    /// [2]: https://doc.rust-lang.org/nightly/std/option/index.html#representation
115    unsafe impl<T> Aligned for Option<Rc<T>> {
116        const ALIGNMENT: usize = max(align_of::<T>(), align_of::<usize>());
117    }
118
119    /// On top of the safety reasoning of `impl Align for Arc<T>`, implementing [`Aligned`]
120    /// for `Option<Arc<T>>` is safe as well. `Arc` holds [a pointer to its `ArcInner` as
121    /// `NonNull<ArcInner<T>>`][1]
122    /// And the `Option`-ed type (i.e. `Option<NonNull<ArcInner<T>>>`) is explicitly guaranteed
123    /// to be [same as the original type in terms of size and alignment][2].
124    ///
125    /// [1]: https://doc.rust-lang.org/nightly/src/alloc/sync.rs.html#241-248
126    /// [2]: https://doc.rust-lang.org/nightly/std/option/index.html#representation
127    unsafe impl<T> Aligned for Option<Arc<T>> {
128        const ALIGNMENT: usize = max(align_of::<T>(), align_of::<usize>());
129    }
130}