format_struct/
lib.rs

1//! A crate for quick and easy format structure definitions for use in binary file parsing.
2//!
3//! # Usage
4//!
5//! This crate should be used by invoking the provided [`format_struct`] macro like this:
6//!
7//! ```rust
8//! use format_struct::{format_struct, ReprByteSlice};
9//!
10//! // Here we define a small structure.
11//! format_struct! {
12//!     struct little Test {
13//!         foo: u8,
14//!         bar: u32,
15//!         baz: [u8; 2],
16//!     }
17//! }
18//!
19//! # pub fn main() {
20//! // This is the data we want to parse:
21//! let data = &[
22//!     0x42u8, // this goes into foo
23//!     0x39, 0x05, 0x00, 0x00, // this goes into bar
24//!     0xaa, 0x55, // this goes into baz
25//! ][..];
26//!
27//! // This is completely zero-cost since the implementation is just a transmute.
28//! let s = Test::from_byte_slice(data).unwrap();
29//!
30//! // Each integer field access compiles to a single unaligned memory access instruction.
31//! assert_eq!(s.foo, 0x42);
32//! assert_eq!(s.bar.get(), 1337);
33//! assert_eq!(&s.baz, &[0xaa, 0x55]);
34//! # }
35//! ```
36
37#![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/// The error type returned when a byte slice of size that is either not equal to or not a multiple
56/// of the target type's size is transmuted into that type.
57#[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/// The error type returned when a type is transmuted into a byte slice and the multiple of the
70/// slice's length and the type's size overflows `isize`.
71#[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
83/// Safely multiplies a size of a type with a count.
84///
85/// # Errors
86///
87/// Returns [`SliceSizeOverflowError`] in case the resulting value overflows [`isize`]
88pub 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
102/// Checks that the specified size if a multiple of a type's size and returns the size divided by
103/// the type's size.
104///
105/// # Errors
106///
107/// Returns [`UnalignedSizeError`] in case the provided size is not aligned or `T` is zero sized type.
108pub 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
120/// An **unsafe** trait for types that may be safely transmuted from and to byte slices.
121///
122/// This trait is usually automatically implemented by the [`format_struct`] macro so there is no
123/// need to implement it manually.
124///
125/// All the trait's methods could be implemented automatically but are not due to limitations of the
126/// Rust's generics: using `Self` in a const context (array size on our case) isn't possible in
127/// traits. Since the trait isn't meant to be implemented manually that is considered a non-issue.
128///
129/// # Safety
130///
131/// Types implementing the trait must be safe to transmute from an arbitrary byte slice of the same
132/// size as the type itself. The alignment for the type must be 1.
133pub unsafe trait ReprByteSlice: Sized {
134    /// Transmutes an immutable byte slice reference into an immutable `Self` reference.
135    ///
136    /// # Errors
137    ///
138    /// Returns an error in case the size doesn't match the type's size.
139    fn from_byte_slice(s: &[u8]) -> Result<&Self, UnalignedSizeError>;
140
141    /// Transmutes a mutable byte slice reference into a mutable `Self` reference.
142    ///
143    /// # Errors
144    ///
145    /// Returns an error in case the size doesn't match the type's size.
146    fn from_byte_slice_mut(s: &mut [u8]) -> Result<&mut Self, UnalignedSizeError>;
147
148    /// Transmutes an immutable reference to `self` into an immutable reference to a byte slice.
149    fn as_byte_slice(&self) -> &[u8];
150
151    /// Transmutes a mutable reference to `self` into a mutable reference to a byte slice.
152    fn as_byte_slice_mut(&mut self) -> &mut [u8];
153
154    /// Transmutes an immutable byte slice reference into an immutable to a slice of `Self`.
155    ///
156    /// # Errors
157    ///
158    /// Returns an error in case the size isn't a multiple of the type's size.
159    fn slice_from_byte_slice(s: &[u8]) -> Result<&[Self], UnalignedSizeError>;
160
161    /// Transmutes a mutable byte slice reference into a mutable to a slice of `Self`.
162    ///
163    /// # Errors
164    ///
165    /// Returns an error in case the size isn't a multiple of the type's size.
166    fn slice_from_byte_slice_mut(s: &mut [u8]) -> Result<&mut [Self], UnalignedSizeError>;
167
168    /// Transmutes an immutable reference to a slice of `Self` into an immutable reference to a byte
169    /// slice.
170    ///
171    /// # Errors
172    ///
173    /// Returns [`SliceSizeOverflowError`] in case the product of the slice length and the type's
174    /// size would be larger than [`isize::MAX`].
175    fn slice_as_byte_slice(slice: &[Self]) -> Result<&[u8], SliceSizeOverflowError>;
176
177    /// Transmutes a mutable reference to a slice of `Self` into a mutable reference to a byte
178    /// slice.
179    ///
180    /// # Errors
181    ///
182    /// Returns [`SliceSizeOverflowError`] in case the product of the slice length and the type's
183    /// size would be larger than [`isize::MAX`].
184    fn slice_as_byte_slice_mut(s: &mut [Self]) -> Result<&mut [u8], SliceSizeOverflowError>;
185
186    /// Splits an immutable slice into two parts where the first one has the same size as `Self`.
187    /// The first part is then transmuted to an immutable reference to `Self` and the second is
188    /// returned as is.
189    ///
190    /// In case the slice is smaller than `Self`, returns `None`.
191    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    /// Splits a mutable byte slice into two parts where the first one has the same size as
200    /// `Self`. The first part is then transmuted to a mutable reference to `Self` and the
201    /// second is returned as is.
202    ///
203    /// In case the slice is smaller than `Self`, returns `None`.
204    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    /// Transmutes an immutable reference to a slice of [`MaybeUninit<u8>`] into an immutable
213    /// reference to a slice of [`MaybeUninit<Self>`].
214    ///
215    /// # Errors
216    ///
217    /// Returns an error in case the size isn't a multiple of the type's size.
218    fn uninit_slice_from_byte_slice(
219        bytes: &[MaybeUninit<u8>],
220    ) -> Result<&[MaybeUninit<Self>], UnalignedSizeError>;
221
222    /// Transmutes a mutable reference to a slice of [`MaybeUninit<u8>`] into a mutable reference
223    /// to a slice of [`MaybeUninit<Self>`].
224    ///
225    /// # Errors
226    ///
227    /// Returns an error in case the size isn't a multiple of the type's size.
228    fn uninit_slice_from_byte_slice_mut(
229        bytes: &mut [MaybeUninit<u8>],
230    ) -> Result<&mut [MaybeUninit<Self>], UnalignedSizeError>;
231
232    /// Transmutes an immutable reference to a slice of [`MaybeUninit<Self>`] into an immutable
233    /// reference to a slice of [`MaybeUninit<u8>`].
234    ///
235    /// # Errors
236    ///
237    /// Returns [`SliceSizeOverflowError`] in case the product of the slice length and the type's
238    /// size would be larger than [`isize::MAX`].
239    fn uninit_slice_as_byte_slice(
240        slice: &[MaybeUninit<Self>],
241    ) -> Result<&[MaybeUninit<u8>], SliceSizeOverflowError>;
242
243    /// Transmutes a mutable reference to a slice of [`MaybeUninit<u8>`] into a mutable reference
244    /// to a slice of [`MaybeUninit<Self>`].
245    ///
246    /// # Errors
247    ///
248    /// Returns [`SliceSizeOverflowError`] in case the product of the slice length and the type's
249    /// size would be larger than [`isize::MAX`].
250    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        /// The generic parameter represents the endianness used to decode the wrapped value. In
261        /// case the value is expected to have fixed endianness, either [`BigEndian`] or
262        /// [`LittleEndian`] types should be used, otherwise the [`Endian`] type.
263        #[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/// Defines a structure that can be transmuted from/into a byte slice for parsing/constructing binary formats in a
372/// zero-copy way.
373///
374/// The macro achieves this by replacing all multibyte integers with wrapper types that are byte
375/// arrays internally and only allowing integer and fixed size array fields in a structure.
376///
377/// Accepted syntax is similar to a standard structure definition in Rust with some differences:
378///
379/// * The `struct` keyword is followed by either `little` or `big` keywords if you want fixed
380///   endianness or `dynamic` keyword if you want dynamic endianness.
381/// * Fields of the generated structure may only have documentation meta, other meta types are
382///   disallowed.
383///
384/// # Examples
385///
386/// ```rust
387/// # use format_struct::format_struct;
388/// format_struct! {
389///     /// A little-endian test structure.
390///     #[derive(Default, Clone)]
391///     pub struct little Test {
392///         /// this byte is public
393///         pub byte: u8,
394///         short: u16,
395///         word: i32,
396///         dword: i64,
397///         qword: u128,
398///         byte_arr: [u8; 16],
399///     }
400/// }
401/// ```
402///
403/// It is also possible to define multiple structures in one macro invocation:
404///
405/// ```rust
406/// # use format_struct::format_struct;
407/// format_struct! {
408///     struct little Foo {
409///         byte: u8,
410///     }
411///
412///     struct big Bar {
413///         a: u64,
414///     }
415///
416///     pub struct little Baz {
417///         z: [u8; 33],
418///     }
419/// }
420/// ```
421///
422/// # Allowed field types
423///
424/// Integer types (`u8`, `u16`, `u32`, `u64`, `u128` and their signed counterparts) are allowed. Multi-byte integer
425/// types are converted to wrapper types with alignment 1 (u16 to [`U16`], u32 to [`U32`], ...).
426///
427/// Statically-sized arrays of types implementing [`ReprByteSlice`] are allowed as well making it possible to nest
428/// structures defined by the [`format_struct`] macros.
429///
430/// Example:
431/// ```rust
432/// # use format_struct::format_struct;
433/// format_struct! {
434///     #[derive(Clone, Debug)]
435///     struct little TopLevel {
436///         foo: u32,
437///         nested: Nested,
438///     }
439///
440///     #[derive(Clone, Debug)]
441///     struct big Nested {
442///         bar: u32,
443///     }
444/// }
445/// ```
446///
447/// Note that nested structures are only affected by their endian specifiers. In the example above field `bar` of
448/// the `Nested` structure will be big-endian even when wrapped into the `TopLevel` structure.
449///
450/// # Layout
451///
452/// The fields in the structure are laid out in declaration order without any padding. That means that the following
453/// structure will take 7 bytes instead of 16 you might expect:
454///
455/// ```rust
456/// # use format_struct::format_struct;
457/// format_struct! {
458///     struct little SmallStruct {
459///         byte: u8,
460///         dword: u64,
461///     }
462/// }
463/// ```
464#[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            /// this is a byte
683            /// this is a multiline comment
684            #[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}