/// The main core of the parser.
///
/// TODO: split into more module (error, trait, base type)
use std::io::{Cursor, Read, Seek, SeekFrom, Write};

pub use androscalpel_serializer_derive::*;

pub mod leb;
pub mod string;
pub use leb::*;
pub use string::*;

#[derive(Debug, PartialEq, Eq)]
pub enum Error {
    InputTooSmall(String), // TODO: find a better name
    SerializationError(String),
    DeserializationError(String),
    InvalidStringEncoding(String),
    InconsistantStruct(String),
    OutOfBound(String),
}

pub type Result<T> = core::result::Result<T, Error>;

pub trait ReadSeek: Read + Seek {}
impl<T: Read + Seek> ReadSeek for T {}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            Self::InputTooSmall(msg) => write!(f, "{}", msg),
            Self::SerializationError(msg) => write!(f, "{}", msg),
            Self::DeserializationError(msg) => write!(f, "{}", msg),
            Self::InvalidStringEncoding(msg) => write!(f, "{}", msg),
            Self::InconsistantStruct(msg) => write!(f, "{}", msg),
            Self::OutOfBound(msg) => write!(f, "{}", msg),
        }
    }
}

impl std::error::Error for Error {}

pub trait Serializable {
    fn serialize(&self, output: &mut dyn Write) -> Result<()>;
    fn deserialize(input: &mut dyn ReadSeek) -> Result<Self>
    where
        Self: Sized;
    fn size(&self) -> usize;

    fn serialize_to_vec(&self) -> Result<Vec<u8>> {
        let mut output = Cursor::new(Vec::<u8>::new());
        self.serialize(&mut output)?;
        Ok(output.into_inner())
    }

    fn deserialize_from_slice(input: &[u8]) -> Result<Self>
    where
        Self: Sized,
    {
        let mut buffer = Cursor::new(input);
        Self::deserialize(&mut buffer)
    }
}

pub trait SerializableUntil<D: Serializable, U: Serializable + Eq> {
    fn serialize(&self, output: &mut dyn Write, end_val: U) -> Result<()>;
    fn deserialize(input: &mut dyn ReadSeek, end_val: U) -> Result<Self>
    where
        Self: Sized;
    fn size(&self, end_val: U) -> usize;
    fn serialize_to_vec(&self, end_val: U) -> Result<Vec<u8>> {
        let mut output = Cursor::new(Vec::<u8>::new());
        self.serialize(&mut output, end_val)?;
        Ok(output.into_inner())
    }

    fn deserialize_from_slice(input: &[u8], end_val: U) -> Result<Self>
    where
        Self: Sized,
    {
        let mut buffer = Cursor::new(input);
        Self::deserialize(&mut buffer, end_val)
    }
}

impl<D: Serializable, U: Serializable + Eq> SerializableUntil<D, U> for Vec<D> {
    fn serialize(&self, output: &mut dyn Write, end_val: U) -> Result<()> {
        for data in self {
            data.serialize(output)?;
        }
        end_val.serialize(output)
    }

    fn deserialize(input: &mut dyn ReadSeek, end_val: U) -> Result<Self>
    where
        Self: Sized,
    {
        let mut data = Self::new();
        loop {
            let pos = input.stream_position().map_err(|err| {
                Error::SerializationError(format!("Failled to get position in steam: {err}"))
            })?;
            match U::deserialize(input) {
                Ok(val) if val == end_val => break Ok(data),
                Err(err) => break Err(err),
                Ok(_) => input.seek(SeekFrom::Start(pos)).map_err(|err| {
                    Error::SerializationError(format!("Failled to get to position in steam: {err}"))
                })?,
            };
            data.push(D::deserialize(input)?);
        }
    }

    fn size(&self, end_val: U) -> usize {
        self.iter().map(|data| data.size()).sum::<usize>() + end_val.size()
    }
}

