1#![no_std]
38#![deny(missing_docs)]
39#![deny(missing_debug_implementations)]
40#![deny(rust_2018_idioms)]
41#![deny(unreachable_pub)]
42#![deny(clippy::unwrap_used)]
43#![warn(clippy::missing_errors_doc)]
44#![warn(clippy::missing_panics_doc)]
45
46#[cfg(feature = "std")]
47extern crate std;
48
49pub mod endian;
50
51use core::mem::MaybeUninit;
52use endian::FixedEndian;
53pub use endian::{BigEndian, Endian, LittleEndian};
54
55#[derive(Copy, Clone, Debug)]
58pub struct UnalignedSizeError;
59
60impl core::fmt::Display for UnalignedSizeError {
61 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
62 f.write_str("byte slice is not aligned to the structure's size")
63 }
64}
65
66#[cfg(feature = "std")]
67impl std::error::Error for UnalignedSizeError {}
68
69#[derive(Copy, Clone, Debug)]
72pub struct SliceSizeOverflowError;
73
74impl core::fmt::Display for SliceSizeOverflowError {
75 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
76 f.write_str("multiple of slice count and type size overflows isize")
77 }
78}
79
80#[cfg(feature = "std")]
81impl std::error::Error for SliceSizeOverflowError {}
82
83pub const fn safe_count_to_size<T: Sized>(count: usize) -> Result<usize, SliceSizeOverflowError> {
89 const MAX_SIZE: usize = isize::MAX as usize;
90
91 if let Some(size) = core::mem::size_of::<T>().checked_mul(count) {
92 if size <= MAX_SIZE {
93 Ok(size)
94 } else {
95 Err(SliceSizeOverflowError)
96 }
97 } else {
98 Err(SliceSizeOverflowError)
99 }
100}
101
102pub const fn safe_size_to_count<T: Sized>(size: usize) -> Result<usize, UnalignedSizeError> {
109 if size % core::mem::size_of::<T>() == 0 {
110 if let Some(count) = size.checked_div(core::mem::size_of::<T>()) {
111 Ok(count)
112 } else {
113 Err(UnalignedSizeError)
114 }
115 } else {
116 Err(UnalignedSizeError)
117 }
118}
119
120pub unsafe trait ReprByteSlice: Sized {
134 fn from_byte_slice(s: &[u8]) -> Result<&Self, UnalignedSizeError>;
140
141 fn from_byte_slice_mut(s: &mut [u8]) -> Result<&mut Self, UnalignedSizeError>;
147
148 fn as_byte_slice(&self) -> &[u8];
150
151 fn as_byte_slice_mut(&mut self) -> &mut [u8];
153
154 fn slice_from_byte_slice(s: &[u8]) -> Result<&[Self], UnalignedSizeError>;
160
161 fn slice_from_byte_slice_mut(s: &mut [u8]) -> Result<&mut [Self], UnalignedSizeError>;
167
168 fn slice_as_byte_slice(slice: &[Self]) -> Result<&[u8], SliceSizeOverflowError>;
176
177 fn slice_as_byte_slice_mut(s: &mut [Self]) -> Result<&mut [u8], SliceSizeOverflowError>;
185
186 fn uninit_slice_from_byte_slice(
193 bytes: &[MaybeUninit<u8>],
194 ) -> Result<&[MaybeUninit<Self>], UnalignedSizeError>;
195
196 fn uninit_slice_from_byte_slice_mut(
203 bytes: &mut [MaybeUninit<u8>],
204 ) -> Result<&mut [MaybeUninit<Self>], UnalignedSizeError>;
205
206 fn uninit_slice_as_byte_slice(
214 slice: &[MaybeUninit<Self>],
215 ) -> Result<&[MaybeUninit<u8>], SliceSizeOverflowError>;
216
217 fn uninit_slice_as_byte_slice_mut(
225 s: &mut [MaybeUninit<Self>],
226 ) -> Result<&mut [MaybeUninit<u8>], SliceSizeOverflowError>;
227}
228
229macro_rules! define_int_wrapper {
230 ($ty:ident, $name:ident) => {
231 #[doc = concat!(
232 "A type that wraps a byte array to be decoded into a `", stringify!($ty), "`.\n\n"
233 )]
234 #[derive(Copy, Clone, Eq, PartialEq, Hash)]
238 #[repr(C)]
239 pub struct $name<E>([u8; ($ty::BITS as usize) / 8], ::core::marker::PhantomData<E>);
240
241 impl<E> $name<E> {
242 #[doc = concat!("Converts a byte array into a [`", stringify!($name), "`].")]
243 pub const fn from_bytes(bytes: [u8; ($ty::BITS as usize) / 8]) -> Self {
244 Self(bytes, ::core::marker::PhantomData)
245 }
246
247 #[doc = concat!("Converts a [`", stringify!($name), "`] into a byte array.")]
248 pub const fn into_bytes(self) -> [u8; ($ty::BITS as usize) / 8] {
249 self.0
250 }
251 }
252
253 $crate::format_struct!(@impl_conv $name<E> size (($ty::BITS as usize) / 8));
254
255 impl $name<Endian> {
256 #[doc = concat!(
257 "Constructs a [`", stringify!($name), "`] wrapper type from a `", stringify!($ty),
258 "` value using the specified endianness."
259 )]
260 #[inline]
261 pub const fn new_with_endian(value: $ty, endian: Endian) -> Self {
262 let bytes = match endian {
263 Endian::Little => value.to_le_bytes(),
264 Endian::Big => value.to_be_bytes(),
265 };
266
267 Self(bytes, ::core::marker::PhantomData)
268 }
269
270 #[doc = concat!(
271 "Extracts a `", stringify!($ty), "` value from a [`", stringify!($name),
272 "`] wrapper using the specified endianness."
273 )]
274 #[inline]
275 pub const fn get_with_endian(self, endian: Endian) -> $ty {
276 match endian {
277 Endian::Little => $ty::from_le_bytes(self.0),
278 Endian::Big => $ty::from_be_bytes(self.0),
279 }
280 }
281 }
282
283 impl<E: FixedEndian> $name<E> {
284 #[doc = concat!(
285 "Constructs a [`", stringify!($name), "`] wrapper type from a `", stringify!($ty),
286 "` value using the type's fixed endianness."
287 )]
288 #[inline]
289 pub const fn new(value: $ty) -> Self {
290 let bytes = match E::ENDIAN {
291 Endian::Little => value.to_le_bytes(),
292 Endian::Big => value.to_be_bytes(),
293 };
294
295 Self(bytes, ::core::marker::PhantomData)
296 }
297
298 #[doc = concat!(
299 "Extracts a `", stringify!($ty), "` value from a [`", stringify!($name),
300 "`] wrapper using the type's fixed endianness."
301 )]
302 #[inline]
303 pub const fn get(self) -> $ty {
304 match E::ENDIAN {
305 Endian::Little => $ty::from_le_bytes(self.0),
306 Endian::Big => $ty::from_be_bytes(self.0),
307 }
308 }
309 }
310
311 impl<E> ::core::default::Default for $name<E> {
312 fn default() -> Self {
313 Self(Default::default(), ::core::marker::PhantomData)
314 }
315 }
316
317 impl<E: FixedEndian> From<$ty> for $name<E> {
318 fn from(value: $ty) -> Self {
319 Self::new(value)
320 }
321 }
322
323 impl core::fmt::Debug for $name<LittleEndian> {
324 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
325 core::fmt::Debug::fmt(&self.get(), f)
326 }
327 }
328
329 impl core::fmt::Debug for $name<BigEndian> {
330 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
331 core::fmt::Debug::fmt(&self.get(), f)
332 }
333 }
334
335 impl core::fmt::Debug for $name<Endian> {
336 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
337 f.debug_tuple(stringify!($name))
338 .field(&self.0)
339 .finish()
340 }
341 }
342 };
343}
344
345#[macro_export]
439macro_rules! format_struct {
440 ($($(#[$m:meta])* $vis:vis struct $endian:tt $name:ident {
441 $($(#[doc = $field_doc:literal])* $field_vis:vis $field_name:ident: $ty:tt),*,
442 })+) => {
443 $(
444 #[repr(C)]
445 $(#[$m])*
446 $vis struct $name {
447 $($(#[doc = $field_doc])*
448 $field_vis $field_name: $crate::format_struct!(@wrapper_type $endian $ty)),*
449 }
450
451 const _: fn() = || {
452 fn assert_impl_repr_byte_slice<T: ?Sized + $crate::ReprByteSlice>() {}
453
454 $(assert_impl_repr_byte_slice::<$crate::format_struct!(@wrapper_type $endian $ty)>();)*
455 };
456
457 impl $name {
458 #[doc = concat!("Converts a byte array into a [`", stringify!($name), "`].")]
459 pub const fn from_bytes(bytes: [u8; ::core::mem::size_of::<Self>()]) -> Self {
460 unsafe { ::core::mem::transmute(bytes) }
461 }
462
463 #[doc = concat!(
464 "Converts an immutable reference to a byte array of the same size as [`",
465 stringify!($name), " into an immutable reference to [`", stringify!($name),
466 "`]."
467 )]
468 pub const fn from_byte_array(bytes: &[u8; ::core::mem::size_of::<Self>()]) -> &Self {
469 unsafe { &*(bytes.as_ptr() as *const Self) }
470 }
471
472 #[doc = concat!(
473 "Converts a mutable reference to a byte array of the same size as [`",
474 stringify!($name), "`] into a mutable reference to [`", stringify!($name),
475 "`]."
476 )]
477 pub fn from_byte_array_mut(bytes: &mut [u8; ::core::mem::size_of::<Self>()]) -> &mut Self {
478 unsafe { &mut *(bytes.as_mut_ptr() as *mut Self) }
479 }
480
481 #[doc = concat!("Converts a [`", stringify!($name), "`] into a byte array.")]
482 pub const fn into_bytes(self) -> [u8; ::core::mem::size_of::<Self>()] {
483 unsafe { ::core::mem::transmute(self) }
484 }
485
486 #[doc = concat!(
487 "Converts an immutable reference to a byte array of the same size as [`",
488 stringify!($name), " into an immutable reference to [`", stringify!($name),
489 "`]."
490 )]
491 pub const fn as_byte_array(&self) -> &[u8; ::core::mem::size_of::<Self>()] {
492 unsafe { &*(self as *const Self as *const [u8; ::core::mem::size_of::<Self>()]) }
493 }
494
495 #[doc = concat!(
496 "Converts a mutable reference to a byte array of the same size as [`",
497 stringify!($name), "`] into a mutable reference to [`", stringify!($name),
498 "`]."
499 )]
500 pub fn as_byte_array_mut(&mut self) -> &mut [u8; ::core::mem::size_of::<Self>()] {
501 unsafe { &mut *(self as *mut Self as *mut [u8; ::core::mem::size_of::<Self>()]) }
502 }
503 }
504
505 $crate::format_struct!(@impl_conv $name size ::core::mem::size_of::<$name>());
506 )+
507 };
508 (@impl_conv $name:tt$(<$gen:ident$(: $trait:ident)?$(, const $const_gen:ident: usize)?>)? size $size_expr:expr) => {
509 unsafe impl$(<$gen$(: $crate::$trait)? $(, const $const_gen: usize)?>)? $crate::ReprByteSlice for $name$(<$gen $(, $const_gen)?>)? {
510 fn from_byte_slice(s: &[u8]) -> ::core::result::Result<&Self, $crate::UnalignedSizeError> {
511 let bytes: &[u8; $size_expr] = ::core::convert::TryInto::try_into(s).map_err(|_| $crate::UnalignedSizeError)?;
512 let ptr = bytes.as_ptr() as *const Self;
513
514 ::core::result::Result::Ok(unsafe { &*ptr })
515 }
516
517 fn from_byte_slice_mut(s: &mut [u8]) -> ::core::result::Result<&mut Self, $crate::UnalignedSizeError> {
518 let bytes: &mut [u8; $size_expr] = ::core::convert::TryInto::try_into(s).map_err(|_| $crate::UnalignedSizeError)?;
519 let ptr = bytes.as_ptr() as *mut Self;
520
521 ::core::result::Result::Ok(unsafe { &mut *ptr })
522 }
523
524 fn as_byte_slice(&self) -> &[u8] {
525 let data = self as *const Self as *const u8;
526 let len = ::core::mem::size_of::<Self>();
527 unsafe { ::core::slice::from_raw_parts(data, len) }
528 }
529
530 fn as_byte_slice_mut(&mut self) -> &mut [u8] {
531 let data = self as *mut Self as *mut u8;
532 let len = ::core::mem::size_of::<Self>();
533 unsafe { ::core::slice::from_raw_parts_mut(data, len) }
534 }
535
536 fn slice_from_byte_slice(s: &[u8]) -> ::core::result::Result<&[Self], $crate::UnalignedSizeError> {
537 if s.is_empty() {
538 ::core::result::Result::Ok(&[])
539 } else {
540 let size = $crate::safe_size_to_count::<Self>(s.len())?;
541 let ptr = s.as_ptr() as *const Self;
542
543 ::core::result::Result::Ok(unsafe { ::core::slice::from_raw_parts(ptr, size) })
544 }
545 }
546
547 fn slice_from_byte_slice_mut(s: &mut [u8]) -> ::core::result::Result<&mut [Self], $crate::UnalignedSizeError> {
548 if s.is_empty() {
549 ::core::result::Result::Ok(&mut [])
550 } else {
551 let size = $crate::safe_size_to_count::<Self>(s.len())?;
552 let ptr = s.as_mut_ptr() as *mut Self;
553
554 ::core::result::Result::Ok(unsafe { ::core::slice::from_raw_parts_mut(ptr, size) })
555 }
556 }
557
558 fn slice_as_byte_slice(slice: &[Self]) -> ::core::result::Result<&[u8], $crate::SliceSizeOverflowError> {
559 let data = slice.as_ptr() as *const u8;
560 let len = $crate::safe_count_to_size::<Self>(slice.len())?;
561 ::core::result::Result::Ok(unsafe { ::core::slice::from_raw_parts(data, len) })
562 }
563
564 fn slice_as_byte_slice_mut(slice: &mut [Self]) -> ::core::result::Result<&mut [u8], $crate::SliceSizeOverflowError> {
565 let data = slice.as_ptr() as *mut u8;
566 let len = $crate::safe_count_to_size::<Self>(slice.len())?;
567 ::core::result::Result::Ok(unsafe { ::core::slice::from_raw_parts_mut(data, len) })
568 }
569
570 fn uninit_slice_from_byte_slice(
571 s: &[::core::mem::MaybeUninit<u8>]
572 ) -> ::core::result::Result<&[::core::mem::MaybeUninit<Self>], $crate::UnalignedSizeError> {
573 if s.is_empty() {
574 ::core::result::Result::Ok(&[])
575 } else {
576 let size = $crate::safe_size_to_count::<Self>(s.len())?;
577 let ptr = s.as_ptr() as *const ::core::mem::MaybeUninit<Self>;
578
579 ::core::result::Result::Ok(unsafe { ::core::slice::from_raw_parts(ptr, size) })
580 }
581 }
582
583 fn uninit_slice_from_byte_slice_mut(
584 s: &mut [::core::mem::MaybeUninit<u8>]
585 ) -> ::core::result::Result<&mut [::core::mem::MaybeUninit<Self>], $crate::UnalignedSizeError> {
586 if s.is_empty() {
587 ::core::result::Result::Ok(&mut [])
588 } else {
589 let size = $crate::safe_size_to_count::<Self>(s.len())?;
590 let ptr = s.as_mut_ptr() as *mut ::core::mem::MaybeUninit<Self>;
591
592 ::core::result::Result::Ok(unsafe { ::core::slice::from_raw_parts_mut(ptr, size) })
593 }
594 }
595
596 fn uninit_slice_as_byte_slice(
597 slice: &[::core::mem::MaybeUninit<Self>]
598 ) -> ::core::result::Result<&[::core::mem::MaybeUninit<u8>], $crate::SliceSizeOverflowError> {
599 let data = slice.as_ptr() as *const ::core::mem::MaybeUninit<u8>;
600 let len = ::core::mem::size_of::<Self>().checked_mul(slice.len()).expect("");
601 ::core::result::Result::Ok(unsafe { ::core::slice::from_raw_parts(data, len) })
602 }
603
604 fn uninit_slice_as_byte_slice_mut(
605 slice: &mut [::core::mem::MaybeUninit<Self>]
606 ) -> ::core::result::Result<&mut [::core::mem::MaybeUninit<u8>], $crate::SliceSizeOverflowError> {
607 let data = slice.as_ptr() as *mut ::core::mem::MaybeUninit<u8>;
608 let len = ::core::mem::size_of::<Self>().checked_mul(slice.len()).unwrap();
609 ::core::result::Result::Ok(unsafe { ::core::slice::from_raw_parts_mut(data, len) })
610 }
611 }
612 };
613 (@endian_type little) => {$crate::LittleEndian};
614 (@endian_type big) => {$crate::BigEndian};
615 (@endian_type dynamic) => {$crate::Endian};
616 (@wrapper_type $endian:tt [$ty:ident; $($n:tt)+]) => {
617 [$crate::format_struct!(@wrapper_type $endian $ty); $($n)+]
618 };
619 (@wrapper_type $endian:tt u8) => {u8};
620 (@wrapper_type $endian:tt i8) => {i8};
621 (@wrapper_type $endian:tt u16) => {$crate::U16<$crate::format_struct!(@endian_type $endian)>};
622 (@wrapper_type $endian:tt i16) => {$crate::I16<$crate::format_struct!(@endian_type $endian)>};
623 (@wrapper_type $endian:tt u32) => {$crate::U32<$crate::format_struct!(@endian_type $endian)>};
624 (@wrapper_type $endian:tt i32) => {$crate::I32<$crate::format_struct!(@endian_type $endian)>};
625 (@wrapper_type $endian:tt u64) => {$crate::U64<$crate::format_struct!(@endian_type $endian)>};
626 (@wrapper_type $endian:tt i64) => {$crate::I64<$crate::format_struct!(@endian_type $endian)>};
627 (@wrapper_type $endian:tt u128) => {$crate::U128<$crate::format_struct!(@endian_type $endian)>};
628 (@wrapper_type $endian:tt i128) => {$crate::I128<$crate::format_struct!(@endian_type $endian)>};
629 (@wrapper_type $endian:tt $ty:ty) => {$ty};
630}
631
632format_struct!(@impl_conv u8 size 1);
633define_int_wrapper!(u16, U16);
634define_int_wrapper!(i16, I16);
635define_int_wrapper!(u32, U32);
636define_int_wrapper!(i32, I32);
637define_int_wrapper!(u64, U64);
638define_int_wrapper!(i64, I64);
639define_int_wrapper!(u128, U128);
640define_int_wrapper!(i128, I128);
641
642type Arr<T, const N: usize> = [T; N];
643format_struct!(@impl_conv Arr<T: ReprByteSlice, const N: usize> size N);
644
645#[cfg(test)]
646#[allow(unused, unreachable_pub)]
647mod tests {
648 use super::*;
649 use core::{marker::PhantomData, mem::MaybeUninit};
650
651 const CONSTANT_SIZE: usize = 16;
652
653 format_struct! {
654 #[derive(Default, Clone)]
655 struct little TestLe {
656 #[doc = "this is the third line"]
659 byte: u8,
660 short: u16,
661 word: u32,
662 dword: u64,
663 qword: u128,
664 byte_arr: [u8; 16],
665 short_arr: [u16; 16],
666 }
667
668 #[derive(Default, Clone)]
669 struct big TestBe {
670 pub byte: u8,
671 short: u16,
672 word: u32,
673 dword: u64,
674 qword: u128,
675 byte_arr: [u8; 16],
676 short_arr: [u16; 16],
677 }
678
679 #[derive(Default, Clone)]
680 struct dynamic TestDyn {
681 byte: u8,
682 short: u16,
683 word: u32,
684 dword: u64,
685 qword: u128,
686 byte_arr: [u8; const { 16 }],
687 short_arr: [u16; CONSTANT_SIZE],
688 }
689
690 #[derive(Default, Clone)]
691 struct little TestNested {
692 regular: u8,
693 single: TestBe,
694 array: [TestLe; 2],
695 }
696 }
697
698 #[test]
699 fn test_access_short_arr() {
700 let mut test_le = TestLe::default();
701
702 for (i, s) in test_le.short_arr.iter_mut().enumerate() {
703 *s = U16((i as u16).to_le_bytes(), PhantomData);
704 }
705
706 assert_eq!(test_le.short_arr[5].get(), 5);
707 }
708
709 #[test]
710 fn test_access_u8() {
711 let mut test = TestLe::default();
712
713 test.byte = 42;
714 assert_eq!(test.byte, 42);
715 }
716
717 #[test]
718 fn test_access_u16() {
719 let mut test_le = TestLe::default();
720 test_le.short = U16::new(1337);
721 assert_eq!(test_le.short.get(), 1337);
722 assert_eq!(test_le.short.0, 1337u16.to_le_bytes());
723
724 let mut test_be = TestBe::default();
725 test_be.short = U16::new(1337);
726 assert_eq!(test_be.short.get(), 1337);
727 assert_eq!(test_be.short.0, 1337u16.to_be_bytes());
728 }
729
730 #[test]
731 fn test_access_u32() {
732 let mut test_le = TestLe::default();
733 test_le.word = U32::new(13371337);
734 assert_eq!(test_le.word.get(), 13371337);
735 assert_eq!(test_le.word.0, 13371337u32.to_le_bytes());
736
737 let mut test_be = TestBe::default();
738 test_be.word = U32::new(13371337);
739 assert_eq!(test_be.word.get(), 13371337);
740 assert_eq!(test_be.word.0, 13371337u32.to_be_bytes());
741 }
742
743 #[test]
744 fn test_access_u64() {
745 let mut test_le = TestLe::default();
746 test_le.dword = U64::new(1337133713371337);
747 assert_eq!(test_le.dword.get(), 1337133713371337);
748 assert_eq!(test_le.dword.0, 1337133713371337u64.to_le_bytes());
749
750 let mut test_be = TestBe::default();
751 test_be.dword = U64::new(1337133713371337);
752 assert_eq!(test_be.dword.get(), 1337133713371337);
753 assert_eq!(test_be.dword.0, 1337133713371337u64.to_be_bytes());
754 }
755
756 #[test]
757 fn test_access_u128() {
758 let mut test_le = TestLe::default();
759 test_le.qword = U128::new(13371337133713371337133713371337);
760 assert_eq!(test_le.qword.get(), 13371337133713371337133713371337u128);
761 assert_eq!(
762 test_le.qword.0,
763 13371337133713371337133713371337u128.to_le_bytes()
764 );
765
766 let mut test_be = TestBe::default();
767 test_be.qword = U128::new(13371337133713371337133713371337u128);
768 assert_eq!(test_be.qword.get(), 13371337133713371337133713371337);
769 assert_eq!(
770 test_be.qword.0,
771 13371337133713371337133713371337u128.to_be_bytes()
772 );
773 }
774
775 #[test]
776 fn test_uninit() {
777 let mut test = [
778 MaybeUninit::<TestLe>::uninit(),
779 MaybeUninit::<TestLe>::uninit(),
780 ];
781 TestLe::uninit_slice_as_byte_slice(&test[..]).unwrap()[0];
782 }
783}