use crate::{imp::implements, Deserializer, NonTrivialObject, Serializer};
use std::io::Result;
pub trait PlainOldData: NonTrivialObject {}
mod private {
    pub trait Sealed {}
}
pub trait Object: private::Sealed {
    fn serialize_self(&self, s: &mut Serializer);
    fn serialize_slice(elements: &[Self], s: &mut Serializer)
    where
        Self: Sized;
    unsafe fn deserialize_self(d: &mut Deserializer) -> Result<Self>
    where
        Self: Sized;
    #[doc(hidden)]
    unsafe fn deserialize_on_heap(d: &mut Deserializer) -> Result<*mut ()>
    where
        Self: Sized;
    #[doc(hidden)]
    #[cfg(feature = "nightly")]
    unsafe fn deserialize_on_heap_ptr(self: *const Self, d: &mut Deserializer) -> Result<*mut ()>;
    #[doc(hidden)]
    #[cfg(not(feature = "nightly"))]
    fn deserialize_on_heap_get(&self) -> unsafe fn(&mut Deserializer) -> Result<*mut ()>;
}
impl<T: NonTrivialObject> private::Sealed for T {}
impl<T: NonTrivialObject> Object for T {
    fn serialize_self(&self, s: &mut Serializer) {
        if implements!(T: PlainOldData) {
            s.write(unsafe {
                std::slice::from_raw_parts(self as *const T as *const u8, std::mem::size_of::<T>())
            });
        } else {
            self.serialize_self_non_trivial(s);
        }
    }
    fn serialize_slice(elements: &[Self], s: &mut Serializer)
    where
        Self: Sized,
    {
        if implements!(T: PlainOldData) {
            s.write(unsafe {
                std::slice::from_raw_parts(
                    elements.as_ptr() as *const u8,
                    std::mem::size_of_val(elements),
                )
            });
        } else {
            for element in elements {
                element.serialize_self_non_trivial(s)
            }
        }
    }
    unsafe fn deserialize_self(d: &mut Deserializer) -> Result<Self>
    where
        Self: Sized,
    {
        if implements!(T: PlainOldData) {
            let mut val = std::mem::MaybeUninit::<T>::uninit();
            d.read(std::slice::from_raw_parts_mut(
                val.as_mut_ptr() as *mut u8,
                std::mem::size_of::<T>(),
            ));
            Ok(val.assume_init())
        } else {
            T::deserialize_self_non_trivial(d)
        }
    }
    unsafe fn deserialize_on_heap(d: &mut Deserializer) -> Result<*mut ()>
    where
        Self: Sized,
    {
        Ok(Box::into_raw(Box::new(Self::deserialize_self(d)?)) as *mut ())
    }
    #[cfg(feature = "nightly")]
    unsafe fn deserialize_on_heap_ptr(self: *const T, d: &mut Deserializer) -> Result<*mut ()> {
        Self::deserialize_on_heap(d)
    }
    #[cfg(not(feature = "nightly"))]
    fn deserialize_on_heap_get(&self) -> unsafe fn(&mut Deserializer) -> Result<*mut ()> {
        Self::deserialize_on_heap
    }
}