impl Serializable for u8 {
    fn serialize(&self, output: &mut dyn Write) -> Result<()> {
        output.write_all(&self.to_le_bytes()).map_err(|err| {
            Error::SerializationError(format!("Failed to write serialize u8 to output: {err}"))
        })?;
        Ok(())
    }

    fn deserialize(input: &mut dyn ReadSeek) -> Result<Self> {
        let mut buffer = [0u8; 1];
        input.read_exact(&mut buffer).map_err(|_| {
            Error::InputTooSmall("Failed to read all bytes for u8 from the input".into())
        })?;
        Ok(Self::from_le_bytes(buffer))
    }

    fn size(&self) -> usize {
        1
    }
}

impl Serializable for i8 {
    fn serialize(&self, output: &mut dyn Write) -> Result<()> {
        output.write_all(&self.to_le_bytes()).map_err(|err| {
            Error::SerializationError(format!("Failed to write serialize i8 to output: {err}"))
        })?;
        Ok(())
    }

    fn deserialize(input: &mut dyn ReadSeek) -> Result<Self> {
        let mut buffer = [0u8; 1];
        input.read_exact(&mut buffer).map_err(|_| {
            Error::InputTooSmall("Failed to read all bytes for i8 from the input".into())
        })?;
        Ok(Self::from_le_bytes(buffer))
    }

    fn size(&self) -> usize {
        1
    }
}

impl Serializable for u16 {
    fn serialize(&self, output: &mut dyn Write) -> Result<()> {
        output.write_all(&self.to_le_bytes()).map_err(|err| {
            Error::SerializationError(format!("Failed to write serialize u16 to output: {err}"))
        })?;
        Ok(())
    }

    fn deserialize(input: &mut dyn ReadSeek) -> Result<Self> {
        let mut buffer = [0u8; 2];
        input.read_exact(&mut buffer).map_err(|_| {
            Error::InputTooSmall("Failed to read all bytes for u16 from the input".into())
        })?;
        Ok(Self::from_le_bytes(buffer))
    }

    fn size(&self) -> usize {
        2
    }
}

impl Serializable for i16 {
    fn serialize(&self, output: &mut dyn Write) -> Result<()> {
        output.write_all(&self.to_le_bytes()).map_err(|err| {
            Error::SerializationError(format!("Failed to write serialize i16 to output: {err}"))
        })?;
        Ok(())
    }

    fn deserialize(input: &mut dyn ReadSeek) -> Result<Self> {
        let mut buffer = [0u8; 2];
        input.read_exact(&mut buffer).map_err(|_| {
            Error::InputTooSmall("Failed to read all bytes for i16 from the input".into())
        })?;
        Ok(Self::from_le_bytes(buffer))
    }

    fn size(&self) -> usize {
        2
    }
}

impl Serializable for u32 {
    fn serialize(&self, output: &mut dyn Write) -> Result<()> {
        output.write_all(&self.to_le_bytes()).map_err(|err| {
            Error::SerializationError(format!("Failed to write serialize u32 to output: {err}"))
        })?;
        Ok(())
    }

    fn deserialize(input: &mut dyn ReadSeek) -> Result<Self> {
        let mut buffer = [0u8; 4];
        input.read_exact(&mut buffer).map_err(|_| {
            Error::InputTooSmall("Failed to read all bytes for u32 from the input".into())
        })?;
        Ok(Self::from_le_bytes(buffer))
    }

    fn size(&self) -> usize {
        4
    }
}

impl Serializable for i32 {
    fn serialize(&self, output: &mut dyn Write) -> Result<()> {
        output.write_all(&self.to_le_bytes()).map_err(|err| {
            Error::SerializationError(format!("Failed to write serialize i32 to output: {err}"))
        })?;
        Ok(())
    }

    fn deserialize(input: &mut dyn ReadSeek) -> Result<Self> {
        let mut buffer = [0u8; 4];
        input.read_exact(&mut buffer).map_err(|_| {
            Error::InputTooSmall("Failed to read all bytes for i32 from the input".into())
        })?;
        Ok(Self::from_le_bytes(buffer))
    }

    fn size(&self) -> usize {
        4
    }
}

