#![feature(decl_macro, ip_from, maybe_uninit_array_assume_init)]
#![no_std]

#[cfg(not(feature = "rustc-dep-of-std"))]
extern crate alloc;
#[cfg(feature = "rustc-dep-of-std")]
extern crate rustc_std_alloc as alloc;

pub mod des;
pub mod ser;

mod impls;

#[cfg(test)]
pub mod test;

pub mod wire;

pub use des::Deserialize;
pub use ser::Serialize;

#[macro_export]
macro_rules! impl_enum1_serde {
    (
        $name:ident $(<$lifetime:lifetime>)? : [
            $(
                $variant:ident => $discriminant:literal
            ),* $(,)?
        ]
    ) => {
        impl $(<$lifetime>)? $crate::Serialize for $name $(<$lifetime>)? {
            fn serialize<S: $crate::ser::Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
                match self {
                    $(
                        Self::$variant(value) => {
                            serializer.write_enum_variant($discriminant)?;
                            $crate::Serialize::serialize(value, serializer)
                        }
                    )*
                }
            }
        }

        impl<'de> $crate::Deserialize<'de> for $name $(<$lifetime>)? {
            fn deserialize<D: $crate::des::Deserializer<'de>>(deserializer: &mut D) -> Result<Self, D::Error> {
                let variant = deserializer.read_enum_variant()?;
                match variant {
                    $(
                        $discriminant => $crate::Deserialize::deserialize(deserializer).map(Self::$variant),
                    )*
                    _ => Err(<D::Error as $crate::des::DeserializeError>::INVALID_ENUM_VARIANT)
                }
            }
        }
    };
}

#[macro_export]
macro_rules! impl_struct_serde {
    (
        $name:ident $(<$lifetime:lifetime>)? : [$($field:ident),* $(,)?]
    ) => {
        impl $(<$lifetime>)? $crate::Serialize for $name $(<$lifetime>)? {
            fn serialize<S: $crate::ser::Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
                $(
                    $crate::Serialize::serialize(&self.$field, serializer)?;
                )*
                Ok(())
            }
        }

        impl<'de> $crate::Deserialize<'de> for $name $(<$lifetime>)? {
            fn deserialize<D: $crate::des::Deserializer<'de>>(deserializer: &mut D) -> Result<Self, D::Error> {
                $(
                    let $field = $crate::Deserialize::deserialize(deserializer)?;
                )*
                Ok(Self {$($field),*})
            }
        }
    }
}

#[macro_export]
macro_rules! impl_newtype_serde {
    ($name:ident) => {
        impl $crate::Serialize for $name {
            fn serialize<S: $crate::ser::Serializer>(
                &self,
                serializer: &mut S,
            ) -> Result<(), S::Error> {
                $crate::Serialize::serialize(&self.0, serializer)
            }
        }

        impl<'de> $crate::Deserialize<'de> for $name {
            fn deserialize<D: $crate::des::Deserializer<'de>>(
                deserializer: &mut D,
            ) -> Result<Self, D::Error> {
                $crate::Deserialize::deserialize(deserializer).map(Self)
            }
        }
    };
}
