use super::super::{Field, StorageIntoFieldView, StorageToFieldView};
use super::view::FieldView;
use super::PrimitiveField;
use crate::endianness::{EndianKind, Endianness};
pub trait FieldCopyAccess: Field {
    type HighLevelType;
    fn read(storage: &[u8]) -> Self::HighLevelType;
    fn write(storage: &mut [u8], v: Self::HighLevelType);
}
macro_rules! impl_field_traits {
    ($type: ty) => {
        impl<E: Endianness, const OFFSET_: usize> Field for PrimitiveField<$type, E, OFFSET_> {
            type Endian = E;
            const OFFSET: usize = OFFSET_;
            const SIZE: Option<usize> = Some(core::mem::size_of::<$type>());
        }
        impl<'a, E: Endianness, const OFFSET_: usize> StorageToFieldView<&'a [u8]>
            for PrimitiveField<$type, E, OFFSET_>
        {
            type View = FieldView<&'a [u8], Self>;
            #[inline(always)]
            fn view(storage: &'a [u8]) -> Self::View {
                Self::View::new(storage)
            }
        }
        impl<'a, E: Endianness, const OFFSET_: usize> StorageToFieldView<&'a mut [u8]>
            for PrimitiveField<$type, E, OFFSET_>
        {
            type View = FieldView<&'a mut [u8], Self>;
            #[inline(always)]
            fn view(storage: &'a mut [u8]) -> Self::View {
                Self::View::new(storage)
            }
        }
        impl<S: AsRef<[u8]>, E: Endianness, const OFFSET_: usize> StorageIntoFieldView<S>
            for PrimitiveField<$type, E, OFFSET_>
        {
            type View = FieldView<S, Self>;
            #[inline(always)]
            fn into_view(storage: S) -> Self::View {
                Self::View::new(storage)
            }
        }
    };
}
macro_rules! int_field {
    ($type:ty) => {
        impl<E: Endianness, const OFFSET_: usize> FieldCopyAccess for PrimitiveField<$type, E, OFFSET_> {
            type HighLevelType = $type;
            doc_comment::doc_comment! {
                concat! {"
                Read the integer field from a given data region, assuming the defined layout, using the [Field] API.
                # Example:
                ```
                use binary_layout::prelude::*;
                define_layout!(my_layout, LittleEndian, {
                    //... other fields ...
                    some_integer_field: ", stringify!($type), "
                    //... other fields ...
                });
                fn func(storage_data: &[u8]) {
                    let read: ", stringify!($type), " = my_layout::some_integer_field::read(storage_data);
                }
                ```
                "},
                #[inline(always)]
                fn read(storage: &[u8]) -> $type {
                    let mut value = [0; core::mem::size_of::<$type>()];
                    value.copy_from_slice(
                        &storage[Self::OFFSET..(Self::OFFSET + core::mem::size_of::<$type>())],
                    );
                    match E::KIND {
                        EndianKind::Big => <$type>::from_be_bytes(value),
                        EndianKind::Little => <$type>::from_le_bytes(value),
                        EndianKind::Native => <$type>::from_ne_bytes(value)
                    }
                }
            }
            doc_comment::doc_comment! {
                concat! {"
                Write the integer field to a given data region, assuming the defined layout, using the [Field] API.
                # Example:
                ```
                use binary_layout::prelude::*;
                define_layout!(my_layout, LittleEndian, {
                    //... other fields ...
                    some_integer_field: ", stringify!($type), "
                    //... other fields ...
                });
                fn func(storage_data: &mut [u8]) {
                    my_layout::some_integer_field::write(storage_data, 10);
                }
                ```
                "},
                #[inline(always)]
                fn write(storage: &mut [u8], value: $type) {
                    let value_as_bytes = match E::KIND {
                        EndianKind::Big => value.to_be_bytes(),
                        EndianKind::Little => value.to_le_bytes(),
                        EndianKind::Native => value.to_ne_bytes(),
                    };
                    storage[Self::OFFSET..(Self::OFFSET + core::mem::size_of::<$type>())]
                        .copy_from_slice(&value_as_bytes);
                }
            }
        }
        impl_field_traits!($type);
    };
}
int_field!(i8);
int_field!(i16);
int_field!(i32);
int_field!(i64);
int_field!(i128);
int_field!(u8);
int_field!(u16);
int_field!(u32);
int_field!(u64);
int_field!(u128);
macro_rules! float_field {
    ($type:ty) => {
        impl<E: Endianness, const OFFSET_: usize> FieldCopyAccess for PrimitiveField<$type, E, OFFSET_> {
            type HighLevelType = $type;
            doc_comment::doc_comment! {
                concat! {"
                Read the float field from a given data region, assuming the defined layout, using the [Field] API.
                # Example:
                ```
                use binary_layout::prelude::*;
                define_layout!(my_layout, LittleEndian, {
                    //... other fields ...
                    some_float_field: ", stringify!($type), "
                    //... other fields ...
                });
                fn func(storage_data: &[u8]) {
                    let read: ", stringify!($type), " = my_layout::some_float_field::read(storage_data);
                }
                ```
                # WARNING
                At it's core, this method uses [", stringify!($type), "::from_bits](https://doc.rust-lang.org/std/primitive.", stringify!($type), ".html#method.from_bits),
                which has some weird behavior around signaling and non-signaling `NaN` values.  Read the
                documentation for [", stringify!($type), "::from_bits](https://doc.rust-lang.org/std/primitive.", stringify!($type), ".html#method.from_bits) which
                explains the situation.
                "},
                #[inline(always)]
                fn read(storage: &[u8]) -> $type {
                    let mut value = [0; core::mem::size_of::<$type>()];
                    value.copy_from_slice(
                        &storage[Self::OFFSET..(Self::OFFSET + core::mem::size_of::<$type>())],
                    );
                    match E::KIND {
                        EndianKind::Big => <$type>::from_be_bytes(value),
                        EndianKind::Little => <$type>::from_le_bytes(value),
                        EndianKind::Native => <$type>::from_ne_bytes(value),
                    }
                }
            }
            doc_comment::doc_comment! {
                concat! {"
                Write the float field to a given data region, assuming the defined layout, using the [Field] API.
                # Example:
                ```
                use binary_layout::prelude::*;
                define_layout!(my_layout, LittleEndian, {
                    //... other fields ...
                    some_float_field: ", stringify!($type), "
                    //... other fields ...
                });
                fn func(storage_data: &mut [u8]) {
                    my_layout::some_float_field::write(storage_data, 10.0);
                }
                ```
                # WARNING
                At it's core, this method uses [", stringify!($type), "::to_bits](https://doc.rust-lang.org/std/primitive.", stringify!($type), ".html#method.to_bits),
                which has some weird behavior around signaling and non-signaling `NaN` values.  Read the
                documentation for [", stringify!($type), "::to_bits](https://doc.rust-lang.org/std/primitive.", stringify!($type), ".html#method.to_bits) which
                explains the situation.
                "},
                #[inline(always)]
                fn write(storage: &mut [u8], value: $type) {
                    let value_as_bytes = match E::KIND {
                        EndianKind::Big => value.to_be_bytes(),
                        EndianKind::Little => value.to_le_bytes(),
                        EndianKind::Native => value.to_ne_bytes(),
                    };
                    storage[Self::OFFSET..(Self::OFFSET + core::mem::size_of::<$type>())]
                        .copy_from_slice(&value_as_bytes);
                }
            }
        }
        impl_field_traits!($type);
    };
}
float_field!(f32);
float_field!(f64);
impl<E: Endianness, const OFFSET_: usize> FieldCopyAccess for PrimitiveField<(), E, OFFSET_> {
    type HighLevelType = ();
    doc_comment::doc_comment! {
        concat! {"
                'Read' the `", stringify!(()), "`-typed field from a given data region, assuming the defined layout, using the [Field] API.
                # Example:
                ```
                use binary_layout::prelude::*;
                define_layout!(my_layout, LittleEndian, {
                    //... other fields ...
                    some_zst_field: ", stringify!(()), "
                    //... other fields ...
                });
                fn func(storage_data: &[u8]) {
                    let read: ", stringify!(()), " = my_layout::some_zst_field::read(storage_data);
                }
                ```
                In reality, this method doesn't do any work; `",
                stringify!(()), "` is a zero-sized type, so there's no work to
                do. This implementation exists solely to make writing derive
                macros simpler.
                "},
        #[inline(always)]
        #[allow(clippy::unused_unit)] fn read(_storage: &[u8]) -> () {
            ()
        }
    }
    doc_comment::doc_comment! {
        concat! {"
                'Write' the `", stringify!(()), "`-typed field to a given data region, assuming the defined layout, using the [Field] API.
                # Example:
                ```
                use binary_layout::prelude::*;
                define_layout!(my_layout, LittleEndian, {
                    //... other fields ...
                    some_zst_field: ", stringify!(()), "
                    //... other fields ...
                });
                fn func(storage_data: &mut [u8]) {
                    my_layout::some_zst_field::write(storage_data, ());
                }
                ```
                # WARNING
                In reality, this method doesn't do any work; `",
                stringify!(()), "` is a zero-sized type, so there's no work to
                do. This implementation exists solely to make writing derive
                macros simpler.
                "},
        #[inline(always)]
        #[allow(clippy::unused_unit)] fn write(_storage: &mut [u8], _value: ()) {
            ()
        }
    }
}
impl_field_traits!(());
#[cfg(test)]
mod tests {
    #![allow(clippy::float_cmp)]
    use crate::prelude::*;
    use crate::PrimitiveField;
    use core::convert::TryInto;
    #[test]
    fn test_i8_littleendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<i8, LittleEndian, 5>;
        type Field2 = PrimitiveField<i8, LittleEndian, 20>;
        Field1::write(&mut storage, 50);
        Field2::write(&mut storage, -20);
        assert_eq!(50, Field1::read(&storage));
        assert_eq!(-20, Field2::read(&storage));
        assert_eq!(50, i8::from_le_bytes((&storage[5..6]).try_into().unwrap()));
        assert_eq!(
            -20,
            i8::from_le_bytes((&storage[20..21]).try_into().unwrap())
        );
        assert_eq!(Some(1), PrimitiveField::<i8, LittleEndian, 5>::SIZE);
        assert_eq!(Some(1), PrimitiveField::<i8, LittleEndian, 5>::SIZE);
    }
    #[test]
    fn test_i8_bigendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<i8, BigEndian, 5>;
        type Field2 = PrimitiveField<i8, BigEndian, 20>;
        Field1::write(&mut storage, 50);
        Field2::write(&mut storage, -20);
        assert_eq!(50, Field1::read(&storage));
        assert_eq!(-20, Field2::read(&storage));
        assert_eq!(50, i8::from_be_bytes((&storage[5..6]).try_into().unwrap()));
        assert_eq!(
            -20,
            i8::from_be_bytes((&storage[20..21]).try_into().unwrap())
        );
        assert_eq!(Some(1), PrimitiveField::<i8, BigEndian, 5>::SIZE);
        assert_eq!(Some(1), PrimitiveField::<i8, BigEndian, 5>::SIZE);
    }
    #[test]
    fn test_i8_nativeendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<i8, NativeEndian, 5>;
        type Field2 = PrimitiveField<i8, NativeEndian, 20>;
        Field1::write(&mut storage, 50);
        Field2::write(&mut storage, -20);
        assert_eq!(50, Field1::read(&storage));
        assert_eq!(-20, Field2::read(&storage));
        assert_eq!(50, i8::from_ne_bytes((&storage[5..6]).try_into().unwrap()));
        assert_eq!(
            -20,
            i8::from_ne_bytes((&storage[20..21]).try_into().unwrap())
        );
        assert_eq!(Some(1), PrimitiveField::<i8, NativeEndian, 5>::SIZE);
        assert_eq!(Some(1), PrimitiveField::<i8, NativeEndian, 5>::SIZE);
    }
    #[test]
    fn test_i16_littleendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<i16, LittleEndian, 5>;
        type Field2 = PrimitiveField<i16, LittleEndian, 20>;
        Field1::write(&mut storage, 500);
        Field2::write(&mut storage, -2000);
        assert_eq!(
            500,
            i16::from_le_bytes((&storage[5..7]).try_into().unwrap())
        );
        assert_eq!(
            -2000,
            i16::from_le_bytes((&storage[20..22]).try_into().unwrap())
        );
        assert_eq!(500, Field1::read(&storage));
        assert_eq!(-2000, Field2::read(&storage));
        assert_eq!(Some(2), PrimitiveField::<i16, LittleEndian, 5>::SIZE);
        assert_eq!(Some(2), PrimitiveField::<i16, LittleEndian, 5>::SIZE);
    }
    #[test]
    fn test_i16_bigendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<i16, BigEndian, 5>;
        type Field2 = PrimitiveField<i16, BigEndian, 20>;
        Field1::write(&mut storage, 500);
        Field2::write(&mut storage, -2000);
        assert_eq!(
            500,
            i16::from_be_bytes((&storage[5..7]).try_into().unwrap())
        );
        assert_eq!(
            -2000,
            i16::from_be_bytes((&storage[20..22]).try_into().unwrap())
        );
        assert_eq!(500, Field1::read(&storage));
        assert_eq!(-2000, Field2::read(&storage));
        assert_eq!(Some(2), PrimitiveField::<i16, BigEndian, 5>::SIZE);
        assert_eq!(Some(2), PrimitiveField::<i16, BigEndian, 5>::SIZE);
    }
    #[test]
    fn test_i16_nativeendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<i16, NativeEndian, 5>;
        type Field2 = PrimitiveField<i16, NativeEndian, 20>;
        Field1::write(&mut storage, 500);
        Field2::write(&mut storage, -2000);
        assert_eq!(
            500,
            i16::from_ne_bytes((&storage[5..7]).try_into().unwrap())
        );
        assert_eq!(
            -2000,
            i16::from_ne_bytes((&storage[20..22]).try_into().unwrap())
        );
        assert_eq!(500, Field1::read(&storage));
        assert_eq!(-2000, Field2::read(&storage));
        assert_eq!(Some(2), PrimitiveField::<i16, NativeEndian, 5>::SIZE);
        assert_eq!(Some(2), PrimitiveField::<i16, NativeEndian, 5>::SIZE);
    }
    #[test]
    fn test_i32_littleendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<i32, LittleEndian, 5>;
        type Field2 = PrimitiveField<i32, LittleEndian, 20>;
        Field1::write(&mut storage, 10i32.pow(8));
        Field2::write(&mut storage, -(10i32.pow(7)));
        assert_eq!(
            10i32.pow(8),
            i32::from_le_bytes((&storage[5..9]).try_into().unwrap())
        );
        assert_eq!(
            -(10i32.pow(7)),
            i32::from_le_bytes((&storage[20..24]).try_into().unwrap())
        );
        assert_eq!(10i32.pow(8), Field1::read(&storage));
        assert_eq!(-(10i32.pow(7)), Field2::read(&storage));
        assert_eq!(Some(4), PrimitiveField::<i32, LittleEndian, 5>::SIZE);
        assert_eq!(Some(4), PrimitiveField::<i32, LittleEndian, 5>::SIZE);
    }
    #[test]
    fn test_i32_bigendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<i32, BigEndian, 5>;
        type Field2 = PrimitiveField<i32, BigEndian, 20>;
        Field1::write(&mut storage, 10i32.pow(8));
        Field2::write(&mut storage, -(10i32.pow(7)));
        assert_eq!(
            10i32.pow(8),
            i32::from_be_bytes((&storage[5..9]).try_into().unwrap())
        );
        assert_eq!(
            -(10i32.pow(7)),
            i32::from_be_bytes((&storage[20..24]).try_into().unwrap())
        );
        assert_eq!(10i32.pow(8), Field1::read(&storage));
        assert_eq!(-(10i32.pow(7)), Field2::read(&storage));
        assert_eq!(Some(4), PrimitiveField::<i32, BigEndian, 5>::SIZE);
        assert_eq!(Some(4), PrimitiveField::<i32, BigEndian, 5>::SIZE);
    }
    #[test]
    fn test_i32_nativeendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<i32, NativeEndian, 5>;
        type Field2 = PrimitiveField<i32, NativeEndian, 20>;
        Field1::write(&mut storage, 10i32.pow(8));
        Field2::write(&mut storage, -(10i32.pow(7)));
        assert_eq!(
            10i32.pow(8),
            i32::from_ne_bytes((&storage[5..9]).try_into().unwrap())
        );
        assert_eq!(
            -(10i32.pow(7)),
            i32::from_ne_bytes((&storage[20..24]).try_into().unwrap())
        );
        assert_eq!(10i32.pow(8), Field1::read(&storage));
        assert_eq!(-(10i32.pow(7)), Field2::read(&storage));
        assert_eq!(Some(4), PrimitiveField::<i32, NativeEndian, 5>::SIZE);
        assert_eq!(Some(4), PrimitiveField::<i32, NativeEndian, 5>::SIZE);
    }
    #[test]
    fn test_i64_littleendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<i64, LittleEndian, 5>;
        type Field2 = PrimitiveField<i64, LittleEndian, 20>;
        Field1::write(&mut storage, 10i64.pow(15));
        Field2::write(&mut storage, -(10i64.pow(14)));
        assert_eq!(
            10i64.pow(15),
            i64::from_le_bytes((&storage[5..13]).try_into().unwrap())
        );
        assert_eq!(
            -(10i64.pow(14)),
            i64::from_le_bytes((&storage[20..28]).try_into().unwrap())
        );
        assert_eq!(10i64.pow(15), Field1::read(&storage));
        assert_eq!(-(10i64.pow(14)), Field2::read(&storage));
        assert_eq!(Some(8), PrimitiveField::<i64, LittleEndian, 5>::SIZE);
        assert_eq!(Some(8), PrimitiveField::<i64, LittleEndian, 5>::SIZE);
    }
    #[test]
    fn test_i64_bigendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<i64, BigEndian, 5>;
        type Field2 = PrimitiveField<i64, BigEndian, 20>;
        Field1::write(&mut storage, 10i64.pow(15));
        Field2::write(&mut storage, -(10i64.pow(14)));
        assert_eq!(
            10i64.pow(15),
            i64::from_be_bytes((&storage[5..13]).try_into().unwrap())
        );
        assert_eq!(
            -(10i64.pow(14)),
            i64::from_be_bytes((&storage[20..28]).try_into().unwrap())
        );
        assert_eq!(10i64.pow(15), Field1::read(&storage));
        assert_eq!(-(10i64.pow(14)), Field2::read(&storage));
        assert_eq!(Some(8), PrimitiveField::<i64, BigEndian, 5>::SIZE);
        assert_eq!(Some(8), PrimitiveField::<i64, BigEndian, 5>::SIZE);
    }
    #[test]
    fn test_i64_nativeendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<i64, NativeEndian, 5>;
        type Field2 = PrimitiveField<i64, NativeEndian, 20>;
        Field1::write(&mut storage, 10i64.pow(15));
        Field2::write(&mut storage, -(10i64.pow(14)));
        assert_eq!(
            10i64.pow(15),
            i64::from_ne_bytes((&storage[5..13]).try_into().unwrap())
        );
        assert_eq!(
            -(10i64.pow(14)),
            i64::from_ne_bytes((&storage[20..28]).try_into().unwrap())
        );
        assert_eq!(10i64.pow(15), Field1::read(&storage));
        assert_eq!(-(10i64.pow(14)), Field2::read(&storage));
        assert_eq!(Some(8), PrimitiveField::<i64, NativeEndian, 5>::SIZE);
        assert_eq!(Some(8), PrimitiveField::<i64, NativeEndian, 5>::SIZE);
    }
    #[test]
    fn test_i128_littleendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<i128, LittleEndian, 5>;
        type Field2 = PrimitiveField<i128, LittleEndian, 200>;
        Field1::write(&mut storage, 10i128.pow(30));
        Field2::write(&mut storage, -(10i128.pow(28)));
        assert_eq!(
            10i128.pow(30),
            i128::from_le_bytes((&storage[5..21]).try_into().unwrap())
        );
        assert_eq!(
            -(10i128.pow(28)),
            i128::from_le_bytes((&storage[200..216]).try_into().unwrap())
        );
        assert_eq!(10i128.pow(30), Field1::read(&storage));
        assert_eq!(-(10i128.pow(28)), Field2::read(&storage));
        assert_eq!(Some(16), PrimitiveField::<i128, LittleEndian, 5>::SIZE);
        assert_eq!(Some(16), PrimitiveField::<i128, LittleEndian, 5>::SIZE);
    }
    #[test]
    fn test_i128_bigendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<i128, BigEndian, 5>;
        type Field2 = PrimitiveField<i128, BigEndian, 200>;
        Field1::write(&mut storage, 10i128.pow(30));
        Field2::write(&mut storage, -(10i128.pow(28)));
        assert_eq!(
            10i128.pow(30),
            i128::from_be_bytes((&storage[5..21]).try_into().unwrap())
        );
        assert_eq!(
            -(10i128.pow(28)),
            i128::from_be_bytes((&storage[200..216]).try_into().unwrap())
        );
        assert_eq!(10i128.pow(30), Field1::read(&storage));
        assert_eq!(-(10i128.pow(28)), Field2::read(&storage));
        assert_eq!(Some(16), PrimitiveField::<i128, BigEndian, 5>::SIZE);
        assert_eq!(Some(16), PrimitiveField::<i128, BigEndian, 5>::SIZE);
    }
    #[test]
    fn test_i128_nativeendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<i128, NativeEndian, 5>;
        type Field2 = PrimitiveField<i128, NativeEndian, 200>;
        Field1::write(&mut storage, 10i128.pow(30));
        Field2::write(&mut storage, -(10i128.pow(28)));
        assert_eq!(
            10i128.pow(30),
            i128::from_ne_bytes((&storage[5..21]).try_into().unwrap())
        );
        assert_eq!(
            -(10i128.pow(28)),
            i128::from_ne_bytes((&storage[200..216]).try_into().unwrap())
        );
        assert_eq!(10i128.pow(30), Field1::read(&storage));
        assert_eq!(-(10i128.pow(28)), Field2::read(&storage));
        assert_eq!(Some(16), PrimitiveField::<i128, NativeEndian, 5>::SIZE);
        assert_eq!(Some(16), PrimitiveField::<i128, NativeEndian, 5>::SIZE);
    }
    #[test]
    fn test_u8_littleendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<u8, LittleEndian, 5>;
        type Field2 = PrimitiveField<u8, LittleEndian, 20>;
        Field1::write(&mut storage, 50);
        Field2::write(&mut storage, 20);
        assert_eq!(50, Field1::read(&storage));
        assert_eq!(20, Field2::read(&storage));
        assert_eq!(50, u8::from_le_bytes((&storage[5..6]).try_into().unwrap()));
        assert_eq!(
            20,
            u8::from_le_bytes((&storage[20..21]).try_into().unwrap())
        );
        assert_eq!(Some(1), PrimitiveField::<u8, LittleEndian, 5>::SIZE);
        assert_eq!(Some(1), PrimitiveField::<u8, LittleEndian, 5>::SIZE);
    }
    #[test]
    fn test_u8_bigendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<u8, BigEndian, 5>;
        type Field2 = PrimitiveField<u8, BigEndian, 20>;
        Field1::write(&mut storage, 50);
        Field2::write(&mut storage, 20);
        assert_eq!(50, Field1::read(&storage));
        assert_eq!(20, Field2::read(&storage));
        assert_eq!(50, u8::from_be_bytes((&storage[5..6]).try_into().unwrap()));
        assert_eq!(
            20,
            u8::from_be_bytes((&storage[20..21]).try_into().unwrap())
        );
        assert_eq!(Some(1), PrimitiveField::<u8, BigEndian, 5>::SIZE);
        assert_eq!(Some(1), PrimitiveField::<u8, BigEndian, 5>::SIZE);
    }
    #[test]
    fn test_u8_nativeendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<u8, NativeEndian, 5>;
        type Field2 = PrimitiveField<u8, NativeEndian, 20>;
        Field1::write(&mut storage, 50);
        Field2::write(&mut storage, 20);
        assert_eq!(50, Field1::read(&storage));
        assert_eq!(20, Field2::read(&storage));
        assert_eq!(50, u8::from_ne_bytes((&storage[5..6]).try_into().unwrap()));
        assert_eq!(
            20,
            u8::from_ne_bytes((&storage[20..21]).try_into().unwrap())
        );
        assert_eq!(Some(1), PrimitiveField::<u8, NativeEndian, 5>::SIZE);
        assert_eq!(Some(1), PrimitiveField::<u8, NativeEndian, 5>::SIZE);
    }
    #[test]
    fn test_u16_littleendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<u16, LittleEndian, 5>;
        type Field2 = PrimitiveField<u16, LittleEndian, 20>;
        Field1::write(&mut storage, 500);
        Field2::write(&mut storage, 2000);
        assert_eq!(
            500,
            u16::from_le_bytes((&storage[5..7]).try_into().unwrap())
        );
        assert_eq!(
            2000,
            u16::from_le_bytes((&storage[20..22]).try_into().unwrap())
        );
        assert_eq!(500, Field1::read(&storage));
        assert_eq!(2000, Field2::read(&storage));
        assert_eq!(Some(2), PrimitiveField::<u16, LittleEndian, 5>::SIZE);
        assert_eq!(Some(2), PrimitiveField::<u16, LittleEndian, 5>::SIZE);
    }
    #[test]
    fn test_u16_bigendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<u16, BigEndian, 5>;
        type Field2 = PrimitiveField<u16, BigEndian, 20>;
        Field1::write(&mut storage, 500);
        Field2::write(&mut storage, 2000);
        assert_eq!(
            500,
            u16::from_be_bytes((&storage[5..7]).try_into().unwrap())
        );
        assert_eq!(
            2000,
            u16::from_be_bytes((&storage[20..22]).try_into().unwrap())
        );
        assert_eq!(500, Field1::read(&storage));
        assert_eq!(2000, Field2::read(&storage));
        assert_eq!(Some(2), PrimitiveField::<u16, BigEndian, 5>::SIZE);
        assert_eq!(Some(2), PrimitiveField::<u16, BigEndian, 5>::SIZE);
    }
    #[test]
    fn test_u16_nativeendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<u16, NativeEndian, 5>;
        type Field2 = PrimitiveField<u16, NativeEndian, 20>;
        Field1::write(&mut storage, 500);
        Field2::write(&mut storage, 2000);
        assert_eq!(
            500,
            u16::from_ne_bytes((&storage[5..7]).try_into().unwrap())
        );
        assert_eq!(
            2000,
            u16::from_ne_bytes((&storage[20..22]).try_into().unwrap())
        );
        assert_eq!(500, Field1::read(&storage));
        assert_eq!(2000, Field2::read(&storage));
        assert_eq!(Some(2), PrimitiveField::<u16, NativeEndian, 5>::SIZE);
        assert_eq!(Some(2), PrimitiveField::<u16, NativeEndian, 5>::SIZE);
    }
    #[test]
    fn test_u32_littleendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<u32, LittleEndian, 5>;
        type Field2 = PrimitiveField<u32, LittleEndian, 20>;
        Field1::write(&mut storage, 10u32.pow(8));
        Field2::write(&mut storage, 10u32.pow(7));
        assert_eq!(
            10u32.pow(8),
            u32::from_le_bytes((&storage[5..9]).try_into().unwrap())
        );
        assert_eq!(
            10u32.pow(7),
            u32::from_le_bytes((&storage[20..24]).try_into().unwrap())
        );
        assert_eq!(10u32.pow(8), Field1::read(&storage));
        assert_eq!(10u32.pow(7), Field2::read(&storage));
        assert_eq!(Some(4), PrimitiveField::<u32, LittleEndian, 5>::SIZE);
        assert_eq!(Some(4), PrimitiveField::<u32, LittleEndian, 5>::SIZE);
    }
    #[test]
    fn test_u32_bigendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<u32, BigEndian, 5>;
        type Field2 = PrimitiveField<u32, BigEndian, 20>;
        Field1::write(&mut storage, 10u32.pow(8));
        Field2::write(&mut storage, 10u32.pow(7));
        assert_eq!(
            10u32.pow(8),
            u32::from_be_bytes((&storage[5..9]).try_into().unwrap())
        );
        assert_eq!(
            10u32.pow(7),
            u32::from_be_bytes((&storage[20..24]).try_into().unwrap())
        );
        assert_eq!(10u32.pow(8), Field1::read(&storage));
        assert_eq!(10u32.pow(7), Field2::read(&storage));
        assert_eq!(Some(4), PrimitiveField::<u32, BigEndian, 5>::SIZE);
        assert_eq!(Some(4), PrimitiveField::<u32, BigEndian, 5>::SIZE);
    }
    #[test]
    fn test_u32_nativeendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<u32, NativeEndian, 5>;
        type Field2 = PrimitiveField<u32, NativeEndian, 20>;
        Field1::write(&mut storage, 10u32.pow(8));
        Field2::write(&mut storage, 10u32.pow(7));
        assert_eq!(
            10u32.pow(8),
            u32::from_ne_bytes((&storage[5..9]).try_into().unwrap())
        );
        assert_eq!(
            10u32.pow(7),
            u32::from_ne_bytes((&storage[20..24]).try_into().unwrap())
        );
        assert_eq!(10u32.pow(8), Field1::read(&storage));
        assert_eq!(10u32.pow(7), Field2::read(&storage));
        assert_eq!(Some(4), PrimitiveField::<u32, NativeEndian, 5>::SIZE);
        assert_eq!(Some(4), PrimitiveField::<u32, NativeEndian, 5>::SIZE);
    }
    #[test]
    fn test_u64_littleendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<u64, LittleEndian, 5>;
        type Field2 = PrimitiveField<u64, LittleEndian, 20>;
        Field1::write(&mut storage, 10u64.pow(15));
        Field2::write(&mut storage, 10u64.pow(14));
        assert_eq!(
            10u64.pow(15),
            u64::from_le_bytes((&storage[5..13]).try_into().unwrap())
        );
        assert_eq!(
            10u64.pow(14),
            u64::from_le_bytes((&storage[20..28]).try_into().unwrap())
        );
        assert_eq!(10u64.pow(15), Field1::read(&storage));
        assert_eq!(10u64.pow(14), Field2::read(&storage));
        assert_eq!(Some(8), PrimitiveField::<u64, LittleEndian, 5>::SIZE);
        assert_eq!(Some(8), PrimitiveField::<u64, LittleEndian, 5>::SIZE);
    }
    #[test]
    fn test_u64_bigendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<u64, BigEndian, 5>;
        type Field2 = PrimitiveField<u64, BigEndian, 20>;
        Field1::write(&mut storage, 10u64.pow(15));
        Field2::write(&mut storage, 10u64.pow(14));
        assert_eq!(
            10u64.pow(15),
            u64::from_be_bytes((&storage[5..13]).try_into().unwrap())
        );
        assert_eq!(
            10u64.pow(14),
            u64::from_be_bytes((&storage[20..28]).try_into().unwrap())
        );
        assert_eq!(10u64.pow(15), Field1::read(&storage));
        assert_eq!(10u64.pow(14), Field2::read(&storage));
        assert_eq!(Some(8), PrimitiveField::<u64, BigEndian, 5>::SIZE);
        assert_eq!(Some(8), PrimitiveField::<u64, BigEndian, 5>::SIZE);
    }
    #[test]
    fn test_u64_nativeendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<u64, NativeEndian, 5>;
        type Field2 = PrimitiveField<u64, NativeEndian, 20>;
        Field1::write(&mut storage, 10u64.pow(15));
        Field2::write(&mut storage, 10u64.pow(14));
        assert_eq!(
            10u64.pow(15),
            u64::from_ne_bytes((&storage[5..13]).try_into().unwrap())
        );
        assert_eq!(
            10u64.pow(14),
            u64::from_ne_bytes((&storage[20..28]).try_into().unwrap())
        );
        assert_eq!(10u64.pow(15), Field1::read(&storage));
        assert_eq!(10u64.pow(14), Field2::read(&storage));
        assert_eq!(Some(8), PrimitiveField::<u64, NativeEndian, 5>::SIZE);
        assert_eq!(Some(8), PrimitiveField::<u64, NativeEndian, 5>::SIZE);
    }
    #[test]
    fn test_u128_littleendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<u128, LittleEndian, 5>;
        type Field2 = PrimitiveField<u128, LittleEndian, 200>;
        Field1::write(&mut storage, 10u128.pow(30));
        Field2::write(&mut storage, 10u128.pow(28));
        assert_eq!(
            10u128.pow(30),
            u128::from_le_bytes((&storage[5..21]).try_into().unwrap())
        );
        assert_eq!(
            10u128.pow(28),
            u128::from_le_bytes((&storage[200..216]).try_into().unwrap())
        );
        assert_eq!(10u128.pow(30), Field1::read(&storage));
        assert_eq!(10u128.pow(28), Field2::read(&storage));
        assert_eq!(Some(16), PrimitiveField::<u128, LittleEndian, 5>::SIZE);
        assert_eq!(Some(16), PrimitiveField::<u128, LittleEndian, 5>::SIZE);
    }
    #[test]
    fn test_u128_bigendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<u128, BigEndian, 5>;
        type Field2 = PrimitiveField<u128, BigEndian, 200>;
        Field1::write(&mut storage, 10u128.pow(30));
        Field2::write(&mut storage, 10u128.pow(28));
        assert_eq!(
            10u128.pow(30),
            u128::from_be_bytes((&storage[5..21]).try_into().unwrap())
        );
        assert_eq!(
            10u128.pow(28),
            u128::from_be_bytes((&storage[200..216]).try_into().unwrap())
        );
        assert_eq!(10u128.pow(30), Field1::read(&storage));
        assert_eq!(10u128.pow(28), Field2::read(&storage));
        assert_eq!(Some(16), PrimitiveField::<u128, BigEndian, 5>::SIZE);
        assert_eq!(Some(16), PrimitiveField::<u128, BigEndian, 5>::SIZE);
    }
    #[test]
    fn test_u128_nativeendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<u128, NativeEndian, 5>;
        type Field2 = PrimitiveField<u128, NativeEndian, 200>;
        Field1::write(&mut storage, 10u128.pow(30));
        Field2::write(&mut storage, 10u128.pow(28));
        assert_eq!(
            10u128.pow(30),
            u128::from_ne_bytes((&storage[5..21]).try_into().unwrap())
        );
        assert_eq!(
            10u128.pow(28),
            u128::from_ne_bytes((&storage[200..216]).try_into().unwrap())
        );
        assert_eq!(10u128.pow(30), Field1::read(&storage));
        assert_eq!(10u128.pow(28), Field2::read(&storage));
        assert_eq!(Some(16), PrimitiveField::<u128, NativeEndian, 5>::SIZE);
        assert_eq!(Some(16), PrimitiveField::<u128, NativeEndian, 5>::SIZE);
    }
    #[test]
    fn test_f32_littleendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<f32, LittleEndian, 5>;
        type Field2 = PrimitiveField<f32, LittleEndian, 20>;
        Field1::write(&mut storage, 10f32.powf(8.31));
        Field2::write(&mut storage, -(10f32.powf(7.31)));
        assert_eq!(
            10f32.powf(8.31),
            f32::from_le_bytes((&storage[5..9]).try_into().unwrap())
        );
        assert_eq!(
            -(10f32.powf(7.31)),
            f32::from_le_bytes((&storage[20..24]).try_into().unwrap())
        );
        assert_eq!(10f32.powf(8.31), Field1::read(&storage));
        assert_eq!(-(10f32.powf(7.31)), Field2::read(&storage));
        assert_eq!(Some(4), PrimitiveField::<f32, LittleEndian, 5>::SIZE);
        assert_eq!(Some(4), PrimitiveField::<f32, LittleEndian, 5>::SIZE);
    }
    #[test]
    fn test_f32_bigendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<f32, BigEndian, 5>;
        type Field2 = PrimitiveField<f32, BigEndian, 20>;
        Field1::write(&mut storage, 10f32.powf(8.31));
        Field2::write(&mut storage, -(10f32.powf(7.31)));
        assert_eq!(
            10f32.powf(8.31),
            f32::from_be_bytes((&storage[5..9]).try_into().unwrap())
        );
        assert_eq!(
            -(10f32.powf(7.31)),
            f32::from_be_bytes((&storage[20..24]).try_into().unwrap())
        );
        assert_eq!(10f32.powf(8.31), Field1::read(&storage));
        assert_eq!(-(10f32.powf(7.31)), Field2::read(&storage));
        assert_eq!(Some(4), PrimitiveField::<f32, BigEndian, 5>::SIZE);
        assert_eq!(Some(4), PrimitiveField::<f32, BigEndian, 5>::SIZE);
    }
    #[test]
    fn test_f32_nativeendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<f32, NativeEndian, 5>;
        type Field2 = PrimitiveField<f32, NativeEndian, 20>;
        Field1::write(&mut storage, 10f32.powf(8.31));
        Field2::write(&mut storage, -(10f32.powf(7.31)));
        assert_eq!(
            10f32.powf(8.31),
            f32::from_ne_bytes((&storage[5..9]).try_into().unwrap())
        );
        assert_eq!(
            -(10f32.powf(7.31)),
            f32::from_ne_bytes((&storage[20..24]).try_into().unwrap())
        );
        assert_eq!(10f32.powf(8.31), Field1::read(&storage));
        assert_eq!(-(10f32.powf(7.31)), Field2::read(&storage));
        assert_eq!(Some(4), PrimitiveField::<f32, NativeEndian, 5>::SIZE);
        assert_eq!(Some(4), PrimitiveField::<f32, NativeEndian, 5>::SIZE);
    }
    #[test]
    fn test_f64_littleendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<f64, LittleEndian, 5>;
        type Field2 = PrimitiveField<f64, LittleEndian, 20>;
        Field1::write(&mut storage, 10f64.powf(15.31));
        Field2::write(&mut storage, -(10f64.powf(15.31)));
        assert_eq!(
            10f64.powf(15.31),
            f64::from_le_bytes((&storage[5..13]).try_into().unwrap())
        );
        assert_eq!(
            -(10f64.powf(15.31)),
            f64::from_le_bytes((&storage[20..28]).try_into().unwrap())
        );
        assert_eq!(10f64.powf(15.31), Field1::read(&storage));
        assert_eq!(-(10f64.powf(15.31)), Field2::read(&storage));
        assert_eq!(Some(8), PrimitiveField::<f64, LittleEndian, 5>::SIZE);
        assert_eq!(Some(8), PrimitiveField::<f64, LittleEndian, 5>::SIZE);
    }
    #[test]
    fn test_f64_bigendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<f64, BigEndian, 5>;
        type Field2 = PrimitiveField<f64, BigEndian, 20>;
        Field1::write(&mut storage, 10f64.powf(15.31));
        Field2::write(&mut storage, -(10f64.powf(15.31)));
        assert_eq!(
            10f64.powf(15.31),
            f64::from_be_bytes((&storage[5..13]).try_into().unwrap())
        );
        assert_eq!(
            -(10f64.powf(15.31)),
            f64::from_be_bytes((&storage[20..28]).try_into().unwrap())
        );
        assert_eq!(10f64.powf(15.31), Field1::read(&storage));
        assert_eq!(-(10f64.powf(15.31)), Field2::read(&storage));
        assert_eq!(Some(8), PrimitiveField::<f64, BigEndian, 5>::SIZE);
        assert_eq!(Some(8), PrimitiveField::<f64, BigEndian, 5>::SIZE);
    }
    #[test]
    fn test_f64_nativeendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<f64, NativeEndian, 5>;
        type Field2 = PrimitiveField<f64, NativeEndian, 20>;
        Field1::write(&mut storage, 10f64.powf(15.31));
        Field2::write(&mut storage, -(10f64.powf(15.31)));
        assert_eq!(
            10f64.powf(15.31),
            f64::from_ne_bytes((&storage[5..13]).try_into().unwrap())
        );
        assert_eq!(
            -(10f64.powf(15.31)),
            f64::from_ne_bytes((&storage[20..28]).try_into().unwrap())
        );
        assert_eq!(10f64.powf(15.31), Field1::read(&storage));
        assert_eq!(-(10f64.powf(15.31)), Field2::read(&storage));
        assert_eq!(Some(8), PrimitiveField::<f64, NativeEndian, 5>::SIZE);
        assert_eq!(Some(8), PrimitiveField::<f64, NativeEndian, 5>::SIZE);
    }
    #[allow(clippy::unit_cmp)]
    #[test]
    fn test_unit_bigendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<(), BigEndian, 5>;
        type Field2 = PrimitiveField<(), BigEndian, 20>;
        Field1::write(&mut storage, ());
        Field2::write(&mut storage, ());
        assert_eq!((), Field1::read(&storage));
        assert_eq!((), Field2::read(&storage));
        assert_eq!(Some(0), PrimitiveField::<(), BigEndian, 5>::SIZE);
        assert_eq!(Some(0), PrimitiveField::<(), BigEndian, 20>::SIZE);
        assert_eq!(storage, vec![0; 1024]);
    }
    #[allow(clippy::unit_cmp)]
    #[test]
    fn test_unit_littleendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<(), LittleEndian, 5>;
        type Field2 = PrimitiveField<(), LittleEndian, 20>;
        Field1::write(&mut storage, ());
        Field2::write(&mut storage, ());
        assert_eq!((), Field1::read(&storage));
        assert_eq!((), Field2::read(&storage));
        assert_eq!(Some(0), PrimitiveField::<(), LittleEndian, 5>::SIZE);
        assert_eq!(Some(0), PrimitiveField::<(), LittleEndian, 20>::SIZE);
        assert_eq!(storage, vec![0; 1024]);
    }
    #[allow(clippy::unit_cmp)]
    #[test]
    fn test_unit_nativeendian() {
        let mut storage = vec![0; 1024];
        type Field1 = PrimitiveField<(), NativeEndian, 5>;
        type Field2 = PrimitiveField<(), NativeEndian, 20>;
        Field1::write(&mut storage, ());
        Field2::write(&mut storage, ());
        assert_eq!((), Field1::read(&storage));
        assert_eq!((), Field2::read(&storage));
        assert_eq!(Some(0), PrimitiveField::<(), NativeEndian, 5>::SIZE);
        assert_eq!(Some(0), PrimitiveField::<(), NativeEndian, 20>::SIZE);
        assert_eq!(storage, vec![0; 1024]);
    }
}