impl Serializable for u64 {
    fn serialize(&self, output: &mut dyn Write) -> Result<()> {
        output.write_all(&self.to_le_bytes()).map_err(|err| {
            Error::SerializationError(format!("Failed to write serialize u64 to output: {err}"))
        })?;
        Ok(())
    }

    fn deserialize(input: &mut dyn ReadSeek) -> Result<Self> {
        let mut buffer = [0u8; 8];
        input.read_exact(&mut buffer).map_err(|_| {
            Error::InputTooSmall("Failed to read all bytes for u64 from the input".into())
        })?;
        Ok(Self::from_le_bytes(buffer))
    }

    fn size(&self) -> usize {
        8
    }
}

impl Serializable for i64 {
    fn serialize(&self, output: &mut dyn Write) -> Result<()> {
        output.write_all(&self.to_le_bytes()).map_err(|err| {
            Error::SerializationError(format!("Failed to write serialize i64 to output: {err}"))
        })?;
        Ok(())
    }

    fn deserialize(input: &mut dyn ReadSeek) -> Result<Self> {
        let mut buffer = [0u8; 8];
        input.read_exact(&mut buffer).map_err(|_| {
            Error::InputTooSmall("Failed to read all bytes for i64 from the input".into())
        })?;
        Ok(Self::from_le_bytes(buffer))
    }

    fn size(&self) -> usize {
        8
    }
}

impl Serializable for u128 {
    fn serialize(&self, output: &mut dyn Write) -> Result<()> {
        output.write_all(&self.to_le_bytes()).map_err(|err| {
            Error::SerializationError(format!("Failed to write serialize u128 to output: {err}"))
        })?;
        Ok(())
    }

    fn deserialize(input: &mut dyn ReadSeek) -> Result<Self> {
        let mut buffer = [0u8; 16];
        input.read_exact(&mut buffer).map_err(|_| {
            Error::InputTooSmall("Failed to read all bytes for u128 from the input".into())
        })?;
        Ok(Self::from_le_bytes(buffer))
    }

    fn size(&self) -> usize {
        16
    }
}

impl Serializable for i128 {
    fn serialize(&self, output: &mut dyn Write) -> Result<()> {
        output.write_all(&self.to_le_bytes()).map_err(|err| {
            Error::SerializationError(format!("Failed to write serialize i128 to output: {err}"))
        })?;
        Ok(())
    }

    fn deserialize(input: &mut dyn ReadSeek) -> Result<Self> {
        let mut buffer = [0u8; 16];
        input.read_exact(&mut buffer).map_err(|_| {
            Error::InputTooSmall("Failed to read all bytes for i128 from the input".into())
        })?;
        Ok(Self::from_le_bytes(buffer))
    }

    fn size(&self) -> usize {
        16
    }
}

#[cfg(test)]
mod test {
    use super::*;
    // Hacky hack to refere to "crate" by its name
    use crate as androscalpel_serializer;

    #[test]
    fn serialize_u8() {
        assert_eq!(42u8.serialize_to_vec().unwrap(), vec![42u8]);
    }

    #[test]
    fn deserialize_u8() {
        assert_eq!(u8::deserialize_from_slice(&[42u8]).unwrap(), 42u8);
    }

    #[test]
    fn size_u8() {
        assert_eq!(42u8.size(), 1);
    }

    #[test]
    fn serialize_u16() {
        assert_eq!(0x1234u16.serialize_to_vec().unwrap(), vec![0x34u8, 0x12u8]);
    }

    #[test]
    fn deserialize_u16() {
        assert_eq!(
            u16::deserialize_from_slice(&[0x34u8, 0x12u8]).unwrap(),
            0x1234u16
        );
    }

    #[test]
    fn size_u16() {
        assert_eq!(0x1234u16.size(), 2);
    }

    #[test]
    fn serialize_u32() {
        assert_eq!(
            0x12345678u32.serialize_to_vec().unwrap(),
            vec![0x78u8, 0x56u8, 0x34u8, 0x12u8]
        );
    }

