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
13pub trait Alignment: sealed_traits::SealedAlignment + Sized + Clone + Default + Send + Sync {}
16
17#[allow(unsafe_code)]
21pub unsafe trait AsBytes: sealed_traits::SealedAsBytes + Sized {
22 #[must_use]
24 fn as_bytes(&self) -> &[u8];
25}
26
27#[allow(unsafe_code)]
31pub unsafe trait AsBytesMut: sealed_traits::SealedAsBytesMut + AsBytes {
32 #[must_use]
34 fn as_bytes_mut(&mut self) -> &mut [u8];
35}
36
37#[derive(Debug)]
39pub struct FromByteSliceError {
40 actual_len: usize,
41 expected_len: usize,
42}
43
44impl FromByteSliceError {
45 #[must_use]
46 pub fn actual_len(&self) -> usize {
48 self.actual_len
49 }
50 #[must_use]
51 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 #[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(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 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 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 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 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 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 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 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 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 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 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 pub struct A131072 or Bit1048576 or A128K(pub [u8; 131_072]);
406 test = test_a131072
407}
408
409#[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 pub fn new(t: T) -> Self {
428 Self { _alignment: [], t }
429 }
430 pub fn into_inner(self) -> T {
432 self.t
433 }
434}
435
436pub 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
482impl<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}