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 split_off(s: &[u8]) -> Option<(&Self, &[u8])> {
192 (s.len() > core::mem::size_of::<Self>()).then(|| {
193 let (head, tail) = s.split_at(core::mem::size_of::<Self>());
194 let head = Self::from_byte_slice(head).expect("size checked");
195 (head, tail)
196 })
197 }
198
199 fn split_off_mut(s: &mut [u8]) -> Option<(&mut Self, &mut [u8])> {
205 (s.len() > core::mem::size_of::<Self>()).then(|| {
206 let (head, tail) = s.split_at_mut(core::mem::size_of::<Self>());
207 let head = Self::from_byte_slice_mut(head).expect("size checked");
208 (head, tail)
209 })
210 }
211
212 fn uninit_slice_from_byte_slice(
219 bytes: &[MaybeUninit<u8>],
220 ) -> Result<&[MaybeUninit<Self>], UnalignedSizeError>;
221
222 fn uninit_slice_from_byte_slice_mut(
229 bytes: &mut [MaybeUninit<u8>],
230 ) -> Result<&mut [MaybeUninit<Self>], UnalignedSizeError>;
231
232 fn uninit_slice_as_byte_slice(
240 slice: &[MaybeUninit<Self>],
241 ) -> Result<&[MaybeUninit<u8>], SliceSizeOverflowError>;
242
243 fn uninit_slice_as_byte_slice_mut(
251 s: &mut [MaybeUninit<Self>],
252 ) -> Result<&mut [MaybeUninit<u8>], SliceSizeOverflowError>;
253}
254
255macro_rules! define_int_wrapper {
256 ($ty:ident, $name:ident) => {
257 #[doc = concat!(
258 "A type that wraps a byte array to be decoded into a `", stringify!($ty), "`.\n\n"
259 )]
260 #[derive(Copy, Clone, Eq, PartialEq, Hash)]
264 #[repr(C)]
265 pub struct $name<E>([u8; ($ty::BITS as usize) / 8], ::core::marker::PhantomData<E>);
266
267 impl<E> $name<E> {
268 #[doc = concat!("Converts a byte array into a [`", stringify!($name), "`].")]
269 pub const fn from_bytes(bytes: [u8; ($ty::BITS as usize) / 8]) -> Self {
270 Self(bytes, ::core::marker::PhantomData)
271 }
272
273 #[doc = concat!("Converts a [`", stringify!($name), "`] into a byte array.")]
274 pub const fn into_bytes(self) -> [u8; ($ty::BITS as usize) / 8] {
275 self.0
276 }
277 }
278
279 $crate::format_struct!(@impl_conv $name<E> size (($ty::BITS as usize) / 8));
280
281 impl $name<Endian> {
282 #[doc = concat!(
283 "Constructs a [`", stringify!($name), "`] wrapper type from a `", stringify!($ty),
284 "` value using the specified endianness."
285 )]
286 #[inline]
287 pub const fn new_with_endian(value: $ty, endian: Endian) -> Self {
288 let bytes = match endian {
289 Endian::Little => value.to_le_bytes(),
290 Endian::Big => value.to_be_bytes(),
291 };
292
293 Self(bytes, ::core::marker::PhantomData)
294 }
295
296 #[doc = concat!(
297 "Extracts a `", stringify!($ty), "` value from a [`", stringify!($name),
298 "`] wrapper using the specified endianness."
299 )]
300 #[inline]
301 pub const fn get_with_endian(self, endian: Endian) -> $ty {
302 match endian {
303 Endian::Little => $ty::from_le_bytes(self.0),
304 Endian::Big => $ty::from_be_bytes(self.0),
305 }
306 }
307 }
308
309 impl<E: FixedEndian> $name<E> {
310 #[doc = concat!(
311 "Constructs a [`", stringify!($name), "`] wrapper type from a `", stringify!($ty),
312 "` value using the type's fixed endianness."
313 )]
314 #[inline]
315 pub const fn new(value: $ty) -> Self {
316 let bytes = match E::ENDIAN {
317 Endian::Little => value.to_le_bytes(),
318 Endian::Big => value.to_be_bytes(),
319 };
320
321 Self(bytes, ::core::marker::PhantomData)
322 }
323
324 #[doc = concat!(
325 "Extracts a `", stringify!($ty), "` value from a [`", stringify!($name),
326 "`] wrapper using the type's fixed endianness."
327 )]
328 #[inline]
329 pub const fn get(self) -> $ty {
330 match E::ENDIAN {
331 Endian::Little => $ty::from_le_bytes(self.0),
332 Endian::Big => $ty::from_be_bytes(self.0),
333 }
334 }
335 }
336
337 impl<E> ::core::default::Default for $name<E> {
338 fn default() -> Self {
339 Self(Default::default(), ::core::marker::PhantomData)
340 }
341 }
342
343 impl<E: FixedEndian> From<$ty> for $name<E> {
344 fn from(value: $ty) -> Self {
345 Self::new(value)
346 }
347 }
348
349 impl core::fmt::Debug for $name<LittleEndian> {
350 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
351 core::fmt::Debug::fmt(&self.get(), f)
352 }
353 }
354
355 impl core::fmt::Debug for $name<BigEndian> {
356 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
357 core::fmt::Debug::fmt(&self.get(), f)
358 }
359 }
360
361 impl core::fmt::Debug for $name<Endian> {
362 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
363 f.debug_tuple(stringify!($name))
364 .field(&self.0)
365 .finish()
366 }
367 }
368 };
369}
370
371#[macro_export]
465macro_rules! format_struct {
466 ($($(#[$m:meta])* $vis:vis struct $endian:tt $name:ident {
467 $($(#[doc = $field_doc:literal])* $field_vis:vis $field_name:ident: $ty:tt),*,
468 })+) => {
469 $(
470 #[repr(C)]
471 $(#[$m])*
472 $vis struct $name {
473 $($(#[doc = $field_doc])*
474 $field_vis $field_name: $crate::format_struct!(@wrapper_type $endian $ty)),*
475 }
476
477 const _: fn() = || {
478 fn assert_impl_repr_byte_slice<T: ?Sized + $crate::ReprByteSlice>() {}
479
480 $(assert_impl_repr_byte_slice::<$crate::format_struct!(@wrapper_type $endian $ty)>();)*
481 };
482
483 impl $name {
484 #[doc = concat!("Converts a byte array into a [`", stringify!($name), "`].")]
485 pub const fn from_bytes(bytes: [u8; ::core::mem::size_of::<Self>()]) -> Self {
486 unsafe { ::core::mem::transmute(bytes) }
487 }
488
489 #[doc = concat!(
490 "Converts an immutable reference to a byte array of the same size as [`",
491 stringify!($name), " into an immutable reference to [`", stringify!($name),
492 "`]."
493 )]
494 pub const fn from_byte_array(bytes: &[u8; ::core::mem::size_of::<Self>()]) -> &Self {
495 unsafe { &*(bytes.as_ptr() as *const Self) }
496 }
497
498 #[doc = concat!(
499 "Converts a mutable reference to a byte array of the same size as [`",
500 stringify!($name), "`] into a mutable reference to [`", stringify!($name),
501 "`]."
502 )]
503 pub fn from_byte_array_mut(bytes: &mut [u8; ::core::mem::size_of::<Self>()]) -> &mut Self {
504 unsafe { &mut *(bytes.as_mut_ptr() as *mut Self) }
505 }
506
507 #[doc = concat!("Converts a [`", stringify!($name), "`] into a byte array.")]
508 pub const fn into_bytes(self) -> [u8; ::core::mem::size_of::<Self>()] {
509 unsafe { ::core::mem::transmute(self) }
510 }
511
512 #[doc = concat!(
513 "Converts an immutable reference to a byte array of the same size as [`",
514 stringify!($name), " into an immutable reference to [`", stringify!($name),
515 "`]."
516 )]
517 pub const fn as_byte_array(&self) -> &[u8; ::core::mem::size_of::<Self>()] {
518 unsafe { &*(self as *const Self as *const [u8; ::core::mem::size_of::<Self>()]) }
519 }
520
521 #[doc = concat!(
522 "Converts a mutable reference to a byte array of the same size as [`",
523 stringify!($name), "`] into a mutable reference to [`", stringify!($name),
524 "`]."
525 )]
526 pub fn as_byte_array_mut(&mut self) -> &mut [u8; ::core::mem::size_of::<Self>()] {
527 unsafe { &mut *(self as *mut Self as *mut [u8; ::core::mem::size_of::<Self>()]) }
528 }
529 }
530
531 $crate::format_struct!(@impl_conv $name size ::core::mem::size_of::<$name>());
532 )+
533 };
534 (@impl_conv $name:tt$(<$gen:ident$(: $trait:ident)?$(, const $const_gen:ident: usize)?>)? size $size_expr:expr) => {
535 unsafe impl$(<$gen$(: $crate::$trait)? $(, const $const_gen: usize)?>)? $crate::ReprByteSlice for $name$(<$gen $(, $const_gen)?>)? {
536 fn from_byte_slice(s: &[u8]) -> ::core::result::Result<&Self, $crate::UnalignedSizeError> {
537 let bytes: &[u8; $size_expr] = ::core::convert::TryInto::try_into(s).map_err(|_| $crate::UnalignedSizeError)?;
538 let ptr = bytes.as_ptr() as *const Self;
539
540 ::core::result::Result::Ok(unsafe { &*ptr })
541 }
542
543 fn from_byte_slice_mut(s: &mut [u8]) -> ::core::result::Result<&mut Self, $crate::UnalignedSizeError> {
544 let bytes: &mut [u8; $size_expr] = ::core::convert::TryInto::try_into(s).map_err(|_| $crate::UnalignedSizeError)?;
545 let ptr = bytes.as_ptr() as *mut Self;
546
547 ::core::result::Result::Ok(unsafe { &mut *ptr })
548 }
549
550 fn as_byte_slice(&self) -> &[u8] {
551 let data = self as *const Self as *const u8;
552 let len = ::core::mem::size_of::<Self>();
553 unsafe { ::core::slice::from_raw_parts(data, len) }
554 }
555
556 fn as_byte_slice_mut(&mut self) -> &mut [u8] {
557 let data = self as *mut Self as *mut u8;
558 let len = ::core::mem::size_of::<Self>();
559 unsafe { ::core::slice::from_raw_parts_mut(data, len) }
560 }
561
562 fn slice_from_byte_slice(s: &[u8]) -> ::core::result::Result<&[Self], $crate::UnalignedSizeError> {
563 if s.is_empty() {
564 ::core::result::Result::Ok(&[])
565 } else {
566 let size = $crate::safe_size_to_count::<Self>(s.len())?;
567 let ptr = s.as_ptr() as *const Self;
568
569 ::core::result::Result::Ok(unsafe { ::core::slice::from_raw_parts(ptr, size) })
570 }
571 }
572
573 fn slice_from_byte_slice_mut(s: &mut [u8]) -> ::core::result::Result<&mut [Self], $crate::UnalignedSizeError> {
574 if s.is_empty() {
575 ::core::result::Result::Ok(&mut [])
576 } else {
577 let size = $crate::safe_size_to_count::<Self>(s.len())?;
578 let ptr = s.as_mut_ptr() as *mut Self;
579
580 ::core::result::Result::Ok(unsafe { ::core::slice::from_raw_parts_mut(ptr, size) })
581 }
582 }
583
584 fn slice_as_byte_slice(slice: &[Self]) -> ::core::result::Result<&[u8], $crate::SliceSizeOverflowError> {
585 let data = slice.as_ptr() as *const u8;
586 let len = $crate::safe_count_to_size::<Self>(slice.len())?;
587 ::core::result::Result::Ok(unsafe { ::core::slice::from_raw_parts(data, len) })
588 }
589
590 fn slice_as_byte_slice_mut(slice: &mut [Self]) -> ::core::result::Result<&mut [u8], $crate::SliceSizeOverflowError> {
591 let data = slice.as_ptr() as *mut u8;
592 let len = $crate::safe_count_to_size::<Self>(slice.len())?;
593 ::core::result::Result::Ok(unsafe { ::core::slice::from_raw_parts_mut(data, len) })
594 }
595
596 fn uninit_slice_from_byte_slice(
597 s: &[::core::mem::MaybeUninit<u8>]
598 ) -> ::core::result::Result<&[::core::mem::MaybeUninit<Self>], $crate::UnalignedSizeError> {
599 if s.is_empty() {
600 ::core::result::Result::Ok(&[])
601 } else {
602 let size = $crate::safe_size_to_count::<Self>(s.len())?;
603 let ptr = s.as_ptr() as *const ::core::mem::MaybeUninit<Self>;
604
605 ::core::result::Result::Ok(unsafe { ::core::slice::from_raw_parts(ptr, size) })
606 }
607 }
608
609 fn uninit_slice_from_byte_slice_mut(
610 s: &mut [::core::mem::MaybeUninit<u8>]
611 ) -> ::core::result::Result<&mut [::core::mem::MaybeUninit<Self>], $crate::UnalignedSizeError> {
612 if s.is_empty() {
613 ::core::result::Result::Ok(&mut [])
614 } else {
615 let size = $crate::safe_size_to_count::<Self>(s.len())?;
616 let ptr = s.as_mut_ptr() as *mut ::core::mem::MaybeUninit<Self>;
617
618 ::core::result::Result::Ok(unsafe { ::core::slice::from_raw_parts_mut(ptr, size) })
619 }
620 }
621
622 fn uninit_slice_as_byte_slice(
623 slice: &[::core::mem::MaybeUninit<Self>]
624 ) -> ::core::result::Result<&[::core::mem::MaybeUninit<u8>], $crate::SliceSizeOverflowError> {
625 let data = slice.as_ptr() as *const ::core::mem::MaybeUninit<u8>;
626 let len = ::core::mem::size_of::<Self>().checked_mul(slice.len()).expect("");
627 ::core::result::Result::Ok(unsafe { ::core::slice::from_raw_parts(data, len) })
628 }
629
630 fn uninit_slice_as_byte_slice_mut(
631 slice: &mut [::core::mem::MaybeUninit<Self>]
632 ) -> ::core::result::Result<&mut [::core::mem::MaybeUninit<u8>], $crate::SliceSizeOverflowError> {
633 let data = slice.as_ptr() as *mut ::core::mem::MaybeUninit<u8>;
634 let len = ::core::mem::size_of::<Self>().checked_mul(slice.len()).unwrap();
635 ::core::result::Result::Ok(unsafe { ::core::slice::from_raw_parts_mut(data, len) })
636 }
637 }
638 };
639 (@endian_type little) => {$crate::LittleEndian};
640 (@endian_type big) => {$crate::BigEndian};
641 (@endian_type dynamic) => {$crate::Endian};
642 (@wrapper_type $endian:tt [$ty:ident; $($n:tt)+]) => {
643 [$crate::format_struct!(@wrapper_type $endian $ty); $($n)+]
644 };
645 (@wrapper_type $endian:tt u8) => {u8};
646 (@wrapper_type $endian:tt i8) => {i8};
647 (@wrapper_type $endian:tt u16) => {$crate::U16<$crate::format_struct!(@endian_type $endian)>};
648 (@wrapper_type $endian:tt i16) => {$crate::I16<$crate::format_struct!(@endian_type $endian)>};
649 (@wrapper_type $endian:tt u32) => {$crate::U32<$crate::format_struct!(@endian_type $endian)>};
650 (@wrapper_type $endian:tt i32) => {$crate::I32<$crate::format_struct!(@endian_type $endian)>};
651 (@wrapper_type $endian:tt u64) => {$crate::U64<$crate::format_struct!(@endian_type $endian)>};
652 (@wrapper_type $endian:tt i64) => {$crate::I64<$crate::format_struct!(@endian_type $endian)>};
653 (@wrapper_type $endian:tt u128) => {$crate::U128<$crate::format_struct!(@endian_type $endian)>};
654 (@wrapper_type $endian:tt i128) => {$crate::I128<$crate::format_struct!(@endian_type $endian)>};
655 (@wrapper_type $endian:tt $ty:ty) => {$ty};
656}
657
658format_struct!(@impl_conv u8 size 1);
659define_int_wrapper!(u16, U16);
660define_int_wrapper!(i16, I16);
661define_int_wrapper!(u32, U32);
662define_int_wrapper!(i32, I32);
663define_int_wrapper!(u64, U64);
664define_int_wrapper!(i64, I64);
665define_int_wrapper!(u128, U128);
666define_int_wrapper!(i128, I128);
667
668type Arr<T, const N: usize> = [T; N];
669format_struct!(@impl_conv Arr<T: ReprByteSlice, const N: usize> size N);
670
671#[cfg(test)]
672#[allow(unused, unreachable_pub)]
673mod tests {
674 use super::*;
675 use core::{marker::PhantomData, mem::MaybeUninit};
676
677 const CONSTANT_SIZE: usize = 16;
678
679 format_struct! {
680 #[derive(Default, Clone)]
681 struct little TestLe {
682 #[doc = "this is the third line"]
685 byte: u8,
686 short: u16,
687 word: u32,
688 dword: u64,
689 qword: u128,
690 byte_arr: [u8; 16],
691 short_arr: [u16; 16],
692 }
693
694 #[derive(Default, Clone)]
695 struct big TestBe {
696 pub byte: u8,
697 short: u16,
698 word: u32,
699 dword: u64,
700 qword: u128,
701 byte_arr: [u8; 16],
702 short_arr: [u16; 16],
703 }
704
705 #[derive(Default, Clone)]
706 struct dynamic TestDyn {
707 byte: u8,
708 short: u16,
709 word: u32,
710 dword: u64,
711 qword: u128,
712 byte_arr: [u8; const { 16 }],
713 short_arr: [u16; CONSTANT_SIZE],
714 }
715
716 #[derive(Default, Clone)]
717 struct little TestNested {
718 regular: u8,
719 single: TestBe,
720 array: [TestLe; 2],
721 }
722 }
723
724 #[test]
725 fn test_access_short_arr() {
726 let mut test_le = TestLe::default();
727
728 for (i, s) in test_le.short_arr.iter_mut().enumerate() {
729 *s = U16((i as u16).to_le_bytes(), PhantomData);
730 }
731
732 assert_eq!(test_le.short_arr[5].get(), 5);
733 }
734
735 #[test]
736 fn test_access_u8() {
737 let mut test = TestLe::default();
738
739 test.byte = 42;
740 assert_eq!(test.byte, 42);
741 }
742
743 #[test]
744 fn test_access_u16() {
745 let mut test_le = TestLe::default();
746 test_le.short = U16::new(1337);
747 assert_eq!(test_le.short.get(), 1337);
748 assert_eq!(test_le.short.0, 1337u16.to_le_bytes());
749
750 let mut test_be = TestBe::default();
751 test_be.short = U16::new(1337);
752 assert_eq!(test_be.short.get(), 1337);
753 assert_eq!(test_be.short.0, 1337u16.to_be_bytes());
754 }
755
756 #[test]
757 fn test_access_u32() {
758 let mut test_le = TestLe::default();
759 test_le.word = U32::new(13371337);
760 assert_eq!(test_le.word.get(), 13371337);
761 assert_eq!(test_le.word.0, 13371337u32.to_le_bytes());
762
763 let mut test_be = TestBe::default();
764 test_be.word = U32::new(13371337);
765 assert_eq!(test_be.word.get(), 13371337);
766 assert_eq!(test_be.word.0, 13371337u32.to_be_bytes());
767 }
768
769 #[test]
770 fn test_access_u64() {
771 let mut test_le = TestLe::default();
772 test_le.dword = U64::new(1337133713371337);
773 assert_eq!(test_le.dword.get(), 1337133713371337);
774 assert_eq!(test_le.dword.0, 1337133713371337u64.to_le_bytes());
775
776 let mut test_be = TestBe::default();
777 test_be.dword = U64::new(1337133713371337);
778 assert_eq!(test_be.dword.get(), 1337133713371337);
779 assert_eq!(test_be.dword.0, 1337133713371337u64.to_be_bytes());
780 }
781
782 #[test]
783 fn test_access_u128() {
784 let mut test_le = TestLe::default();
785 test_le.qword = U128::new(13371337133713371337133713371337);
786 assert_eq!(test_le.qword.get(), 13371337133713371337133713371337u128);
787 assert_eq!(
788 test_le.qword.0,
789 13371337133713371337133713371337u128.to_le_bytes()
790 );
791
792 let mut test_be = TestBe::default();
793 test_be.qword = U128::new(13371337133713371337133713371337u128);
794 assert_eq!(test_be.qword.get(), 13371337133713371337133713371337);
795 assert_eq!(
796 test_be.qword.0,
797 13371337133713371337133713371337u128.to_be_bytes()
798 );
799 }
800
801 #[test]
802 fn test_uninit() {
803 let mut test = [
804 MaybeUninit::<TestLe>::uninit(),
805 MaybeUninit::<TestLe>::uninit(),
806 ];
807 TestLe::uninit_slice_as_byte_slice(&test[..]).unwrap()[0];
808 }
809}