    #[test]
    fn deserialize_u32() {
        assert_eq!(
            u32::deserialize_from_slice(&[0x78u8, 0x56u8, 0x34u8, 0x12u8]).unwrap(),
            0x12345678u32
        );
    }

    #[test]
    fn size_u32() {
        assert_eq!(0x12345678u32.size(), 4);
    }

    #[test]
    fn serialize_u64() {
        assert_eq!(
            0x123456789ABCDEF0u64.serialize_to_vec().unwrap(),
            vec![0xF0u8, 0xDEu8, 0xBCu8, 0x9Au8, 0x78u8, 0x56u8, 0x34u8, 0x12u8]
        );
    }

    #[test]
    fn deserialize_u64() {
        assert_eq!(
            u64::deserialize_from_slice(&[
                0xF0u8, 0xDEu8, 0xBCu8, 0x9Au8, 0x78u8, 0x56u8, 0x34u8, 0x12u8
            ])
            .unwrap(),
            0x123456789ABCDEF0u64
        );
    }

    #[test]
    fn size_u64() {
        assert_eq!(0x123456789ABCDEF0u64.size(), 8);
    }

    #[test]
    fn serialize_u128() {
        assert_eq!(
            0x123456789ABCDEF0123456789ABCDEF0u128
                .serialize_to_vec()
                .unwrap(),
            vec![
                0xF0u8, 0xDEu8, 0xBCu8, 0x9Au8, 0x78u8, 0x56u8, 0x34u8, 0x12u8, 0xF0u8, 0xDEu8,
                0xBCu8, 0x9Au8, 0x78u8, 0x56u8, 0x34u8, 0x12u8,
            ]
        );
    }

    #[test]
    fn deserialize_u128() {
        assert_eq!(
            u128::deserialize_from_slice(&[
                0xF0u8, 0xDEu8, 0xBCu8, 0x9Au8, 0x78u8, 0x56u8, 0x34u8, 0x12u8, 0xF0u8, 0xDEu8,
                0xBCu8, 0x9Au8, 0x78u8, 0x56u8, 0x34u8, 0x12u8,
            ])
            .unwrap(),
            0x123456789ABCDEF0123456789ABCDEF0u128
        );
    }

    #[test]
    fn size_u128() {
        assert_eq!(0x123456789ABCDEF0123456789ABCDEF0u128.size(), 16);
    }

    #[derive(Serializable, Debug, PartialEq, Eq)]
    struct NamedComposedTest {
        a: u8,
        b: u16,
        c: u32,
        d: u64,
        f: u128,
    }

    #[derive(Serializable, Debug, PartialEq, Eq)]
    struct UnamedComposedTest(u8, u16, u32, u64, u128);

    #[test]
    fn serialize_unnamed_derived() {
        let t = UnamedComposedTest(
            42u8,
            0x1234u16,
            0x12345678u32,
            0x123456789ABCDEF0u64,
            0x123456789ABCDEF0123456789ABCDEF0u128,
        );
        assert_eq!(
            t.serialize_to_vec().unwrap(),
            vec![
                0x2a, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34,
                0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78,
                0x56, 0x34, 0x12
            ]
        );
    }

    #[test]
    fn deserialize_named_derived() {
        let t = UnamedComposedTest(
            42u8,
            0x1234u16,
            0x12345678u32,
            0x123456789ABCDEF0u64,
            0x123456789ABCDEF0123456789ABCDEF0u128,
        );
        let serialized = vec![
            0x2a, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34,
            0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78,
            0x56, 0x34, 0x12,
        ];
        assert_eq!(
            UnamedComposedTest::deserialize_from_slice(&serialized).unwrap(),
            t
        );
    }

    #[test]
    fn size_unnamed_derived() {
        let t = UnamedComposedTest(
            42u8,
            0x1234u16,
            0x12345678u32,
            0x123456789ABCDEF0u64,
            0x123456789ABCDEF0123456789ABCDEF0u128,
        );
        assert_eq!(t.size(), 1 + 2 + 4 + 8 + 16);
    }

