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}