1#![deny(missing_docs)]
2#![cfg_attr(feature = "oibit", feature(optin_builtin_traits))]
3
4use std::mem::{transmute, uninitialized, forget, align_of, size_of};
9use std::ptr::write;
10use std::marker::PhantomData;
11
12pub unsafe trait Unaligned { }
17
18pub type Un<T> = <T as Aligned>::Unaligned;
20
21#[inline]
23pub fn is_aligned_for<T, U>(ptr: *const U) -> bool {
24 align_of::<U>() >= align_of::<T>() ||
25 ptr as usize % align_of::<T>() == 0
26}
27
28#[inline]
30pub fn is_aligned_for_slice<T, U>(slice: &[U]) -> bool {
31 is_aligned_for::<T, _>(slice.as_ptr())
32}
33
34#[inline]
36pub fn size_of_slice<T>(slice: &[T]) -> usize {
37 slice.len() * size_of::<T>()
38}
39
40pub unsafe trait Aligned: Sized {
43 type Unaligned: Unaligned + Sized + Copy;
46
47 #[inline]
49 fn is_aligned(unaligned: &Self::Unaligned) -> bool {
50 is_aligned_for::<Self, _>(unaligned)
51 }
52
53 #[inline]
55 fn as_unaligned(&self) -> &Self::Unaligned {
56 unsafe { transmute(self) }
57 }
58
59 #[inline]
61 unsafe fn as_unaligned_mut(&mut self) -> &mut Self::Unaligned {
62 transmute(self)
63 }
64
65 #[inline]
69 fn from_unaligned_ref(unaligned: &Self::Unaligned) -> Option<&Self> {
70 if Self::is_aligned(unaligned) {
71 Some(unsafe { Self::from_unaligned_unchecked(unaligned) })
72 } else {
73 None
74 }
75 }
76
77 #[inline]
81 unsafe fn from_unaligned_mut(unaligned: &mut Self::Unaligned) -> Option<&mut Self> {
82 if Self::is_aligned(unaligned) {
83 Some(Self::from_unaligned_mut_unchecked(unaligned))
84 } else {
85 None
86 }
87 }
88
89 #[inline]
93 unsafe fn from_unaligned_unchecked(unaligned: &Self::Unaligned) -> &Self {
94 transmute(unaligned)
95 }
96
97 #[inline]
101 unsafe fn from_unaligned_mut_unchecked(unaligned: &mut Self::Unaligned) -> &mut Self {
102 transmute(unaligned)
103 }
104
105 #[inline]
107 fn into_unaligned(self) -> Self::Unaligned {
108 unsafe {
109 let mut un: Self::Unaligned = uninitialized();
110 write(&mut un, *self.as_unaligned());
111 forget(self);
112 un
113 }
114 }
115
116 #[inline]
118 unsafe fn from_unaligned(u: Self::Unaligned) -> Self {
119 let mut s: Self = uninitialized();
120 write(s.as_unaligned_mut(), u);
121 s
122 }
123
124 #[doc(hidden)]
125 unsafe fn __assert_unaligned() { }
126}
127
128pub unsafe trait Packed: Unaligned {
133 #[doc(hidden)]
134 fn __assert_unaligned() { }
135}
136
137#[cfg(feature = "oibit")]
138mod impls {
139 use super::Unaligned;
140
141 unsafe impl Unaligned for .. { }
142
143 impl !Unaligned for char { }
145 impl !Unaligned for f32 { }
146 impl !Unaligned for f64 { }
147 impl !Unaligned for i16 { }
148 impl !Unaligned for u16 { }
149 impl !Unaligned for i32 { }
150 impl !Unaligned for u32 { }
151 impl !Unaligned for i64 { }
152 impl !Unaligned for u64 { }
153 impl !Unaligned for isize { }
154 impl !Unaligned for usize { }
155 impl<T> !Unaligned for *const T { }
156 impl<T> !Unaligned for *mut T { }
157 impl<'a, T> !Unaligned for &'a T { }
158 impl<'a, T> !Unaligned for &'a mut T { }
159}
160
161#[cfg(not(feature = "oibit"))]
162mod impls {
163 use super::Unaligned;
164
165 unsafe impl Unaligned for () { }
166 unsafe impl Unaligned for i8 { }
167 unsafe impl Unaligned for u8 { }
168 unsafe impl Unaligned for bool { }
169}
170
171unsafe impl<T> Unaligned for PhantomData<T> { }
172
173macro_rules! aligned_assert {
174 ($t:ident) => {
175 unsafe fn __assert_unaligned() {
176 ::std::mem::forget(::std::mem::transmute::<$t, $t::Unaligned>(::std::mem::uninitialized()));
177 }
178 };
179}
180
181macro_rules! aligned_self {
182 ($t:ty) => {
183 unsafe impl Aligned for $t {
184 type Unaligned = $t;
185 }
186 };
187 ($($t:ty),*) => {
188 $(
189 aligned_self!($t);
190 )*
191 };
192}
193
194macro_rules! aligned_impl {
195 ($t:ident: $s:expr) => {
196 unsafe impl Aligned for $t {
197 type Unaligned = [u8; $s];
198
199 aligned_assert!(Self);
200 }
201 };
202 ($($t:ident: $e:expr),*) => {
203 $(
204 aligned_impl!($t: $e);
205 )*
206 };
207}
208
209aligned_impl! {
210 char: 4,
211 f32: 4,
212 f64: 8,
213 i16: 2,
214 u16: 2,
215 i32: 4,
216 u32: 4,
217 i64: 8,
218 u64: 8
219}
220
221aligned_self! {
222 u8,
223 i8,
224 (),
225 bool
226}
227
228#[cfg(target_pointer_width = "32")]
229mod impl32 {
230 use super::Aligned;
231 aligned_impl! { isize: 4, usize: 4 }
232 unsafe impl<T: Sized> Aligned for *const T { type Unaligned = [u8; 4]; aligned_assert!(Self); }
233 unsafe impl<T: Sized> Aligned for *mut T { type Unaligned = [u8; 4]; aligned_assert!(Self); }
234 unsafe impl<'a, T: Sized> Aligned for &'a T { type Unaligned = [u8; 4]; }
235 unsafe impl<'a, T: Sized> Aligned for &'a mut T { type Unaligned = [u8; 4]; }
236}
237
238#[cfg(target_pointer_width = "64")]
239mod impl64 {
240 use super::Aligned;
241 aligned_impl! { isize: 8, usize: 8 }
242 unsafe impl<T: Sized> Aligned for *const T { type Unaligned = [u8; 8]; aligned_assert!(Self); }
243 unsafe impl<T: Sized> Aligned for *mut T { type Unaligned = [u8; 8]; aligned_assert!(Self); }
244 unsafe impl<'a, T: Sized> Aligned for &'a T { type Unaligned = [u8; 8]; }
245 unsafe impl<'a, T: Sized> Aligned for &'a mut T { type Unaligned = [u8; 8]; }
246}
247
248unsafe impl Packed for () { }
252unsafe impl Packed for i8 { }
253unsafe impl Packed for u8 { }
254unsafe impl Packed for bool { }
255unsafe impl<T> Packed for PhantomData<T> { }
256
257macro_rules! packed_def {
258 (=> $id_0:ident) => {};
259 (=> $id_0:ident $(, $ids:ident)*) => {
260 packed_def! {
261 => $($ids),*
262 }
263
264 unsafe impl<$($ids: Unaligned),*> Unaligned for ($($ids),*,) { }
265
266 unsafe impl<$($ids: Unaligned),*> Packed for ($($ids),*,) { }
268 };
269 ($($x:expr),*) => {
270 $(
271 unsafe impl<T: Unaligned> Unaligned for [T; $x] { }
272
273 unsafe impl<T: Unaligned> Packed for [T; $x] { }
274 )*
275 };
276}
277
278unsafe impl<T: Aligned> Aligned for (T,) {
279 type Unaligned = T::Unaligned;
280}
281
282unsafe impl<T: Aligned> Aligned for [T; 1] {
283 type Unaligned = T::Unaligned;
284}
285
286unsafe impl<T: Aligned> Aligned for [T; 0] {
287 type Unaligned = ();
288}
289
290packed_def! {
291 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
292 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
293 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
294 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
295 0x40,
296 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x800, 0x900, 0xa00, 0xb00, 0xc00, 0xd00, 0xe00, 0xf00,
297 0x1000
298}
299packed_def! { => __, A, B, C, D, E, F, G, H, I, J, K }
300
301#[cfg(test)]
302mod test {
303 use super::*;
304
305 #[test]
306 fn assert_packed() {
307 fn is<T: Packed>() { }
308 fn is_unaligned<T: Unaligned>() { }
309
310 is::<()>();
311 is::<u8>();
312 is::<i8>();
313 is::<bool>();
314 is_unaligned::<(bool, u8)>();
315 }
316
317 #[test]
318 fn unaligned_conversion() {
319 let f = 0.5f32;
320 let x = Aligned::into_unaligned(f);
321 assert!(<f32 as Aligned>::is_aligned(&x));
322 assert_eq!(&f, <f32 as Aligned>::from_unaligned_ref(&x).unwrap());
323 }
324
325 #[test]
326 fn pointer_alignment() {
327 use std::mem::align_of;
328
329 let f = 0.5f32;
330 assert!(is_aligned_for::<f32, _>(&f));
331 assert!(is_aligned_for::<u8, _>(&f));
332 if align_of::<f32>() > 1 {
333 assert!(!is_aligned_for::<f32, _>((&f as *const _ as usize + 1) as *const u8));
334 }
335 }
336}