    #[derive(Serializable, Debug, PartialEq, Eq)]
    struct NamedArrayComposedTest {
        a: [u8; 1],
        b: [u16; 2],
        c: [u32; 3],
        d: [u64; 4],
        e: [u128; 5],
    }

    #[derive(Serializable, Debug, PartialEq, Eq)]
    struct UnamedArrayComposedTest([u8; 1], [u16; 2], [u32; 3], [u64; 4], [u128; 5]);

    #[test]
    fn serialize_array_unamed_derived() {
        let t = UnamedArrayComposedTest(
            [42u8],
            [0x1234u16, 0x1234u16],
            [0x12345678u32, 0x12345678u32, 0x12345678u32],
            [
                0x123456789ABCDEF0u64,
                0x123456789ABCDEF0u64,
                0x123456789ABCDEF0u64,
                0x123456789ABCDEF0u64,
            ],
            [
                0x123456789ABCDEF0123456789ABCDEF0u128,
                0x123456789ABCDEF0123456789ABCDEF0u128,
                0x123456789ABCDEF0123456789ABCDEF0u128,
                0x123456789ABCDEF0123456789ABCDEF0u128,
                0x123456789ABCDEF0123456789ABCDEF0u128,
            ],
        );
        assert_eq!(
            t.serialize_to_vec().unwrap(),
            vec![
                0x2a, 0x34, 0x12, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12, 0x78,
                0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc,
                0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0,
                0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34,
                0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78,
                0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc,
                0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0,
                0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34,
                0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78,
                0x56, 0x34, 0x12
            ]
        );
    }

    #[test]
    fn deserialize_array_unamed_derived() {
        let t = UnamedArrayComposedTest(
            [42u8],
            [0x1234u16, 0x1234u16],
            [0x12345678u32, 0x12345678u32, 0x12345678u32],
            [
                0x123456789ABCDEF0u64,
                0x123456789ABCDEF0u64,
                0x123456789ABCDEF0u64,
                0x123456789ABCDEF0u64,
            ],
            [
                0x123456789ABCDEF0123456789ABCDEF0u128,
                0x123456789ABCDEF0123456789ABCDEF0u128,
                0x123456789ABCDEF0123456789ABCDEF0u128,
                0x123456789ABCDEF0123456789ABCDEF0u128,
                0x123456789ABCDEF0123456789ABCDEF0u128,
            ],
        );
        let serialized = vec![
            0x2a, 0x34, 0x12, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12, 0x78,
            0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc,
            0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0,
            0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34,
            0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78,
            0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc,
            0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0,
            0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34,
            0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78,
            0x56, 0x34, 0x12,
        ];
        assert_eq!(
            UnamedArrayComposedTest::deserialize_from_slice(&serialized).unwrap(),
            t
        );
    }

    #[test]
    fn size_array_unamed_derived() {
        let t = UnamedArrayComposedTest(
            [42u8],
            [0x1234u16, 0x1234u16],
            [0x12345678u32, 0x12345678u32, 0x12345678u32],
            [
                0x123456789ABCDEF0u64,
                0x123456789ABCDEF0u64,
                0x123456789ABCDEF0u64,
                0x123456789ABCDEF0u64,
            ],
            [
                0x123456789ABCDEF0123456789ABCDEF0u128,
                0x123456789ABCDEF0123456789ABCDEF0u128,
                0x123456789ABCDEF0123456789ABCDEF0u128,
                0x123456789ABCDEF0123456789ABCDEF0u128,
                0x123456789ABCDEF0123456789ABCDEF0u128,
            ],
        );
        assert_eq!(t.size(), 1 + 2 * 2 + 4 * 3 + 8 * 4 + 16 * 5);
    }

