1 | //! A newtype with alignment of at least `A` bytes |
2 | //! |
3 | //! # Examples |
4 | //! |
5 | //! ``` |
6 | //! use std::mem; |
7 | //! |
8 | //! use aligned::{Aligned, A2, A4, A16}; |
9 | //! |
10 | //! // Array aligned to a 2 byte boundary |
11 | //! static X: Aligned<A2, [u8; 3]> = Aligned([0; 3]); |
12 | //! |
13 | //! // Array aligned to a 4 byte boundary |
14 | //! static Y: Aligned<A4, [u8; 3]> = Aligned([0; 3]); |
15 | //! |
16 | //! // Unaligned array |
17 | //! static Z: [u8; 3] = [0; 3]; |
18 | //! |
19 | //! // You can allocate the aligned arrays on the stack too |
20 | //! let w: Aligned<A16, _> = Aligned([0u8; 3]); |
21 | //! |
22 | //! assert_eq!(mem::align_of_val(&X), 2); |
23 | //! assert_eq!(mem::align_of_val(&Y), 4); |
24 | //! assert_eq!(mem::align_of_val(&Z), 1); |
25 | //! assert_eq!(mem::align_of_val(&w), 16); |
26 | //! ``` |
27 | |
28 | #![deny (missing_docs)] |
29 | #![deny (warnings)] |
30 | #![cfg_attr (not(test), no_std)] |
31 | |
32 | use core::{ |
33 | borrow::{Borrow, BorrowMut}, |
34 | cmp::Ordering, |
35 | fmt::{Debug, Display}, |
36 | hash::{Hash, Hasher}, |
37 | ops, |
38 | }; |
39 | |
40 | use as_slice::{AsMutSlice, AsSlice}; |
41 | |
42 | /// A marker trait for an alignment value. |
43 | pub trait Alignment: Copy + sealed::Sealed {} |
44 | |
45 | impl Alignment for A1 {} |
46 | impl Alignment for A2 {} |
47 | impl Alignment for A4 {} |
48 | impl Alignment for A8 {} |
49 | impl Alignment for A16 {} |
50 | impl Alignment for A32 {} |
51 | impl Alignment for A64 {} |
52 | |
53 | mod sealed { |
54 | pub trait Sealed {} |
55 | |
56 | impl Sealed for super::A1 {} |
57 | impl Sealed for super::A2 {} |
58 | impl Sealed for super::A4 {} |
59 | impl Sealed for super::A8 {} |
60 | impl Sealed for super::A16 {} |
61 | impl Sealed for super::A32 {} |
62 | impl Sealed for super::A64 {} |
63 | } |
64 | |
65 | /// 1-byte alignment |
66 | #[derive (Clone, Copy)] |
67 | #[repr (align(1))] |
68 | pub struct A1; |
69 | |
70 | /// 2-byte alignment |
71 | #[derive (Clone, Copy)] |
72 | #[repr (align(2))] |
73 | pub struct A2; |
74 | |
75 | /// 4-byte alignment |
76 | #[derive (Clone, Copy)] |
77 | #[repr (align(4))] |
78 | pub struct A4; |
79 | |
80 | /// 8-byte alignment |
81 | #[derive (Clone, Copy)] |
82 | #[repr (align(8))] |
83 | pub struct A8; |
84 | |
85 | /// 16-byte alignment |
86 | #[derive (Clone, Copy)] |
87 | #[repr (align(16))] |
88 | pub struct A16; |
89 | |
90 | /// 32-byte alignment |
91 | #[derive (Clone, Copy)] |
92 | #[repr (align(32))] |
93 | pub struct A32; |
94 | |
95 | /// 64-byte alignment |
96 | #[derive (Clone, Copy)] |
97 | #[repr (align(64))] |
98 | pub struct A64; |
99 | |
100 | /// A newtype with alignment of at least `A` bytes |
101 | #[repr (C)] |
102 | pub struct Aligned<A, T> |
103 | where |
104 | T: ?Sized, |
105 | { |
106 | _alignment: [A; 0], |
107 | value: T, |
108 | } |
109 | |
110 | /// Changes the alignment of `value` to be at least `A` bytes |
111 | #[allow (non_snake_case)] |
112 | pub const fn Aligned<A, T>(value: T) -> Aligned<A, T> { |
113 | Aligned { |
114 | _alignment: [], |
115 | value, |
116 | } |
117 | } |
118 | |
119 | impl<A, T> ops::Deref for Aligned<A, T> |
120 | where |
121 | A: Alignment, |
122 | T: ?Sized, |
123 | { |
124 | type Target = T; |
125 | |
126 | fn deref(&self) -> &T { |
127 | &self.value |
128 | } |
129 | } |
130 | |
131 | impl<A, T> ops::DerefMut for Aligned<A, T> |
132 | where |
133 | A: Alignment, |
134 | T: ?Sized, |
135 | { |
136 | fn deref_mut(&mut self) -> &mut T { |
137 | &mut self.value |
138 | } |
139 | } |
140 | |
141 | impl<A, T> ops::Index<ops::RangeTo<usize>> for Aligned<A, [T]> |
142 | where |
143 | A: Alignment, |
144 | { |
145 | type Output = Aligned<A, [T]>; |
146 | |
147 | fn index(&self, range: ops::RangeTo<usize>) -> &Aligned<A, [T]> { |
148 | unsafe { &*(&self.value[range] as *const [T] as *const Aligned<A, [T]>) } |
149 | } |
150 | } |
151 | |
152 | impl<A, T> AsSlice for Aligned<A, T> |
153 | where |
154 | A: Alignment, |
155 | T: AsSlice, |
156 | { |
157 | type Element = T::Element; |
158 | |
159 | fn as_slice(&self) -> &[T::Element] { |
160 | T::as_slice(&**self) |
161 | } |
162 | } |
163 | |
164 | impl<A, T> AsMutSlice for Aligned<A, T> |
165 | where |
166 | A: Alignment, |
167 | T: AsMutSlice, |
168 | { |
169 | fn as_mut_slice(&mut self) -> &mut [T::Element] { |
170 | T::as_mut_slice(&mut **self) |
171 | } |
172 | } |
173 | |
174 | impl<A, T> Borrow<T> for Aligned<A, T> |
175 | where |
176 | A: Alignment, |
177 | { |
178 | fn borrow(&self) -> &T { |
179 | &self.value |
180 | } |
181 | } |
182 | |
183 | impl<A, T> BorrowMut<T> for Aligned<A, T> |
184 | where |
185 | A: Alignment, |
186 | { |
187 | fn borrow_mut(&mut self) -> &mut T { |
188 | &mut self.value |
189 | } |
190 | } |
191 | |
192 | impl<A, T> Borrow<[<Aligned<A, T> as AsSlice>::Element]> for Aligned<A, T> |
193 | where |
194 | A: Alignment, |
195 | Aligned<A, T>: AsSlice, |
196 | { |
197 | fn borrow(&self) -> &[<Aligned<A, T> as AsSlice>::Element] { |
198 | self.as_slice() |
199 | } |
200 | } |
201 | |
202 | impl<A, T> BorrowMut<[<Aligned<A, T> as AsSlice>::Element]> for Aligned<A, T> |
203 | where |
204 | A: Alignment, |
205 | Aligned<A, T>: AsMutSlice, |
206 | { |
207 | fn borrow_mut(&mut self) -> &mut [<Aligned<A, T> as AsSlice>::Element] { |
208 | self.as_mut_slice() |
209 | } |
210 | } |
211 | |
212 | impl<A, T> Clone for Aligned<A, T> |
213 | where |
214 | A: Alignment, |
215 | T: Clone, |
216 | { |
217 | fn clone(&self) -> Self { |
218 | Self { |
219 | _alignment: [], |
220 | value: self.value.clone(), |
221 | } |
222 | } |
223 | } |
224 | |
225 | impl<A, T> Copy for Aligned<A, T> |
226 | where |
227 | A: Alignment, |
228 | T: Copy, |
229 | { |
230 | } |
231 | |
232 | impl<A, T> Default for Aligned<A, T> |
233 | where |
234 | A: Alignment, |
235 | T: Default, |
236 | { |
237 | fn default() -> Self { |
238 | Self { |
239 | _alignment: [], |
240 | value: Default::default(), |
241 | } |
242 | } |
243 | } |
244 | |
245 | impl<A, T> Debug for Aligned<A, T> |
246 | where |
247 | A: Alignment, |
248 | T: Debug, |
249 | { |
250 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
251 | self.value.fmt(f) |
252 | } |
253 | } |
254 | |
255 | impl<A, T> Display for Aligned<A, T> |
256 | where |
257 | A: Alignment, |
258 | T: Display, |
259 | { |
260 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
261 | self.value.fmt(f) |
262 | } |
263 | } |
264 | |
265 | impl<A, T> PartialEq for Aligned<A, T> |
266 | where |
267 | A: Alignment, |
268 | T: PartialEq, |
269 | { |
270 | fn eq(&self, other: &Self) -> bool { |
271 | self.value == other.value |
272 | } |
273 | } |
274 | |
275 | impl<A, T> Eq for Aligned<A, T> |
276 | where |
277 | A: Alignment, |
278 | T: Eq, |
279 | { |
280 | } |
281 | |
282 | impl<A, T> Hash for Aligned<A, T> |
283 | where |
284 | A: Alignment, |
285 | T: Hash, |
286 | { |
287 | fn hash<H: Hasher>(&self, state: &mut H) { |
288 | self.value.hash(state); |
289 | } |
290 | } |
291 | |
292 | impl<A, T> Ord for Aligned<A, T> |
293 | where |
294 | A: Alignment, |
295 | T: Ord, |
296 | { |
297 | fn cmp(&self, other: &Self) -> Ordering { |
298 | self.value.cmp(&other.value) |
299 | } |
300 | } |
301 | |
302 | impl<A, T> PartialOrd for Aligned<A, T> |
303 | where |
304 | A: Alignment, |
305 | T: PartialOrd, |
306 | { |
307 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { |
308 | self.value.partial_cmp(&other.value) |
309 | } |
310 | } |
311 | |
312 | #[test ] |
313 | fn sanity() { |
314 | use core::mem; |
315 | |
316 | let a: Aligned<A1, _> = Aligned([0u8; 3]); |
317 | let x: Aligned<A2, _> = Aligned([0u8; 3]); |
318 | let y: Aligned<A4, _> = Aligned([0u8; 3]); |
319 | let z: Aligned<A8, _> = Aligned([0u8; 3]); |
320 | let w: Aligned<A16, _> = Aligned([0u8; 3]); |
321 | |
322 | // check alignment |
323 | assert_eq!(mem::align_of_val(&a), 1); |
324 | assert_eq!(mem::align_of_val(&x), 2); |
325 | assert_eq!(mem::align_of_val(&y), 4); |
326 | assert_eq!(mem::align_of_val(&z), 8); |
327 | assert_eq!(mem::align_of_val(&w), 16); |
328 | |
329 | assert!(a.as_ptr() as usize % 1 == 0); |
330 | assert!(x.as_ptr() as usize % 2 == 0); |
331 | assert!(y.as_ptr() as usize % 4 == 0); |
332 | assert!(z.as_ptr() as usize % 8 == 0); |
333 | assert!(w.as_ptr() as usize % 16 == 0); |
334 | |
335 | // test `deref` |
336 | assert_eq!(a.len(), 3); |
337 | assert_eq!(x.len(), 3); |
338 | assert_eq!(y.len(), 3); |
339 | assert_eq!(z.len(), 3); |
340 | assert_eq!(w.len(), 3); |
341 | |
342 | // alignment should be preserved after slicing |
343 | let a: &Aligned<_, [_]> = &a; |
344 | let x: &Aligned<_, [_]> = &x; |
345 | let y: &Aligned<_, [_]> = &y; |
346 | let z: &Aligned<_, [_]> = &z; |
347 | let w: &Aligned<_, [_]> = &w; |
348 | |
349 | let a: &Aligned<_, _> = &a[..2]; |
350 | let x: &Aligned<_, _> = &x[..2]; |
351 | let y: &Aligned<_, _> = &y[..2]; |
352 | let z: &Aligned<_, _> = &z[..2]; |
353 | let w: &Aligned<_, _> = &w[..2]; |
354 | |
355 | assert!(a.as_ptr() as usize % 1 == 0); |
356 | assert!(x.as_ptr() as usize % 2 == 0); |
357 | assert!(y.as_ptr() as usize % 4 == 0); |
358 | assert!(z.as_ptr() as usize % 8 == 0); |
359 | assert!(w.as_ptr() as usize % 16 == 0); |
360 | |
361 | // alignment should be preserved after boxing |
362 | let a: Box<Aligned<A1, [u8]>> = Box::new(Aligned([0u8; 3])); |
363 | let x: Box<Aligned<A2, [u8]>> = Box::new(Aligned([0u8; 3])); |
364 | let y: Box<Aligned<A4, [u8]>> = Box::new(Aligned([0u8; 3])); |
365 | let z: Box<Aligned<A8, [u8]>> = Box::new(Aligned([0u8; 3])); |
366 | let w: Box<Aligned<A16, [u8]>> = Box::new(Aligned([0u8; 3])); |
367 | |
368 | assert_eq!(mem::align_of_val(&*a), 1); |
369 | assert_eq!(mem::align_of_val(&*x), 2); |
370 | assert_eq!(mem::align_of_val(&*y), 4); |
371 | assert_eq!(mem::align_of_val(&*z), 8); |
372 | assert_eq!(mem::align_of_val(&*w), 16); |
373 | |
374 | // test coercions |
375 | let x: Aligned<A2, _> = Aligned([0u8; 3]); |
376 | let y: &Aligned<A2, [u8]> = &x; |
377 | let _: &[u8] = y; |
378 | } |
379 | |