1#![no_std]
2#![cfg_attr(feature = "freeze", feature(freeze))]
3#![cfg_attr(feature = "unstable_docs", feature(doc_auto_cfg))]
4
5#[cfg(feature = "freeze")]
6use core::marker::Freeze;
7use core::{
8 borrow::{Borrow, BorrowMut},
9 fmt,
10 hash::Hash,
11 mem::MaybeUninit,
12 panic::{RefUnwindSafe, UnwindSafe},
13};
14
15#[cfg_attr(feature = "bytemuck", doc = "[`bytemuck::AnyBitPattern`]")]
23#[cfg_attr(
24 not(feature = "bytemuck"),
25 doc = "[`bytemuck::AnyBitPattern`](https://docs.rs/bytemuck/latest/bytemuck/trait.AnyBitPattern.html)"
26)]
27#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
41#[repr(C)]
42pub struct Aligned<T: ?Sized, const ALIGNMENT: usize>
43where
44 Alignment<ALIGNMENT>: SupportedAlignment,
45{
46 pub align: AlignedZst<ALIGNMENT>,
47 pub inner: T,
48}
49
50impl<T: ?Sized + Hash, const ALIGNMENT: usize> Hash for Aligned<T, ALIGNMENT>
51where
52 Alignment<ALIGNMENT>: SupportedAlignment,
53{
54 #[inline]
55 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
56 T::hash(&self.inner, state)
57 }
58}
59
60impl<T: ?Sized, const ALIGNMENT: usize> AsRef<T> for Aligned<T, ALIGNMENT>
61where
62 Alignment<ALIGNMENT>: SupportedAlignment,
63{
64 #[inline]
65 fn as_ref(&self) -> &T {
66 &self.inner
67 }
68}
69
70impl<T: ?Sized, const ALIGNMENT: usize> AsMut<T> for Aligned<T, ALIGNMENT>
71where
72 Alignment<ALIGNMENT>: SupportedAlignment,
73{
74 #[inline]
75 fn as_mut(&mut self) -> &mut T {
76 &mut self.inner
77 }
78}
79
80impl<T: ?Sized, const ALIGNMENT: usize> Borrow<T> for Aligned<T, ALIGNMENT>
81where
82 Alignment<ALIGNMENT>: SupportedAlignment,
83{
84 #[inline]
85 fn borrow(&self) -> &T {
86 &self.inner
87 }
88}
89
90impl<T: ?Sized, const ALIGNMENT: usize> BorrowMut<T> for Aligned<T, ALIGNMENT>
91where
92 Alignment<ALIGNMENT>: SupportedAlignment,
93{
94 #[inline]
95 fn borrow_mut(&mut self) -> &mut T {
96 &mut self.inner
97 }
98}
99
100impl<T, const ALIGNMENT: usize> Aligned<T, ALIGNMENT>
101where
102 Alignment<ALIGNMENT>: SupportedAlignment,
103{
104 pub const fn new(value: T) -> Self {
106 Self { align: AlignedZst::new(), inner: value }
107 }
108
109 pub fn into_inner(self) -> T {
111 let Self { inner, .. } = self;
112 inner
113 }
114}
115
116#[cfg(feature = "bytemuck")]
119unsafe impl<T, const ALIGNMENT: usize> bytemuck::Zeroable
120 for Aligned<T, ALIGNMENT>
121where
122 T: bytemuck::Zeroable,
123 Alignment<ALIGNMENT>: SupportedAlignment,
124{
125}
126
127#[cfg(feature = "bytemuck")]
130unsafe impl<T, const ALIGNMENT: usize> bytemuck::AnyBitPattern
131 for Aligned<T, ALIGNMENT>
132where
133 T: bytemuck::AnyBitPattern,
134 Alignment<ALIGNMENT>: SupportedAlignment,
135{
136}
137
138#[cfg_attr(feature = "bytemuck", doc = "[`bytemuck::Pod`]")]
146#[cfg_attr(
147 not(feature = "bytemuck"),
148 doc = "[`bytemuck::Pod`](https://docs.rs/bytemuck/latest/bytemuck/trait.Pod.html)"
149)]
150#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
155#[repr(transparent)]
156pub struct AlignedZst<const ALIGNMENT: usize>
157where
158 Alignment<ALIGNMENT>: SupportedAlignment,
159{
160 inner: <Alignment<ALIGNMENT> as SupportedAlignment>::AlignedZst,
161}
162
163impl<const ALIGNMENT: usize> AlignedZst<ALIGNMENT>
164where
165 Alignment<ALIGNMENT>: SupportedAlignment,
166{
167 pub const fn new() -> Self {
172 unsafe { MaybeUninit::uninit().assume_init() }
174 }
175}
176
177impl<const ALIGNMENT: usize> fmt::Debug for AlignedZst<ALIGNMENT>
178where
179 Alignment<ALIGNMENT>: SupportedAlignment,
180{
181 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
182 write!(f, "AlignedZst<{}> {{ .. }}", ALIGNMENT)
183 }
184}
185
186#[cfg(feature = "bytemuck")]
188unsafe impl<const ALIGNMENT: usize> bytemuck::Zeroable for AlignedZst<ALIGNMENT> where
189 Alignment<ALIGNMENT>: SupportedAlignment
190{
191}
192
193#[cfg(feature = "bytemuck")]
195unsafe impl<const ALIGNMENT: usize> bytemuck::Pod for AlignedZst<ALIGNMENT> where
196 Alignment<ALIGNMENT>: SupportedAlignment
197{
198}
199
200mod sealed {
201 pub trait Sealed {}
202}
203
204impl<const N: usize> sealed::Sealed for Alignment<N> {}
205
206#[non_exhaustive]
210pub struct Alignment<const N: usize>;
211
212pub unsafe trait SupportedAlignment: sealed::Sealed {
219 cfg_if::cfg_if! {
220 if #[cfg(feature = "freeze")] {
221 #[doc(hidden)]
223 type AlignedZst: Sized + Default + Copy + Ord + Hash + Send + Sync + Unpin + UnwindSafe + RefUnwindSafe + Freeze + 'static;
224 } else {
225 #[doc(hidden)]
227 type AlignedZst: Sized + Default + Copy + Ord + Hash + Send + Sync + Unpin + UnwindSafe + RefUnwindSafe + 'static;
228 }
229 }
230}
231
232macro_rules! make_zsts {
233 ( $($typename:ident = $alignment:literal;)* ) => { $(
234 #[doc = concat!("Is a ZST with alignment ", stringify!($alignment), ".")]
237 #[doc(hidden)]
238 #[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
239 #[repr(align($alignment))]
240 pub struct $typename;
241
242 unsafe impl SupportedAlignment for Alignment<$alignment> {
243 type AlignedZst = $typename;
244 }
245 )* };
246}
247
248make_zsts! {
249 Align1 = 1;
250 Align2 = 2;
251 Align4 = 4;
252 Align8 = 8;
253 Align16 = 16;
254 Align32 = 32;
255 Align64 = 64;
256 Align128 = 128;
257 Align256 = 256;
258 Align512 = 512;
259 Align1024 = 1024;
260 Align2048 = 2048;
261 Align4096 = 4096;
262 Align8192 = 8192;
263 Align16384 = 16384;
264 Align32768 = 32768;
265}
266#[cfg(not(target_pointer_width = "16"))]
267make_zsts! {
268 Align65536 = 65536;
269 Align131072 = 131072;
270 Align262144 = 262144;
271 Align524288 = 524288;
272 Align1048576 = 1048576;
273 Align2097152 = 2097152;
274 Align4194304 = 4194304;
275 Align8388608 = 8388608;
276 Align16777216 = 16777216;
277 Align33554432 = 33554432;
278 Align67108864 = 67108864;
279 Align134217728 = 134217728;
280 Align268435456 = 268435456;
281 Align536870912 = 536870912;
282}
283
284#[cfg(test)]
285mod tests {
286 extern crate std;
287
288 use crate::{Aligned, AlignedZst, Alignment, SupportedAlignment};
289
290 #[test]
291 fn it_works() {
292 #[derive(Default, Clone, Copy)]
293 struct AlignedThing<const N: usize, T>
294 where
295 Alignment<N>: SupportedAlignment,
296 {
297 _aligned: AlignedZst<N>,
298 value: T,
299 }
300
301 assert_eq!(core::mem::align_of::<AlignedThing<64, u8>>(), 64);
302 assert_eq!(
303 core::mem::align_of::<AlignedThing<4, u64>>(),
304 core::cmp::max(4, core::mem::align_of::<u64>())
305 );
306 assert_eq!(
307 core::mem::align_of::<AlignedThing<536870912, u8>>(),
308 536870912
309 );
310
311 let x: [AlignedThing<64, u8>; 2] =
312 [AlignedThing { value: 42, _aligned: Default::default() }; 2];
313 assert_eq!(
314 (&x[1].value as *const _ as usize)
315 - (&x[0].value as *const _ as usize),
316 64
317 );
318 }
319
320 #[test]
321 fn wrapper_works() {
322 assert_eq!(core::mem::align_of::<Aligned<u8, 64>>(), 64);
323 assert_eq!(
324 core::mem::align_of::<Aligned<u64, 4>>(),
325 core::cmp::max(4, core::mem::align_of::<u64>())
326 );
327 assert_eq!(core::mem::align_of::<Aligned<u8, 536870912>>(), 536870912);
328
329 let x: [Aligned<u8, 64>; 2] = [Aligned::new(42); 2];
330 assert_eq!(
331 (&x[1].inner as *const _ as usize)
332 - (&x[0].inner as *const _ as usize),
333 64
334 );
335 }
336}