    #[test]
    fn serialize_array_named_derived() {
        let t = NamedArrayComposedTest {
            a: [42u8],
            b: [0x1234u16, 0x1234u16],
            c: [0x12345678u32, 0x12345678u32, 0x12345678u32],
            d: [
                0x123456789ABCDEF0u64,
                0x123456789ABCDEF0u64,
                0x123456789ABCDEF0u64,
                0x123456789ABCDEF0u64,
            ],
            e: [
                0x123456789ABCDEF0123456789ABCDEF0u128,
                0x123456789ABCDEF0123456789ABCDEF0u128,
                0x123456789ABCDEF0123456789ABCDEF0u128,
                0x123456789ABCDEF0123456789ABCDEF0u128,
                0x123456789ABCDEF0123456789ABCDEF0u128,
            ],
        };
        assert_eq!(
            t.serialize_to_vec().unwrap(),
            vec![
                0x2a, 0x34, 0x12, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12, 0x78,
                0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc,
                0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0,
                0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34,
                0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78,
                0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc,
                0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0,
                0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34,
                0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78,
                0x56, 0x34, 0x12
            ],
        );
    }

    #[test]
    fn deserialize_array_named_derived() {
        let t = NamedArrayComposedTest {
            a: [42u8],
            b: [0x1234u16, 0x1234u16],
            c: [0x12345678u32, 0x12345678u32, 0x12345678u32],
            d: [
                0x123456789ABCDEF0u64,
                0x123456789ABCDEF0u64,
                0x123456789ABCDEF0u64,
                0x123456789ABCDEF0u64,
            ],
            e: [
                0x123456789ABCDEF0123456789ABCDEF0u128,
                0x123456789ABCDEF0123456789ABCDEF0u128,
                0x123456789ABCDEF0123456789ABCDEF0u128,
                0x123456789ABCDEF0123456789ABCDEF0u128,
                0x123456789ABCDEF0123456789ABCDEF0u128,
            ],
        };
        let serialized = vec![
            0x2a, 0x34, 0x12, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12, 0x78,
            0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc,
            0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0,
            0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34,
            0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78,
            0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc,
            0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0,
            0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34,
            0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a, 0x78,
            0x56, 0x34, 0x12,
        ];
        assert_eq!(
            NamedArrayComposedTest::deserialize_from_slice(&serialized).unwrap(),
            t
        );
    }

    #[test]
    fn size_array_named_derived() {
        let t = NamedArrayComposedTest {
            a: [42u8],
            b: [0x1234u16, 0x1234u16],
            c: [0x12345678u32, 0x12345678u32, 0x12345678u32],
            d: [
                0x123456789ABCDEF0u64,
                0x123456789ABCDEF0u64,
                0x123456789ABCDEF0u64,
                0x123456789ABCDEF0u64,
            ],
            e: [
                0x123456789ABCDEF0123456789ABCDEF0u128,
                0x123456789ABCDEF0123456789ABCDEF0u128,
                0x123456789ABCDEF0123456789ABCDEF0u128,
                0x123456789ABCDEF0123456789ABCDEF0u128,
                0x123456789ABCDEF0123456789ABCDEF0u128,
            ],
        };
        assert_eq!(t.size(), 1 + 2 * 2 + 4 * 3 + 8 * 4 + 16 * 5);
    }

    #[test]
    fn size_vec_serializable_until() {
        #[derive(Serializable, PartialEq, Eq)]
        struct UntilArray([u8; 3]);
        let v = vec![0u8, 1u8, 2u8, 3u8];
        assert_eq!(v.size(UntilArray([0, 0, 0])), 7);
        assert_eq!(v.size(0u8), 5);
    }

    #[test]
    fn serialize_vec_serializable_until() {
        #[derive(Serializable, PartialEq, Eq)]
        struct UntilArray([u8; 3]);
        let v = vec![0u8, 1u8, 2u8, 3u8];
        assert_eq!(
            v.serialize_to_vec(UntilArray([0, 0, 0])).unwrap(),
            vec![0u8, 1u8, 2u8, 3u8, 0u8, 0u8, 0u8]
        );
        assert_eq!(
            v.serialize_to_vec(0u8).unwrap(),
            vec![0u8, 1u8, 2u8, 3u8, 0u8]
        );
    }

