maligned/
align.rs

1use core::mem::size_of;
2#[cfg(test)]
3use core::mem::{align_of, size_of_val};
4
5mod sealed_traits {
6  pub trait SealedAlignment {}
7
8  pub trait SealedAsBytes {}
9
10  pub trait SealedAsBytesMut: SealedAsBytes {}
11}
12
13/// Marker trait used for bounds.
14/// All structs that implement this trait have their size and alignment equal.
15pub trait Alignment: sealed_traits::SealedAlignment + Sized + Clone + Default + Send + Sync {}
16
17/// Trait that allows reinterpretation of a struct as bytes. This is unsafe since the
18/// returned slice must always have a length equal to the size of the struct and because
19/// every bit pattern within the structs size must be valid.
20#[allow(unsafe_code)]
21pub unsafe trait AsBytes: sealed_traits::SealedAsBytes + Sized {
22  /// Turn a reference to self to a byte slice.
23  #[must_use]
24  fn as_bytes(&self) -> &[u8];
25}
26
27/// Trait that allows reinterpretation of a mutable struct as mutable bytes. This is unsafe since the
28/// returned slice must always have a length equal to the size of the struct and because
29/// every bit pattern within the structs size must be valid.
30#[allow(unsafe_code)]
31pub unsafe trait AsBytesMut: sealed_traits::SealedAsBytesMut + AsBytes {
32  /// Turn a mutable reference to self to a mutable byte slice.
33  #[must_use]
34  fn as_bytes_mut(&mut self) -> &mut [u8];
35}
36
37/// Representation of failure to convert from a byte slice to some alignment type.
38#[derive(Debug)]
39pub struct FromByteSliceError {
40  actual_len: usize,
41  expected_len: usize,
42}
43
44impl FromByteSliceError {
45  #[must_use]
46  /// Returns the length of the slice that failed to convert to an alignment type.
47  pub fn actual_len(&self) -> usize {
48    self.actual_len
49  }
50  #[must_use]
51  /// Returns the length that the alignment type expected the slice to be when converting.
52  pub fn expected_len(&self) -> usize {
53    self.expected_len
54  }
55}
56
57impl core::fmt::Display for FromByteSliceError {
58  fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
59    write!(
60      f,
61      "Invalid length. Expected slice of length {} got {}",
62      self.expected_len, self.actual_len
63    )
64  }
65}
66
67macro_rules! doc_comment {
68    ($x:expr, $($tt:tt)*) => {
69        #[doc = $x]
70        $($tt)*
71    };
72}
73
74macro_rules! impl_alignment_traits {
75  {
76    $(#[$outer:meta])*
77    $v:vis struct $t:ident or $bit:ident $(or $k_alias:ident)?(pub [u8; $c:literal]);
78    test = $test:ident
79  }
80    => {
81    doc_comment! {
82      concat!(
83        "Struct representing an alignment of ",
84        stringify!($c),
85        "\n\n",
86        "This implements the [Alignment](Alignment) trait and can also be used as a byte buffer\n",
87        "of `[u8; ", stringify!($c), "]`. Since `AsBytes` is implemented for a `&[T: AsBytes]` a `&[A", stringify!($c), "]`\n",
88        "can be used as a buffer of bytes that will always be aligned to at least ", stringify!($c), " bytes.\n\n",
89        "Also aliased by [", stringify!($bit), "](", stringify!($bit), ")", $(" and [", stringify!($k_alias), "](", stringify!($k_alias), ")",)? "\n\n",
90      ),
91      $(#[$outer])*
92      #[repr(align($c))]
93      $v struct $t(pub [u8; $c]);
94    }
95    impl sealed_traits::SealedAlignment for $t {}
96    impl Alignment for $t {}
97    doc_comment! {
98      concat!("Type alias for [", stringify!($t), "](", stringify!($t), ") in bits"),
99      pub type $bit = $t;
100    }
101    $(
102      doc_comment! {
103        concat!("Type alias for [", stringify!($t), "](struct.", stringify!($t), ".html) in kilobytes"),
104        pub type $k_alias = $t;
105      }
106    )?
107    // Not a trait since const generics aren't stable yet
108    #[doc(hidden)]
109    impl $t {
110      #[must_use]
111      pub fn as_array(&self) -> &[u8; size_of::<Self>()] {
112        &self.0
113      }
114      #[must_use]
115      pub fn as_array_mut(&mut self) -> &mut [u8; size_of::<Self>()] {
116        &mut self.0
117      }
118      #[must_use]
119      pub fn into_array(self) -> [u8; size_of::<Self>()] {
120        self.0
121      }
122    }
123    impl sealed_traits::SealedAsBytes for $t {}
124    #[allow(unsafe_code)]
125    unsafe impl AsBytes for $t {
126      #[inline]
127      #[must_use]
128      fn as_bytes(&self) -> &[u8] {
129        unsafe { core::slice::from_raw_parts(&self.0 as *const [u8; size_of::<Self>()] as *const u8, size_of::<Self>()) }
130      }
131    }
132    impl sealed_traits::SealedAsBytesMut for $t {}
133    #[allow(unsafe_code)]
134    unsafe impl AsBytesMut for $t {
135      #[inline]
136      #[must_use]
137      fn as_bytes_mut(&mut self) -> &mut [u8] {
138        unsafe { core::slice::from_raw_parts_mut(&mut self.0 as *mut [u8; size_of::<Self>()] as *mut u8, size_of::<Self>()) }
139      }
140    }
141    impl Default for $t {
142      fn default() -> Self {
143        Self([0; size_of::<Self>()])
144      }
145    }
146    // Allow this so that some types can be copy and
147    // this implentation should be what is already generated
148    #[allow(clippy::expl_impl_clone_on_copy)]
149    impl Clone for $t {
150      fn clone(&self) -> Self {
151        let mut clone = Self::default();
152        #[allow(unsafe_code)]
153        unsafe {core::ptr::copy_nonoverlapping(self.as_bytes().as_ptr(), clone.as_bytes_mut().as_mut_ptr(), $c)}
154        clone
155      }
156    }
157    impl core::ops::Deref for $t {
158      type Target = [u8];
159      fn deref(&self) -> &Self::Target {
160        self.as_bytes()
161      }
162    }
163    impl core::ops::DerefMut for $t {
164      fn deref_mut(&mut self) -> &mut Self::Target {
165        self.as_bytes_mut()
166      }
167    }
168    impl From<[u8; size_of::<$t>()]> for $t {
169      fn from(a: [u8; size_of::<Self>()]) -> Self {
170        Self(a)
171      }
172    }
173    impl core::convert::TryFrom<&[u8]> for $t {
174      type Error = FromByteSliceError;
175      fn try_from(v: &[u8]) -> Result<Self, Self::Error> {
176        if v.len() == $c {
177          let mut s = Self::default();
178          v.iter().zip(s.as_bytes_mut()).for_each(|(v, s)| *s = *v);
179          Ok(s)
180        } else {
181          Err(FromByteSliceError {
182            actual_len: v.len(),
183            expected_len: $c,
184          })
185        }
186      }
187    }
188    impl AsRef<[u8]> for $t {
189      fn as_ref(&self) -> &[u8] {
190        self.as_bytes()
191      }
192    }
193    impl AsMut<[u8]> for $t {
194      fn as_mut(&mut self) -> &mut [u8] {
195        self.as_bytes_mut()
196      }
197    }
198    impl Ord for $t {
199      fn cmp(&self, other: &Self) -> core::cmp::Ordering {
200        self.as_bytes()
201          .iter()
202          .zip(other.as_bytes())
203          .filter_map(|(l, r)| {
204            let cmp = l.cmp(r);
205            if let core::cmp::Ordering::Equal = cmp {
206              None
207            } else {
208              Some(cmp)
209            }
210          })
211          .next()
212          .unwrap_or(core::cmp::Ordering::Equal)
213      }
214    }
215    impl PartialOrd for $t {
216      fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
217        self.as_bytes()
218          .iter()
219          .zip(other.as_bytes())
220          .filter_map(|(l, r)|{
221            let cmp = l.partial_cmp(r);
222            if let Some(core::cmp::Ordering::Equal) = cmp {
223              None
224            } else {
225              cmp
226            }
227          })
228          .next()
229          .or(Some(core::cmp::Ordering::Equal))
230      }
231    }
232    impl Eq for $t {}
233    impl PartialEq for $t {
234      fn eq(&self, other: &Self) -> bool {
235        self.as_bytes().iter().zip(other.as_bytes()).all(|(l, r)| l == r)
236      }
237    }
238    impl core::hash::Hash for $t {
239      fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
240        self.as_bytes().hash(state)
241      }
242    }
243    impl core::fmt::Debug for $t {
244      fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
245        f.debug_tuple(stringify!($t)).field(&self.as_bytes()).finish()
246      }
247    }
248    #[cfg(test)]
249    mod $test {
250      #[test]
251      fn $test() {
252        use super::*;
253        use std::convert::TryFrom;
254        use std::collections::hash_map::DefaultHasher;
255        use std::hash::{Hash, Hasher};
256        use alloc::string::ToString;
257        assert_eq!(align_of::<$t>(), $c);
258        assert_eq!(size_of::<$t>(), $c);
259        assert_eq!(align_of::<$t>(), size_of::<$t>());
260        assert_eq!(size_of_val(&*<$t>::default()), size_of::<$t>());
261        assert_eq!(align_of::<$t>(), size_of::<$bit>());
262        assert_eq!(size_of::<$t>(), size_of::<$bit>());
263        assert_eq!(size_of_val(&*<$t>::default()), size_of_val(&*<$bit>::default()));
264        assert_eq!(<$t>::default().as_bytes().len(), $c);
265        assert_eq!(<$t>::default().as_bytes_mut().len(), $c);
266        let vec_length = 17;
267        let mut v = vec![<$t>::default(); vec_length];
268        assert_eq!(v.len(), vec_length);
269        let mut v_ref: &mut [$t] = &mut v;
270        assert_eq!(v_ref.as_bytes().len(), $c * vec_length);
271        assert_eq!(v_ref.as_bytes_mut().len(), $c * vec_length);
272        let v_big = vec![42_u8; 18];
273        let v = (0_usize..$c).map(|i|i as u8).collect::<std::vec::Vec<_>>();
274        // test TryFrom impl
275        let a = $t::try_from(&v[..]).expect("TryFrom should work for a slice of the same length");
276        let err = $t::try_from(&v_big[..]).unwrap_err();
277        assert_eq!(err.expected_len(), $c);
278        assert_eq!(err.actual_len(), 18);
279        // test Clone impl
280        let mut clone = a.clone();
281        assert_eq!(&*a, &*clone);
282        assert_eq!(a, clone);
283        let mut hasher = DefaultHasher::new();
284        a.hash(&mut hasher);
285        let a_hash = hasher.finish();
286        hasher = DefaultHasher::new();
287        clone.hash(&mut hasher);
288        assert_eq!(a_hash, hasher.finish());
289
290        clone.as_bytes_mut()[3.min($c - 1)] = 42;
291        assert!(a < clone);
292        hasher = DefaultHasher::new();
293        clone.hash(&mut hasher);
294        assert_ne!(a_hash, hasher.finish());
295        // Ensure proper names
296        let x: usize = $c;
297        assert!(stringify!($t).ends_with(&x.to_string()));
298      }
299    }
300  };
301}
302
303impl_alignment_traits! {
304  #[derive(Copy)]
305  pub struct A2 or Bit16(pub [u8; 2]);
306  test = test_a2
307}
308
309impl_alignment_traits! {
310  #[derive(Copy)]
311  pub struct A4 or Bit32(pub [u8; 4]);
312  test = test_a4
313}
314
315impl_alignment_traits! {
316  #[derive(Copy)]
317  pub struct A8 or Bit64(pub [u8; 8]);
318  test = test_a8
319}
320
321impl_alignment_traits! {
322  #[derive(Copy)]
323  pub struct A16 or Bit128(pub [u8; 16]);
324  test = test_a16
325}
326
327impl_alignment_traits! {
328  #[derive(Copy)]
329  pub struct A32 or Bit256(pub [u8; 32]);
330  test = test_a32
331}
332
333impl_alignment_traits! {
334  pub struct A64 or Bit512(pub [u8; 64]);
335  test = test_a64
336}
337
338impl_alignment_traits! {
339  pub struct A128 or Bit1024(pub [u8; 128]);
340  test = test_a128
341}
342
343impl_alignment_traits! {
344  pub struct A256 or Bit2048(pub [u8; 256]);
345  test = test_a256
346}
347
348impl_alignment_traits! {
349  pub struct A512 or Bit4096(pub [u8; 512]);
350  test = test_a512
351}
352
353#[cfg(feature = "align-1k")]
354impl_alignment_traits! {
355  /// Requires feature `align-1k`
356  pub struct A1024 or Bit8192 or A1k(pub [u8; 1024]);
357  test = test_a1024
358}
359
360#[cfg(feature = "align-2k")]
361impl_alignment_traits! {
362  /// Requires feature `align-2k`
363  pub struct A2048 or Bit16384 or A2k(pub [u8; 2048]);
364  test = test_a2048
365}
366
367#[cfg(feature = "align-4k")]
368impl_alignment_traits! {
369  /// Requires feature `align-4k`
370  pub struct A4096 or Bit32768 or A4k(pub [u8; 4096]);
371  test = test_a4096
372}
373
374#[cfg(feature = "align-8k")]
375impl_alignment_traits! {
376  /// Requires feature `align-8k`
377  pub struct A8192 or Bit65536 or A8k(pub [u8; 8192]);
378  test = test_a8192
379}
380
381#[cfg(feature = "align-16k")]
382impl_alignment_traits! {
383  /// Requires feature `align-16k`
384  pub struct A16384 or Bit131072 or A16k(pub [u8; 16384]);
385  test = test_a16384
386}
387
388#[cfg(feature = "align-32k")]
389impl_alignment_traits! {
390  /// Requires feature `align-32k`
391  pub struct A32768 or Bit262144 or A32k(pub [u8; 32768]);
392  test = test_a32768
393}
394
395#[cfg(feature = "align-64k")]
396impl_alignment_traits! {
397  /// Requires feature `align-64k`
398  pub struct A65536 or Bit524288 or A64k(pub [u8; 65536]);
399  test = test_a65536
400}
401
402#[cfg(feature = "align-128k")]
403impl_alignment_traits! {
404  /// Requires feature `align-128k`
405  pub struct A131072 or Bit1048576 or A128K(pub [u8; 131_072]);
406  test = test_a131072
407}
408
409/// Wrapper type that aligns `T` to at least `Alignment`
410/// It adds no size to the layout of the struct if the size is a multiple of the alignment,
411/// otherwise the size is rounded up to the next multiple of the alignment
412/// ```
413/// # use maligned::*;
414/// # use std::mem::*;
415/// assert_eq!(size_of::<Aligned<A16, u8>>(), size_of::<A16>());
416/// assert_eq!(size_of::<Aligned<A256, [u8; 256]>>(), size_of::<[u8; 256]>());
417/// assert_eq!(size_of::<Aligned<A512, [u8; 81920]>>(), size_of::<[u8; 81920]>());
418/// ```
419#[derive(Clone, Copy, Default, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
420pub struct Aligned<A: Alignment, T> {
421  _alignment: [A; 0],
422  t: T,
423}
424
425impl<A: Alignment, T> Aligned<A, T> {
426  /// Creates a new instance of Aligned
427  pub fn new(t: T) -> Self {
428    Self { _alignment: [], t }
429  }
430  /// Consumes Aligned and returns the wrapped value
431  pub fn into_inner(self) -> T {
432    self.t
433  }
434}
435
436/// Convenience function for creating a new Aligned
437/// Because of the current interaction between generics and impl arguments
438/// the function requires both types to be given, though the second one can
439/// be given the default `_`
440/// To align a byte array to a 256 bit boundary
441/// ```
442/// # use maligned::*;
443/// let a = aligned::<Bit256, _>([0_u8; 1024]);
444/// assert_eq!(&a[0] as *const u8 as usize % std::mem::align_of::<Bit256>(), 0);
445/// ```
446pub fn aligned<A: Alignment, T>(t: T) -> Aligned<A, T> {
447  Aligned::new(t)
448}
449
450impl<A: Alignment, T> core::ops::Deref for Aligned<A, T> {
451  type Target = T;
452
453  fn deref(&self) -> &Self::Target {
454    &self.t
455  }
456}
457
458impl<A: Alignment, T> core::ops::DerefMut for Aligned<A, T> {
459  fn deref_mut(&mut self) -> &mut Self::Target {
460    &mut self.t
461  }
462}
463
464impl<A: Alignment, T> From<T> for Aligned<A, T> {
465  fn from(t: T) -> Self {
466    Self::new(t)
467  }
468}
469
470impl<A: Alignment, T> AsRef<T> for Aligned<A, T> {
471  fn as_ref(&self) -> &T {
472    &self.t
473  }
474}
475
476impl<A: Alignment, T> AsMut<T> for Aligned<A, T> {
477  fn as_mut(&mut self) -> &mut T {
478    &mut self.t
479  }
480}
481
482//TODO: Figure out a more generic implementation of this
483impl<T: AsBytes> sealed_traits::SealedAsBytes for &[T] {}
484#[allow(unsafe_code)]
485unsafe impl<T: AsBytes> AsBytes for &[T] {
486  fn as_bytes(&self) -> &[u8] {
487    unsafe { core::slice::from_raw_parts(self.as_ptr() as *const T as *const u8, self.len() * size_of::<T>()) }
488  }
489}
490
491impl<T: AsBytes> sealed_traits::SealedAsBytes for &mut [T] {}
492#[allow(unsafe_code)]
493unsafe impl<T: AsBytes> AsBytes for &mut [T] {
494  fn as_bytes(&self) -> &[u8] {
495    unsafe { core::slice::from_raw_parts(self.as_ptr() as *const T as *const u8, self.len() * size_of::<T>()) }
496  }
497}
498
499impl<T: AsBytesMut> sealed_traits::SealedAsBytesMut for &mut [T] {}
500#[allow(unsafe_code)]
501unsafe impl<T: AsBytesMut> AsBytesMut for &mut [T] {
502  fn as_bytes_mut(&mut self) -> &mut [u8] {
503    unsafe { core::slice::from_raw_parts_mut(self.as_mut_ptr() as *mut T as *mut u8, self.len() * size_of::<T>()) }
504  }
505}
506
507#[cfg(feature = "alloc")]
508impl<T: AsBytes> sealed_traits::SealedAsBytes for alloc::vec::Vec<T> {}
509
510#[cfg(feature = "alloc")]
511#[allow(unsafe_code)]
512unsafe impl<T: AsBytes> AsBytes for alloc::vec::Vec<T> {
513  fn as_bytes(&self) -> &[u8] {
514    unsafe { core::slice::from_raw_parts(self.as_ptr() as *const T as *const u8, self.len() * size_of::<T>()) }
515  }
516}
517
518#[cfg(feature = "alloc")]
519impl<T: AsBytesMut> sealed_traits::SealedAsBytesMut for alloc::vec::Vec<T> {}
520
521#[cfg(feature = "alloc")]
522#[allow(unsafe_code)]
523unsafe impl<T: AsBytesMut> AsBytesMut for alloc::vec::Vec<T> {
524  fn as_bytes_mut(&mut self) -> &mut [u8] {
525    unsafe { core::slice::from_raw_parts_mut(self.as_mut_ptr() as *mut T as *mut u8, self.len() * size_of::<T>()) }
526  }
527}