    #[test]
    fn deserialize_vec_serializable_until() {
        #[derive(Serializable, PartialEq, Eq)]
        struct UntilArray([u8; 3]);
        let v1 = vec![0u8, 1u8, 2u8, 3u8];
        let serialized_1 = &[0u8, 1u8, 2u8, 3u8, 0u8, 0u8, 0u8];
        let serialized_2 = &[0u8, 1u8, 2u8, 3u8, 0u8];
        assert_eq!(
            v1,
            Vec::<u8>::deserialize_from_slice(serialized_1, UntilArray([0, 0, 0])).unwrap()
        );
        assert_eq!(
            Vec::<u8>::new(),
            Vec::<u8>::deserialize_from_slice(serialized_2, 0u8).unwrap()
        );
    }

    #[derive(Serializable, PartialEq, Eq, Debug)]
    struct UntilArray2([u8; 2]);
    #[derive(Serializable, Debug, PartialEq, Eq)]
    struct SerializableUntilNamed {
        pr: u16,
        #[until(u8, UntilArray2, UntilArray2([0u8, 0u8]))]
        v: Vec<u8>,
        ps: u32,
    }

    #[test]
    fn size_named_serializable_until() {
        let v = SerializableUntilNamed {
            pr: 0,
            v: vec![1, 2, 3],
            ps: 0,
        };
        assert_eq!(v.size(), 2 + 3 + 2 + 4);
    }

    #[test]
    fn serialize_named_serializable_until() {
        let v = SerializableUntilNamed {
            pr: 0,
            v: vec![1, 2, 3],
            ps: 0x80000000,
        };
        assert_eq!(
            v.serialize_to_vec().unwrap(),
            vec![0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0x80],
        );
    }

    #[test]
    fn deserialize_named_serializable_until() {
        let v = SerializableUntilNamed {
            pr: 0,
            v: vec![1, 2, 3],
            ps: 0x80000000,
        };
        let s = &[0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0x80];
        assert_eq!(
            v,
            SerializableUntilNamed::deserialize_from_slice(s).unwrap()
        );
    }

    #[derive(Serializable, PartialEq, Eq, Debug)]
    #[prefix_type(u8)]
    enum TestEnum {
        #[prefix(0)]
        Zero,
        #[prefix(1)]
        One(u32),
        #[prefix(2)]
        Two { a: u16, b: u32 },
    }

    #[test]
    fn size_enum() {
        assert_eq!(TestEnum::Zero.size(), 1);
        assert_eq!(TestEnum::One(42).size(), 5);
        assert_eq!(TestEnum::Two { a: 1, b: 2 }.size(), 7);
    }

    #[test]
    fn serialize_enum() {
        assert_eq!(TestEnum::Zero.serialize_to_vec().unwrap(), vec![0u8]);
        assert_eq!(
            TestEnum::One(42).serialize_to_vec().unwrap(),
            vec![1u8, 42u8, 0u8, 0u8, 0u8]
        );
        assert_eq!(
            TestEnum::Two { a: 1, b: 2 }.serialize_to_vec().unwrap(),
            vec![2u8, 1u8, 0u8, 2u8, 0u8, 0u8, 0u8]
        );
    }

    #[test]
    fn deserialize_enum() {
        assert_eq!(
            TestEnum::deserialize_from_slice(&[0u8]).unwrap(),
            TestEnum::Zero
        );
        assert_eq!(
            TestEnum::deserialize_from_slice(&[1u8, 42u8, 0u8, 0u8, 0u8]).unwrap(),
            TestEnum::One(42)
        );
        assert_eq!(
            TestEnum::deserialize_from_slice(&[2u8, 1u8, 0u8, 2u8, 0u8, 0u8, 0u8]).unwrap(),
            TestEnum::Two { a: 1, b: 2 }
        );
        assert!(TestEnum::deserialize_from_slice(&[255u8]).is_err());
    }

    #[derive(Serializable, PartialEq, Debug)]
    struct TestPrefixSuffix {
        #[prefix([0x42])]
        #[suffix([0x66, 0x66])]
        a: u32,
    }

    #[test]
    fn deserialize_prefix_suffix() {
        assert_eq!(
            TestPrefixSuffix::deserialize_from_slice(&[0x42, 3, 2, 1, 0, 0x66, 0x66]).unwrap(),
            TestPrefixSuffix { a: 0x00010203 }
        );
    }

    #[test]
    fn serialize_prefix_suffix() {
        assert_eq!(
            TestPrefixSuffix { a: 0x00010203 }
                .serialize_to_vec()
                .unwrap(),
            vec![0x42, 3, 2, 1, 0, 0x66, 0x66]
        );
    }

    #[derive(Serializable, PartialEq, Eq, Debug)]
    #[prefix_type(u8)]
    enum TestEnumUnnamedDef {
        #[prefix(0)]
        Zero,
        #[prefix(1)]
        One(u32),
        #[prefix(2)]
        Two { a: u16, b: u32 },
        #[default_variant]
        Dft(u8, u32),
    }

    #[test]
    fn size_enum_unnamed_def() {
        assert_eq!(TestEnumUnnamedDef::Zero.size(), 1);
        assert_eq!(TestEnumUnnamedDef::One(42).size(), 5);
        assert_eq!(TestEnumUnnamedDef::Two { a: 1, b: 2 }.size(), 7);
        assert_eq!(TestEnumUnnamedDef::Dft(42, 0x01234567).size(), 5);
    }

    #[test]
    fn serialize_enum_unnamed_def() {
        assert_eq!(
            TestEnumUnnamedDef::Zero.serialize_to_vec().unwrap(),
            vec![0u8]
        );
        assert_eq!(
            TestEnumUnnamedDef::One(42).serialize_to_vec().unwrap(),
            vec![1u8, 42u8, 0u8, 0u8, 0u8]
        );
        assert_eq!(
            TestEnumUnnamedDef::Two { a: 1, b: 2 }
                .serialize_to_vec()
                .unwrap(),
            vec![2u8, 1u8, 0u8, 2u8, 0u8, 0u8, 0u8]
        );
        assert_eq!(
            TestEnumUnnamedDef::Dft(42, 0x01234567)
                .serialize_to_vec()
                .unwrap(),
            vec![42u8, 0x67, 0x45, 0x23, 0x01u8],
        );
    }

    #[test]
    fn deserialize_enum_unnamed_def() {
        assert_eq!(
            TestEnumUnnamedDef::deserialize_from_slice(&[0u8]).unwrap(),
            TestEnumUnnamedDef::Zero
        );
        assert_eq!(
            TestEnumUnnamedDef::deserialize_from_slice(&[1u8, 42u8, 0u8, 0u8, 0u8]).unwrap(),
            TestEnumUnnamedDef::One(42)
        );
        assert_eq!(
            TestEnumUnnamedDef::deserialize_from_slice(&[2u8, 1u8, 0u8, 2u8, 0u8, 0u8, 0u8])
                .unwrap(),
            TestEnumUnnamedDef::Two { a: 1, b: 2 }
        );
        assert_eq!(
            TestEnumUnnamedDef::deserialize_from_slice(&[42u8, 0x67, 0x45, 0x23u8, 0x01u8])
                .unwrap(),
            TestEnumUnnamedDef::Dft(42, 0x01234567)
        );
    }

    #[derive(Serializable, PartialEq, Eq, Debug)]
    #[prefix_type(u8)]
    enum TestEnumNamedDef {
        #[default_variant]
        Dft { prefix: u8 },
    }
    // Must panic: TODO: test that, somehow
    //    #[derive(Serializable, PartialEq, Eq, Debug)]
    //    #[prefix_type(u8)]
    //    enum TestInvalidEnumNamedDef {
    //        #[default_variant]
    //        Dft { plop: u32, prefix: u8 },
    //    }
}
