use self::ErrorImpl::ShortCircuit;
use crate::error::Error;
use crate::sealed;
use alloc::boxed::Box;
use alloc::string::{String, ToString};
use core::fmt::{self, Debug, Display};
use serde::ser::{
    SerializeMap as _, SerializeSeq as _, SerializeStruct as _, SerializeStructVariant as _,
    SerializeTuple as _, SerializeTupleStruct as _, SerializeTupleVariant as _,
};

// TRAITS //////////////////////////////////////////////////////////////////////

/// An object-safe equivalent of Serde's `Serialize` trait.
///
/// Any implementation of Serde's `Serialize` converts seamlessly to a
/// `&dyn erased_serde::Serialize` or `Box<dyn erased_serde::Serialize>` trait
/// object.
///
/// ```rust
/// use erased_serde::{Serialize, Serializer};
/// use std::collections::BTreeMap as Map;
/// use std::io;
///
/// fn main() {
///     // Construct some serializers.
///     let json = &mut serde_json::Serializer::new(io::stdout());
///     let cbor = &mut serde_cbor::Serializer::new(serde_cbor::ser::IoWrite::new(io::stdout()));
///
///     // The values in this map are boxed trait objects. Ordinarily this would not
///     // be possible with serde::Serializer because of object safety, but type
///     // erasure makes it possible with erased_serde::Serializer.
///     let mut formats: Map<&str, Box<dyn Serializer>> = Map::new();
///     formats.insert("json", Box::new(<dyn Serializer>::erase(json)));
///     formats.insert("cbor", Box::new(<dyn Serializer>::erase(cbor)));
///
///     // These are boxed trait objects as well. Same thing here - type erasure
///     // makes this possible.
///     let mut values: Map<&str, Box<dyn Serialize>> = Map::new();
///     values.insert("vec", Box::new(vec!["a", "b"]));
///     values.insert("int", Box::new(65536));
///
///     // Pick a Serializer out of the formats map.
///     let format = formats.get_mut("json").unwrap();
///
///     // Pick a Serialize out of the values map.
///     let value = values.get("vec").unwrap();
///
///     // This line prints `["a","b"]` to stdout.
///     value.erased_serialize(format).unwrap();
/// }
/// ```
///
/// This trait is sealed and can only be implemented via a `serde::Serialize`
/// impl.
#[cfg_attr(
    not(no_diagnostic_namespace),
    diagnostic::on_unimplemented(
        message = "the trait bound `{Self}: serde::Serialize` is not satisfied",
        label = "the trait `serde::Serialize` is not implemented for `{Self}`, so it does not implement `erased_serde::Serialize`",
    )
)]
pub trait Serialize: sealed::serialize::Sealed {
    fn erased_serialize(&self, serializer: &mut dyn Serializer) -> Result<(), Error>;

    #[doc(hidden)]
    fn do_erased_serialize(&self, serializer: &mut dyn Serializer) -> Result<(), ErrorImpl>;
}

/// An object-safe equivalent of Serde's `Serializer` trait.
///
/// Any implementation of Serde's `Serializer` can be converted to a
/// `&dyn erased_serde::Serializer` or `Box<dyn erased_serde::Serializer>` trait
/// object using `erased_serde::Serializer::erase`.
///
/// ```rust
/// use erased_serde::{Serialize, Serializer};
/// use std::collections::BTreeMap as Map;
/// use std::io;
///
/// fn main() {
///     // Construct some serializers.
///     let json = &mut serde_json::Serializer::new(io::stdout());
///     let cbor = &mut serde_cbor::Serializer::new(serde_cbor::ser::IoWrite::new(io::stdout()));
///
///     // The values in this map are boxed trait objects. Ordinarily this would not
///     // be possible with serde::Serializer because of object safety, but type
///     // erasure makes it possible with erased_serde::Serializer.
///     let mut formats: Map<&str, Box<dyn Serializer>> = Map::new();
///     formats.insert("json", Box::new(<dyn Serializer>::erase(json)));
///     formats.insert("cbor", Box::new(<dyn Serializer>::erase(cbor)));
///
///     // These are boxed trait objects as well. Same thing here - type erasure
///     // makes this possible.
///     let mut values: Map<&str, Box<dyn Serialize>> = Map::new();
///     values.insert("vec", Box::new(vec!["a", "b"]));
///     values.insert("int", Box::new(65536));
///
///     // Pick a Serializer out of the formats map.
///     let format = formats.get_mut("json").unwrap();
///
///     // Pick a Serialize out of the values map.
///     let value = values.get("vec").unwrap();
///
///     // This line prints `["a","b"]` to stdout.
///     value.erased_serialize(format).unwrap();
/// }
/// ```
///
/// This trait is sealed and can only be implemented via a `serde::Serializer`
/// impl.
pub trait Serializer: sealed::serializer::Sealed {
    fn erased_serialize_bool(&mut self, v: bool);
    fn erased_serialize_i8(&mut self, v: i8);
    fn erased_serialize_i16(&mut self, v: i16);
    fn erased_serialize_i32(&mut self, v: i32);
    fn erased_serialize_i64(&mut self, v: i64);
    fn erased_serialize_i128(&mut self, v: i128);
    fn erased_serialize_u8(&mut self, v: u8);
    fn erased_serialize_u16(&mut self, v: u16);
    fn erased_serialize_u32(&mut self, v: u32);
    fn erased_serialize_u64(&mut self, v: u64);
    fn erased_serialize_u128(&mut self, v: u128);
    fn erased_serialize_f32(&mut self, v: f32);
    fn erased_serialize_f64(&mut self, v: f64);
    fn erased_serialize_char(&mut self, v: char);
    fn erased_serialize_str(&mut self, v: &str);
    fn erased_serialize_bytes(&mut self, v: &[u8]);
    fn erased_serialize_none(&mut self);
    fn erased_serialize_some(&mut self, value: &dyn Serialize);
    fn erased_serialize_unit(&mut self);
    fn erased_serialize_unit_struct(&mut self, name: &'static str);
    fn erased_serialize_unit_variant(
        &mut self,
        name: &'static str,
        variant_index: u32,
        variant: &'static str,
    );
    fn erased_serialize_newtype_struct(&mut self, name: &'static str, value: &dyn Serialize);
    fn erased_serialize_newtype_variant(
        &mut self,
        name: &'static str,
        variant_index: u32,
        variant: &'static str,
        value: &dyn Serialize,
    );
    fn erased_serialize_seq(
        &mut self,
        len: Option<usize>,
    ) -> Result<&mut dyn SerializeSeq, ErrorImpl>;
    fn erased_serialize_tuple(&mut self, len: usize) -> Result<&mut dyn SerializeTuple, ErrorImpl>;
    fn erased_serialize_tuple_struct(
        &mut self,
        name: &'static str,
        len: usize,
    ) -> Result<&mut dyn SerializeTupleStruct, ErrorImpl>;
    fn erased_serialize_tuple_variant(
        &mut self,
        name: &'static str,
        variant_index: u32,
        variant: &'static str,
        len: usize,
    ) -> Result<&mut dyn SerializeTupleVariant, ErrorImpl>;
    fn erased_serialize_map(
        &mut self,
        len: Option<usize>,
    ) -> Result<&mut dyn SerializeMap, ErrorImpl>;
    fn erased_serialize_struct(
        &mut self,
        name: &'static str,
        len: usize,
    ) -> Result<&mut dyn SerializeStruct, ErrorImpl>;
    fn erased_serialize_struct_variant(
        &mut self,
        name: &'static str,
        variant_index: u32,
        variant: &'static str,
        len: usize,
    ) -> Result<&mut dyn SerializeStructVariant, ErrorImpl>;
    fn erased_is_human_readable(&self) -> bool;
    #[doc(hidden)]
    fn erased_display_error(&self) -> &dyn Display;
}

impl dyn Serializer {
    /// Convert any Serde `Serializer` to a trait object.
    ///
    /// ```rust
    /// use erased_serde::{Serialize, Serializer};
    /// use std::collections::BTreeMap as Map;
    /// use std::io;
    ///
    /// fn main() {
    ///     // Construct some serializers.
    ///     let json = &mut serde_json::Serializer::new(io::stdout());
    ///     let cbor = &mut serde_cbor::Serializer::new(serde_cbor::ser::IoWrite::new(io::stdout()));
    ///
    ///     // The values in this map are boxed trait objects. Ordinarily this would not
    ///     // be possible with serde::Serializer because of object safety, but type
    ///     // erasure makes it possible with erased_serde::Serializer.
    ///     let mut formats: Map<&str, Box<dyn Serializer>> = Map::new();
    ///     formats.insert("json", Box::new(<dyn Serializer>::erase(json)));
    ///     formats.insert("cbor", Box::new(<dyn Serializer>::erase(cbor)));
    ///
    ///     // These are boxed trait objects as well. Same thing here - type erasure
    ///     // makes this possible.
    ///     let mut values: Map<&str, Box<dyn Serialize>> = Map::new();
    ///     values.insert("vec", Box::new(vec!["a", "b"]));
    ///     values.insert("int", Box::new(65536));
    ///
    ///     // Pick a Serializer out of the formats map.
    ///     let format = formats.get_mut("json").unwrap();
    ///
    ///     // Pick a Serialize out of the values map.
    ///     let value = values.get("vec").unwrap();
    ///
    ///     // This line prints `["a","b"]` to stdout.
    ///     value.erased_serialize(format).unwrap();
    /// }
    /// ```
    pub fn erase<S>(serializer: S) -> impl Serializer
    where
        S: serde::Serializer,
    {
        erase::Serializer::new(serializer)
    }
}

// IMPL ERASED SERDE FOR SERDE /////////////////////////////////////////////////

impl<T> Serialize for T
where
    T: ?Sized + serde::Serialize,
{
    fn erased_serialize(&self, serializer: &mut dyn Serializer) -> Result<(), Error> {
        match self.do_erased_serialize(serializer) {
            Ok(()) => Ok(()),
            Err(ShortCircuit) => Err(serde::ser::Error::custom(serializer.erased_display_error())),
            Err(ErrorImpl::Custom(msg)) => Err(serde::ser::Error::custom(msg)),
        }
    }

    fn do_erased_serialize(&self, serializer: &mut dyn Serializer) -> Result<(), ErrorImpl> {
        self.serialize(MakeSerializer(serializer))
    }
}

impl<T> sealed::serialize::Sealed for T where T: ?Sized + serde::Serialize {}

mod erase {
    use core::mem;

    pub enum Serializer<S>
    where
        S: serde::Serializer,
    {
        Ready(S),
        Seq(S::SerializeSeq),
        Tuple(S::SerializeTuple),
        TupleStruct(S::SerializeTupleStruct),
        TupleVariant(S::SerializeTupleVariant),
        Map(S::SerializeMap),
        Struct(S::SerializeStruct),
        StructVariant(S::SerializeStructVariant),
        Error(S::Error),
        Complete(S::Ok),
        Unusable,
    }

    impl<S> Serializer<S>
    where
        S: serde::Serializer,
    {
        pub(crate) fn new(serializer: S) -> Self {
            Serializer::Ready(serializer)
        }

        pub(crate) fn take(&mut self) -> Self {
            mem::replace(self, Serializer::Unusable)
        }

        pub(crate) fn take_serializer(&mut self) -> S {
            match self.take() {
                Serializer::Ready(serializer) => serializer,
                _ => unreachable!(),
            }
        }
    }
}

impl<T> Serializer for erase::Serializer<T>
where
    T: serde::Serializer,
{
    fn erased_serialize_bool(&mut self, v: bool) {
        *self = match self.take_serializer().serialize_bool(v) {
            Ok(ok) => erase::Serializer::Complete(ok),
            Err(err) => erase::Serializer::Error(err),
        };
    }

    fn erased_serialize_i8(&mut self, v: i8) {
        *self = match self.take_serializer().serialize_i8(v) {
            Ok(ok) => erase::Serializer::Complete(ok),
            Err(err) => erase::Serializer::Error(err),
        };
    }

    fn erased_serialize_i16(&mut self, v: i16) {
        *self = match self.take_serializer().serialize_i16(v) {
            Ok(ok) => erase::Serializer::Complete(ok),
            Err(err) => erase::Serializer::Error(err),
        };
    }

    fn erased_serialize_i32(&mut self, v: i32) {
        *self = match self.take_serializer().serialize_i32(v) {
            Ok(ok) => erase::Serializer::Complete(ok),
            Err(err) => erase::Serializer::Error(err),
        };
    }

    fn erased_serialize_i64(&mut self, v: i64) {
        *self = match self.take_serializer().serialize_i64(v) {
            Ok(ok) => erase::Serializer::Complete(ok),
            Err(err) => erase::Serializer::Error(err),
        };
    }

    fn erased_serialize_i128(&mut self, v: i128) {
        *self = match self.take_serializer().serialize_i128(v) {
            Ok(ok) => erase::Serializer::Complete(ok),
            Err(err) => erase::Serializer::Error(err),
        };
    }

    fn erased_serialize_u8(&mut self, v: u8) {
        *self = match self.take_serializer().serialize_u8(v) {
            Ok(ok) => erase::Serializer::Complete(ok),
            Err(err) => erase::Serializer::Error(err),
        };
    }

    fn erased_serialize_u16(&mut self, v: u16) {
        *self = match self.take_serializer().serialize_u16(v) {
            Ok(ok) => erase::Serializer::Complete(ok),
            Err(err) => erase::Serializer::Error(err),
        };
    }

    fn erased_serialize_u32(&mut self, v: u32) {
        *self = match self.take_serializer().serialize_u32(v) {
            Ok(ok) => erase::Serializer::Complete(ok),
            Err(err) => erase::Serializer::Error(err),
        };
    }

    fn erased_serialize_u64(&mut self, v: u64) {
        *self = match self.take_serializer().serialize_u64(v) {
            Ok(ok) => erase::Serializer::Complete(ok),
            Err(err) => erase::Serializer::Error(err),
        };
    }

    fn erased_serialize_u128(&mut self, v: u128) {
        *self = match self.take_serializer().serialize_u128(v) {
            Ok(ok) => erase::Serializer::Complete(ok),
            Err(err) => erase::Serializer::Error(err),
        };
    }

    fn erased_serialize_f32(&mut self, v: f32) {
        *self = match self.take_serializer().serialize_f32(v) {
            Ok(ok) => erase::Serializer::Complete(ok),
            Err(err) => erase::Serializer::Error(err),
        };
    }

    fn erased_serialize_f64(&mut self, v: f64) {
        *self = match self.take_serializer().serialize_f64(v) {
            Ok(ok) => erase::Serializer::Complete(ok),
            Err(err) => erase::Serializer::Error(err),
        };
    }

    fn erased_serialize_char(&mut self, v: char) {
        *self = match self.take_serializer().serialize_char(v) {
            Ok(ok) => erase::Serializer::Complete(ok),
            Err(err) => erase::Serializer::Error(err),
        };
    }

    fn erased_serialize_str(&mut self, v: &str) {
        *self = match self.take_serializer().serialize_str(v) {
            Ok(ok) => erase::Serializer::Complete(ok),
            Err(err) => erase::Serializer::Error(err),
        };
    }

    fn erased_serialize_bytes(&mut self, v: &[u8]) {
        *self = match self.take_serializer().serialize_bytes(v) {
            Ok(ok) => erase::Serializer::Complete(ok),
            Err(err) => erase::Serializer::Error(err),
        };
    }

    fn erased_serialize_none(&mut self) {
        *self = match self.take_serializer().serialize_none() {
            Ok(ok) => erase::Serializer::Complete(ok),
            Err(err) => erase::Serializer::Error(err),
        };
    }

    fn erased_serialize_some(&mut self, value: &dyn Serialize) {
        *self = match self.take_serializer().serialize_some(value) {
            Ok(ok) => erase::Serializer::Complete(ok),
            Err(err) => erase::Serializer::Error(err),
        };
    }

    fn erased_serialize_unit(&mut self) {
        *self = match self.take_serializer().serialize_unit() {
            Ok(ok) => erase::Serializer::Complete(ok),
            Err(err) => erase::Serializer::Error(err),
        };
    }

    fn erased_serialize_unit_struct(&mut self, name: &'static str) {
        *self = match self.take_serializer().serialize_unit_struct(name) {
            Ok(ok) => erase::Serializer::Complete(ok),
            Err(err) => erase::Serializer::Error(err),
        };
    }

    fn erased_serialize_unit_variant(
        &mut self,
        name: &'static str,
        variant_index: u32,
        variant: &'static str,
    ) {
        *self = match self
            .take_serializer()
            .serialize_unit_variant(name, variant_index, variant)
        {
            Ok(ok) => erase::Serializer::Complete(ok),
            Err(err) => erase::Serializer::Error(err),
        };
    }

    fn erased_serialize_newtype_struct(&mut self, name: &'static str, value: &dyn Serialize) {
        *self = match self.take_serializer().serialize_newtype_struct(name, value) {
            Ok(ok) => erase::Serializer::Complete(ok),
            Err(err) => erase::Serializer::Error(err),
        };
    }

    fn erased_serialize_newtype_variant(
        &mut self,
        name: &'static str,
        variant_index: u32,
        variant: &'static str,
        value: &dyn Serialize,
    ) {
        *self = match self.take_serializer().serialize_newtype_variant(
            name,
            variant_index,
            variant,
            value,
        ) {
            Ok(ok) => erase::Serializer::Complete(ok),
            Err(err) => erase::Serializer::Error(err),
        };
    }

    fn erased_serialize_seq(
        &mut self,
        len: Option<usize>,
    ) -> Result<&mut dyn SerializeSeq, ErrorImpl> {
        match self.take_serializer().serialize_seq(len) {
            Ok(ok) => {
                *self = erase::Serializer::Seq(ok);
                Ok(self)
            }
            Err(err) => {
                *self = erase::Serializer::Error(err);
                Err(ShortCircuit)
            }
        }
    }

    fn erased_serialize_tuple(&mut self, len: usize) -> Result<&mut dyn SerializeTuple, ErrorImpl> {
        match self.take_serializer().serialize_tuple(len) {
            Ok(ok) => {
                *self = erase::Serializer::Tuple(ok);
                Ok(self)
            }
            Err(err) => {
                *self = erase::Serializer::Error(err);
                Err(ShortCircuit)
            }
        }
    }

    fn erased_serialize_tuple_struct(
        &mut self,
        name: &'static str,
        len: usize,
    ) -> Result<&mut dyn SerializeTupleStruct, ErrorImpl> {
        match self.take_serializer().serialize_tuple_struct(name, len) {
            Ok(ok) => {
                *self = erase::Serializer::TupleStruct(ok);
                Ok(self)
            }
            Err(err) => {
                *self = erase::Serializer::Error(err);
                Err(ShortCircuit)
            }
        }
    }

    fn erased_serialize_tuple_variant(
        &mut self,
        name: &'static str,
        variant_index: u32,
        variant: &'static str,
        len: usize,
    ) -> Result<&mut dyn SerializeTupleVariant, ErrorImpl> {
        match self
            .take_serializer()
            .serialize_tuple_variant(name, variant_index, variant, len)
        {
            Ok(ok) => {
                *self = erase::Serializer::TupleVariant(ok);
                Ok(self)
            }
            Err(err) => {
                *self = erase::Serializer::Error(err);
                Err(ShortCircuit)
            }
        }
    }

    fn erased_serialize_map(
        &mut self,
        len: Option<usize>,
    ) -> Result<&mut dyn SerializeMap, ErrorImpl> {
        match self.take_serializer().serialize_map(len) {
            Ok(ok) => {
                *self = erase::Serializer::Map(ok);
                Ok(self)
            }
            Err(err) => {
                *self = erase::Serializer::Error(err);
                Err(ShortCircuit)
            }
        }
    }

    fn erased_serialize_struct(
        &mut self,
        name: &'static str,
        len: usize,
    ) -> Result<&mut dyn SerializeStruct, ErrorImpl> {
        match self.take_serializer().serialize_struct(name, len) {
            Ok(ok) => {
                *self = erase::Serializer::Struct(ok);
                Ok(self)
            }
            Err(err) => {
                *self = erase::Serializer::Error(err);
                Err(ShortCircuit)
            }
        }
    }

    fn erased_serialize_struct_variant(
        &mut self,
        name: &'static str,
        variant_index: u32,
        variant: &'static str,
        len: usize,
    ) -> Result<&mut dyn SerializeStructVariant, ErrorImpl> {
        match self
            .take_serializer()
            .serialize_struct_variant(name, variant_index, variant, len)
        {
            Ok(ok) => {
                *self = erase::Serializer::StructVariant(ok);
                Ok(self)
            }
            Err(err) => {
                *self = erase::Serializer::Error(err);
                Err(ShortCircuit)
            }
        }
    }

    fn erased_is_human_readable(&self) -> bool {
        match self {
            erase::Serializer::Ready(serializer) => serializer.is_human_readable(),
            _ => unreachable!(),
        }
    }

    fn erased_display_error(&self) -> &dyn Display {
        match self {
            erase::Serializer::Error(err) => err,
            _ => unreachable!(),
        }
    }
}

impl<T> sealed::serializer::Sealed for erase::Serializer<T> where T: serde::Serializer {}

pub enum ErrorImpl {
    ShortCircuit,
    Custom(Box<String>),
}

impl Display for ErrorImpl {
    fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
        unimplemented!()
    }
}

impl Debug for ErrorImpl {
    fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
        unimplemented!()
    }
}

impl serde::ser::StdError for ErrorImpl {}

impl serde::ser::Error for ErrorImpl {
    fn custom<T: Display>(msg: T) -> Self {
        ErrorImpl::Custom(Box::new(msg.to_string()))
    }
}

// IMPL SERDE FOR ERASED SERDE /////////////////////////////////////////////////

/// Serialize the given type-erased serializable value.
///
/// This can be used to implement `serde::Serialize` for trait objects that have
/// `erased_serde::Serialize` as a supertrait.
///
/// ```
/// trait Event: erased_serde::Serialize {
///     /* ... */
/// }
///
/// impl<'a> serde::Serialize for dyn Event + 'a {
///     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
///     where
///         S: serde::Serializer,
///     {
///         erased_serde::serialize(self, serializer)
///     }
/// }
/// ```
///
/// Since this is reasonably common, the `serialize_trait_object!` macro
/// generates such a Serialize impl.
///
/// ```
/// use erased_serde::serialize_trait_object;
/// #
/// # trait Event: erased_serde::Serialize {}
///
/// serialize_trait_object!(Event);
/// ```
pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
where
    T: ?Sized + Serialize,
    S: serde::Serializer,
{
    let mut erased = erase::Serializer::new(serializer);
    match value.do_erased_serialize(&mut erased) {
        Ok(()) | Err(ShortCircuit) => {}
        Err(ErrorImpl::Custom(msg)) => return Err(serde::ser::Error::custom(msg)),
    }
    match erased {
        erase::Serializer::Complete(ok) => Ok(ok),
        erase::Serializer::Error(err) => Err(err),
        _ => unreachable!(),
    }
}

serialize_trait_object!(Serialize);

struct MakeSerializer<TraitObject>(TraitObject);

impl<'a> serde::Serializer for MakeSerializer<&'a mut (dyn Serializer + '_)> {
    type Ok = ();
    type Error = ErrorImpl;
    type SerializeSeq = MakeSerializer<&'a mut dyn SerializeSeq>;
    type SerializeTuple = MakeSerializer<&'a mut dyn SerializeTuple>;
    type SerializeTupleStruct = MakeSerializer<&'a mut dyn SerializeTupleStruct>;
    type SerializeTupleVariant = MakeSerializer<&'a mut dyn SerializeTupleVariant>;
    type SerializeMap = MakeSerializer<&'a mut dyn SerializeMap>;
    type SerializeStruct = MakeSerializer<&'a mut dyn SerializeStruct>;
    type SerializeStructVariant = MakeSerializer<&'a mut dyn SerializeStructVariant>;

    fn serialize_bool(self, v: bool) -> Result<Self::Ok, Self::Error> {
        self.0.erased_serialize_bool(v);
        Ok(())
    }

    fn serialize_i8(self, v: i8) -> Result<Self::Ok, Self::Error> {
        self.0.erased_serialize_i8(v);
        Ok(())
    }

    fn serialize_i16(self, v: i16) -> Result<Self::Ok, Self::Error> {
        self.0.erased_serialize_i16(v);
        Ok(())
    }

    fn serialize_i32(self, v: i32) -> Result<Self::Ok, Self::Error> {
        self.0.erased_serialize_i32(v);
        Ok(())
    }

    fn serialize_i64(self, v: i64) -> Result<Self::Ok, Self::Error> {
        self.0.erased_serialize_i64(v);
        Ok(())
    }

    fn serialize_i128(self, v: i128) -> Result<Self::Ok, Self::Error> {
        self.0.erased_serialize_i128(v);
        Ok(())
    }

    fn serialize_u8(self, v: u8) -> Result<Self::Ok, Self::Error> {
        self.0.erased_serialize_u8(v);
        Ok(())
    }

    fn serialize_u16(self, v: u16) -> Result<Self::Ok, Self::Error> {
        self.0.erased_serialize_u16(v);
        Ok(())
    }

    fn serialize_u32(self, v: u32) -> Result<Self::Ok, Self::Error> {
        self.0.erased_serialize_u32(v);
        Ok(())
    }

    fn serialize_u64(self, v: u64) -> Result<Self::Ok, Self::Error> {
        self.0.erased_serialize_u64(v);
        Ok(())
    }

    fn serialize_u128(self, v: u128) -> Result<Self::Ok, Self::Error> {
        self.0.erased_serialize_u128(v);
        Ok(())
    }

    fn serialize_f32(self, v: f32) -> Result<Self::Ok, Self::Error> {
        self.0.erased_serialize_f32(v);
        Ok(())
    }

    fn serialize_f64(self, v: f64) -> Result<Self::Ok, Self::Error> {
        self.0.erased_serialize_f64(v);
        Ok(())
    }

    fn serialize_char(self, v: char) -> Result<Self::Ok, Self::Error> {
        self.0.erased_serialize_char(v);
        Ok(())
    }

    fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error> {
        self.0.erased_serialize_str(v);
        Ok(())
    }

    fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok, Self::Error> {
        self.0.erased_serialize_bytes(v);
        Ok(())
    }

    fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
        self.0.erased_serialize_none();
        Ok(())
    }

    fn serialize_some<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
    where
        T: ?Sized + serde::Serialize,
    {
        self.0.erased_serialize_some(&value);
        Ok(())
    }

    fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
        self.0.erased_serialize_unit();
        Ok(())
    }

    fn serialize_unit_struct(self, name: &'static str) -> Result<Self::Ok, Self::Error> {
        self.0.erased_serialize_unit_struct(name);
        Ok(())
    }

    fn serialize_unit_variant(
        self,
        name: &'static str,
        variant_index: u32,
        variant: &'static str,
    ) -> Result<Self::Ok, Self::Error> {
        self.0
            .erased_serialize_unit_variant(name, variant_index, variant);
        Ok(())
    }

    fn serialize_newtype_struct<T>(
        self,
        name: &'static str,
        value: &T,
    ) -> Result<Self::Ok, Self::Error>
    where
        T: ?Sized + serde::Serialize,
    {
        self.0.erased_serialize_newtype_struct(name, &value);
        Ok(())
    }

    fn serialize_newtype_variant<T>(
        self,
        name: &'static str,
        variant_index: u32,
        variant: &'static str,
        value: &T,
    ) -> Result<Self::Ok, Self::Error>
    where
        T: ?Sized + serde::Serialize,
    {
        self.0
            .erased_serialize_newtype_variant(name, variant_index, variant, &value);
        Ok(())
    }

    fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
        self.0.erased_serialize_seq(len).map(MakeSerializer)
    }

    fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> {
        self.0.erased_serialize_tuple(len).map(MakeSerializer)
    }

    fn serialize_tuple_struct(
        self,
        name: &'static str,
        len: usize,
    ) -> Result<Self::SerializeTupleStruct, Self::Error> {
        self.0
            .erased_serialize_tuple_struct(name, len)
            .map(MakeSerializer)
    }

    fn serialize_tuple_variant(
        self,
        name: &'static str,
        variant_index: u32,
        variant: &'static str,
        len: usize,
    ) -> Result<Self::SerializeTupleVariant, Self::Error> {
        self.0
            .erased_serialize_tuple_variant(name, variant_index, variant, len)
            .map(MakeSerializer)
    }

    fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
        self.0.erased_serialize_map(len).map(MakeSerializer)
    }

    fn serialize_struct(
        self,
        name: &'static str,
        len: usize,
    ) -> Result<Self::SerializeStruct, Self::Error> {
        self.0
            .erased_serialize_struct(name, len)
            .map(MakeSerializer)
    }

    fn serialize_struct_variant(
        self,
        name: &'static str,
        variant_index: u32,
        variant: &'static str,
        len: usize,
    ) -> Result<Self::SerializeStructVariant, Self::Error> {
        self.0
            .erased_serialize_struct_variant(name, variant_index, variant, len)
            .map(MakeSerializer)
    }

    #[cfg(not(feature = "alloc"))]
    fn collect_str<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
    where
        T: ?Sized + Display,
    {
        unreachable!()
    }

    fn is_human_readable(&self) -> bool {
        self.0.erased_is_human_readable()
    }
}

pub trait SerializeSeq {
    fn erased_serialize_element(&mut self, value: &dyn Serialize) -> Result<(), ErrorImpl>;
    fn erased_end(&mut self);
}

impl<T> SerializeSeq for erase::Serializer<T>
where
    T: serde::Serializer,
{
    fn erased_serialize_element(&mut self, value: &dyn Serialize) -> Result<(), ErrorImpl> {
        let serializer = match self {
            erase::Serializer::Seq(serializer) => serializer,
            _ => unreachable!(),
        };
        serializer.serialize_element(value).map_err(|err| {
            *self = erase::Serializer::Error(err);
            ShortCircuit
        })
    }

    fn erased_end(&mut self) {
        let serializer = match self.take() {
            erase::Serializer::Seq(serializer) => serializer,
            _ => unreachable!(),
        };
        *self = match serializer.end() {
            Ok(ok) => erase::Serializer::Complete(ok),
            Err(err) => erase::Serializer::Error(err),
        };
    }
}

impl serde::ser::SerializeSeq for MakeSerializer<&mut dyn SerializeSeq> {
    type Ok = ();
    type Error = ErrorImpl;

    fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
    where
        T: ?Sized + serde::Serialize,
    {
        self.0.erased_serialize_element(&value)
    }

    fn end(self) -> Result<Self::Ok, Self::Error> {
        self.0.erased_end();
        Ok(())
    }
}

pub trait SerializeTuple {
    fn erased_serialize_element(&mut self, value: &dyn Serialize) -> Result<(), ErrorImpl>;
    fn erased_end(&mut self);
}

impl<T> SerializeTuple for erase::Serializer<T>
where
    T: serde::Serializer,
{
    fn erased_serialize_element(&mut self, value: &dyn Serialize) -> Result<(), ErrorImpl> {
        let serializer = match self {
            erase::Serializer::Tuple(serializer) => serializer,
            _ => unreachable!(),
        };
        serializer.serialize_element(value).map_err(|err| {
            *self = erase::Serializer::Error(err);
            ShortCircuit
        })
    }

    fn erased_end(&mut self) {
        let serializer = match self.take() {
            erase::Serializer::Tuple(serializer) => serializer,
            _ => unreachable!(),
        };
        *self = match serializer.end() {
            Ok(ok) => erase::Serializer::Complete(ok),
            Err(err) => erase::Serializer::Error(err),
        };
    }
}

impl serde::ser::SerializeTuple for MakeSerializer<&mut dyn SerializeTuple> {
    type Ok = ();
    type Error = ErrorImpl;

    fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
    where
        T: ?Sized + serde::Serialize,
    {
        self.0.erased_serialize_element(&value)
    }

    fn end(self) -> Result<Self::Ok, Self::Error> {
        self.0.erased_end();
        Ok(())
    }
}

pub trait SerializeTupleStruct {
    fn erased_serialize_field(&mut self, value: &dyn Serialize) -> Result<(), ErrorImpl>;
    fn erased_end(&mut self);
}

impl<T> SerializeTupleStruct for erase::Serializer<T>
where
    T: serde::Serializer,
{
    fn erased_serialize_field(&mut self, value: &dyn Serialize) -> Result<(), ErrorImpl> {
        let serializer = match self {
            erase::Serializer::TupleStruct(serializer) => serializer,
            _ => unreachable!(),
        };
        serializer.serialize_field(value).map_err(|err| {
            *self = erase::Serializer::Error(err);
            ShortCircuit
        })
    }

    fn erased_end(&mut self) {
        let serializer = match self.take() {
            erase::Serializer::TupleStruct(serializer) => serializer,
            _ => unreachable!(),
        };
        *self = match serializer.end() {
            Ok(ok) => erase::Serializer::Complete(ok),
            Err(err) => erase::Serializer::Error(err),
        };
    }
}

impl serde::ser::SerializeTupleStruct for MakeSerializer<&mut dyn SerializeTupleStruct> {
    type Ok = ();
    type Error = ErrorImpl;

    fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
    where
        T: ?Sized + serde::Serialize,
    {
        self.0.erased_serialize_field(&value)
    }

    fn end(self) -> Result<Self::Ok, Self::Error> {
        self.0.erased_end();
        Ok(())
    }
}

pub trait SerializeTupleVariant {
    fn erased_serialize_field(&mut self, value: &dyn Serialize) -> Result<(), ErrorImpl>;
    fn erased_end(&mut self);
}

impl<T> SerializeTupleVariant for erase::Serializer<T>
where
    T: serde::Serializer,
{
    fn erased_serialize_field(&mut self, value: &dyn Serialize) -> Result<(), ErrorImpl> {
        let serializer = match self {
            erase::Serializer::TupleVariant(serializer) => serializer,
            _ => unreachable!(),
        };
        serializer.serialize_field(value).map_err(|err| {
            *self = erase::Serializer::Error(err);
            ShortCircuit
        })
    }

    fn erased_end(&mut self) {
        let serializer = match self.take() {
            erase::Serializer::TupleVariant(serializer) => serializer,
            _ => unreachable!(),
        };
        *self = match serializer.end() {
            Ok(ok) => erase::Serializer::Complete(ok),
            Err(err) => erase::Serializer::Error(err),
        };
    }
}

impl serde::ser::SerializeTupleVariant for MakeSerializer<&mut dyn SerializeTupleVariant> {
    type Ok = ();
    type Error = ErrorImpl;

    fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
    where
        T: ?Sized + serde::Serialize,
    {
        self.0.erased_serialize_field(&value)
    }

    fn end(self) -> Result<Self::Ok, Self::Error> {
        self.0.erased_end();
        Ok(())
    }
}

pub trait SerializeMap {
    fn erased_serialize_key(&mut self, key: &dyn Serialize) -> Result<(), ErrorImpl>;
    fn erased_serialize_value(&mut self, value: &dyn Serialize) -> Result<(), ErrorImpl>;
    fn erased_serialize_entry(
        &mut self,
        key: &dyn Serialize,
        value: &dyn Serialize,
    ) -> Result<(), ErrorImpl>;
    fn erased_end(&mut self);
}

impl<T> SerializeMap for erase::Serializer<T>
where
    T: serde::Serializer,
{
    fn erased_serialize_key(&mut self, key: &dyn Serialize) -> Result<(), ErrorImpl> {
        let serializer = match self {
            erase::Serializer::Map(serializer) => serializer,
            _ => unreachable!(),
        };
        serializer.serialize_key(key).map_err(|err| {
            *self = erase::Serializer::Error(err);
            ShortCircuit
        })
    }

    fn erased_serialize_value(&mut self, value: &dyn Serialize) -> Result<(), ErrorImpl> {
        let serializer = match self {
            erase::Serializer::Map(serializer) => serializer,
            _ => unreachable!(),
        };
        serializer.serialize_value(value).map_err(|err| {
            *self = erase::Serializer::Error(err);
            ShortCircuit
        })
    }

    fn erased_serialize_entry(
        &mut self,
        key: &dyn Serialize,
        value: &dyn Serialize,
    ) -> Result<(), ErrorImpl> {
        let serializer = match self {
            erase::Serializer::Map(serializer) => serializer,
            _ => unreachable!(),
        };
        serializer.serialize_entry(key, value).map_err(|err| {
            *self = erase::Serializer::Error(err);
            ShortCircuit
        })
    }

    fn erased_end(&mut self) {
        let serializer = match self.take() {
            erase::Serializer::Map(serializer) => serializer,
            _ => unreachable!(),
        };
        *self = match serializer.end() {
            Ok(ok) => erase::Serializer::Complete(ok),
            Err(err) => erase::Serializer::Error(err),
        };
    }
}

impl serde::ser::SerializeMap for MakeSerializer<&mut dyn SerializeMap> {
    type Ok = ();
    type Error = ErrorImpl;

    fn serialize_key<T>(&mut self, key: &T) -> Result<(), Self::Error>
    where
        T: ?Sized + serde::Serialize,
    {
        self.0.erased_serialize_key(&key)
    }

    fn serialize_value<T>(&mut self, value: &T) -> Result<(), Self::Error>
    where
        T: ?Sized + serde::Serialize,
    {
        self.0.erased_serialize_value(&value)
    }

    fn serialize_entry<K, V>(&mut self, key: &K, value: &V) -> Result<(), Self::Error>
    where
        K: ?Sized + serde::Serialize,
        V: ?Sized + serde::Serialize,
    {
        self.0.erased_serialize_entry(&key, &value)
    }

    fn end(self) -> Result<Self::Ok, Self::Error> {
        self.0.erased_end();
        Ok(())
    }
}

pub trait SerializeStruct {
    fn erased_serialize_field(
        &mut self,
        key: &'static str,
        value: &dyn Serialize,
    ) -> Result<(), ErrorImpl>;
    fn erased_skip_field(&mut self, key: &'static str) -> Result<(), ErrorImpl>;
    fn erased_end(&mut self);
}

impl<T> SerializeStruct for erase::Serializer<T>
where
    T: serde::Serializer,
{
    fn erased_serialize_field(
        &mut self,
        key: &'static str,
        value: &dyn Serialize,
    ) -> Result<(), ErrorImpl> {
        let serializer = match self {
            erase::Serializer::Struct(serializer) => serializer,
            _ => unreachable!(),
        };
        serializer.serialize_field(key, value).map_err(|err| {
            *self = erase::Serializer::Error(err);
            ShortCircuit
        })
    }

    fn erased_skip_field(&mut self, key: &'static str) -> Result<(), ErrorImpl> {
        let serializer = match self {
            erase::Serializer::Struct(serializer) => serializer,
            _ => unreachable!(),
        };
        serializer.skip_field(key).map_err(|err| {
            *self = erase::Serializer::Error(err);
            ShortCircuit
        })
    }

    fn erased_end(&mut self) {
        let serializer = match self.take() {
            erase::Serializer::Struct(serializer) => serializer,
            _ => unreachable!(),
        };
        *self = match serializer.end() {
            Ok(ok) => erase::Serializer::Complete(ok),
            Err(err) => erase::Serializer::Error(err),
        };
    }
}

impl serde::ser::SerializeStruct for MakeSerializer<&mut dyn SerializeStruct> {
    type Ok = ();
    type Error = ErrorImpl;

    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
    where
        T: ?Sized + serde::Serialize,
    {
        self.0.erased_serialize_field(key, &value)
    }

    fn skip_field(&mut self, key: &'static str) -> Result<(), Self::Error> {
        self.0.erased_skip_field(key)
    }

    fn end(self) -> Result<Self::Ok, Self::Error> {
        self.0.erased_end();
        Ok(())
    }
}

pub trait SerializeStructVariant {
    fn erased_serialize_field(
        &mut self,
        key: &'static str,
        value: &dyn Serialize,
    ) -> Result<(), ErrorImpl>;
    fn erased_skip_field(&mut self, key: &'static str) -> Result<(), ErrorImpl>;
    fn erased_end(&mut self);
}

impl<T> SerializeStructVariant for erase::Serializer<T>
where
    T: serde::Serializer,
{
    fn erased_serialize_field(
        &mut self,
        key: &'static str,
        value: &dyn Serialize,
    ) -> Result<(), ErrorImpl> {
        let serializer = match self {
            erase::Serializer::StructVariant(serializer) => serializer,
            _ => unreachable!(),
        };
        serializer.serialize_field(key, value).map_err(|err| {
            *self = erase::Serializer::Error(err);
            ShortCircuit
        })
    }

    fn erased_skip_field(&mut self, key: &'static str) -> Result<(), ErrorImpl> {
        let serializer = match self {
            erase::Serializer::Struct(serializer) => serializer,
            _ => unreachable!(),
        };
        serializer.skip_field(key).map_err(|err| {
            *self = erase::Serializer::Error(err);
            ShortCircuit
        })
    }

    fn erased_end(&mut self) {
        let serializer = match self.take() {
            erase::Serializer::StructVariant(serializer) => serializer,
            _ => unreachable!(),
        };
        *self = match serializer.end() {
            Ok(ok) => erase::Serializer::Complete(ok),
            Err(err) => erase::Serializer::Error(err),
        };
    }
}

impl serde::ser::SerializeStructVariant for MakeSerializer<&mut dyn SerializeStructVariant> {
    type Ok = ();
    type Error = ErrorImpl;

    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
    where
        T: ?Sized + serde::Serialize,
    {
        self.0.erased_serialize_field(key, &value)
    }

    fn skip_field(&mut self, key: &'static str) -> Result<(), Self::Error> {
        self.0.erased_skip_field(key)
    }

    fn end(self) -> Result<Self::Ok, Self::Error> {
        self.0.erased_end();
        Ok(())
    }
}

// IMPL ERASED SERDE FOR ERASED SERDE //////////////////////////////////////////

macro_rules! deref_erased_serializer {
    (<$T:ident> Serializer for $ty:ty $(where $($where:tt)*)?) => {
        impl<$T> Serializer for $ty $(where $($where)*)? {
            fn erased_serialize_bool(&mut self, v: bool) {
                (**self).erased_serialize_bool(v);
            }

            fn erased_serialize_i8(&mut self, v: i8) {
                (**self).erased_serialize_i8(v);
            }

            fn erased_serialize_i16(&mut self, v: i16) {
                (**self).erased_serialize_i16(v);
            }

            fn erased_serialize_i32(&mut self, v: i32) {
                (**self).erased_serialize_i32(v);
            }

            fn erased_serialize_i64(&mut self, v: i64) {
                (**self).erased_serialize_i64(v);
            }

            fn erased_serialize_i128(&mut self, v: i128) {
                (**self).erased_serialize_i128(v);
            }

            fn erased_serialize_u8(&mut self, v: u8) {
                (**self).erased_serialize_u8(v);
            }

            fn erased_serialize_u16(&mut self, v: u16) {
                (**self).erased_serialize_u16(v);
            }

            fn erased_serialize_u32(&mut self, v: u32) {
                (**self).erased_serialize_u32(v);
            }

            fn erased_serialize_u64(&mut self, v: u64) {
                (**self).erased_serialize_u64(v);
            }

            fn erased_serialize_u128(&mut self, v: u128) {
                (**self).erased_serialize_u128(v);
            }

            fn erased_serialize_f32(&mut self, v: f32) {
                (**self).erased_serialize_f32(v);
            }

            fn erased_serialize_f64(&mut self, v: f64) {
                (**self).erased_serialize_f64(v);
            }

            fn erased_serialize_char(&mut self, v: char) {
                (**self).erased_serialize_char(v);
            }

            fn erased_serialize_str(&mut self, v: &str) {
                (**self).erased_serialize_str(v);
            }

            fn erased_serialize_bytes(&mut self, v: &[u8]) {
                (**self).erased_serialize_bytes(v);
            }

            fn erased_serialize_none(&mut self) {
                (**self).erased_serialize_none();
            }

            fn erased_serialize_some(&mut self, value: &dyn Serialize) {
                (**self).erased_serialize_some(value);
            }

            fn erased_serialize_unit(&mut self) {
                (**self).erased_serialize_unit();
            }

            fn erased_serialize_unit_struct(&mut self, name: &'static str) {
                (**self).erased_serialize_unit_struct(name);
            }

            fn erased_serialize_unit_variant(&mut self, name: &'static str, variant_index: u32, variant: &'static str) {
                (**self).erased_serialize_unit_variant(name, variant_index, variant);
            }

            fn erased_serialize_newtype_struct(&mut self, name: &'static str, value: &dyn Serialize) {
                (**self).erased_serialize_newtype_struct(name, value);
            }

            fn erased_serialize_newtype_variant(&mut self, name: &'static str, variant_index: u32, variant: &'static str, value: &dyn Serialize) {
                (**self).erased_serialize_newtype_variant(name, variant_index, variant, value);
            }

            fn erased_serialize_seq(&mut self, len: Option<usize>) -> Result<&mut dyn SerializeSeq, ErrorImpl> {
                (**self).erased_serialize_seq(len)
            }

            fn erased_serialize_tuple(&mut self, len: usize) -> Result<&mut dyn SerializeTuple, ErrorImpl> {
                (**self).erased_serialize_tuple(len)
            }

            fn erased_serialize_tuple_struct(&mut self, name: &'static str, len: usize) -> Result<&mut dyn SerializeTupleStruct, ErrorImpl> {
                (**self).erased_serialize_tuple_struct(name, len)
            }

            fn erased_serialize_tuple_variant(&mut self, name: &'static str, variant_index: u32, variant: &'static str, len: usize) -> Result<&mut dyn SerializeTupleVariant, ErrorImpl> {
                (**self).erased_serialize_tuple_variant(name, variant_index, variant, len)
            }

            fn erased_serialize_map(&mut self, len: Option<usize>) -> Result<&mut dyn SerializeMap, ErrorImpl> {
                (**self).erased_serialize_map(len)
            }

            fn erased_serialize_struct(&mut self, name: &'static str, len: usize) -> Result<&mut dyn SerializeStruct, ErrorImpl> {
                (**self).erased_serialize_struct(name, len)
            }

            fn erased_serialize_struct_variant(&mut self, name: &'static str, variant_index: u32, variant: &'static str, len: usize) -> Result<&mut dyn SerializeStructVariant, ErrorImpl> {
                (**self).erased_serialize_struct_variant(name, variant_index, variant, len)
            }

            fn erased_is_human_readable(&self) -> bool {
                (**self).erased_is_human_readable()
            }

            fn erased_display_error(&self) -> &dyn Display {
                (**self).erased_display_error()
            }
        }

        impl<$T> sealed::serializer::Sealed for $ty $(where $($where)*)? {}
    };
}

deref_erased_serializer!(<T> Serializer for &mut T where T: ?Sized + Serializer);
deref_erased_serializer!(<T> Serializer for Box<T> where T: ?Sized + Serializer);

// TEST ////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use super::*;
    use alloc::{vec, vec::Vec};
    use serde_derive::Serialize;

    fn test_json<T>(t: T)
    where
        T: serde::Serialize,
    {
        let expected = serde_json::to_vec(&t).unwrap();

        // test borrowed trait object
        {
            let obj: &dyn Serialize = &t;

            let mut buf = Vec::new();

            {
                let mut ser = serde_json::Serializer::new(&mut buf);
                let ser: &mut dyn Serializer = &mut <dyn Serializer>::erase(&mut ser);

                obj.erased_serialize(ser).unwrap();
            }

            assert_eq!(buf, expected);
        }

        // test boxed trait object
        {
            let obj: Box<dyn Serialize> = Box::new(t);

            let mut buf = Vec::new();

            {
                let mut ser = serde_json::Serializer::new(&mut buf);
                let mut ser: Box<dyn Serializer> = Box::new(<dyn Serializer>::erase(&mut ser));

                obj.erased_serialize(&mut ser).unwrap();
            }

            assert_eq!(buf, expected);
        }
    }

    #[test]
    fn test_vec() {
        test_json(vec!["a", "b"]);
    }

    #[test]
    fn test_struct() {
        #[derive(Serialize)]
        struct S {
            f: usize,
        }

        test_json(S { f: 256 });
    }

    #[test]
    fn test_enum() {
        #[derive(Serialize)]
        enum E {
            Unit,
            Newtype(bool),
            Tuple(bool, bool),
            Struct { t: bool, f: bool },
        }

        test_json(E::Unit);
        test_json(E::Newtype(true));
        test_json(E::Tuple(true, false));
        test_json(E::Struct { t: true, f: false });
    }

    #[test]
    fn test_error_custom() {
        struct Kaboom;

        impl serde::Serialize for Kaboom {
            fn serialize<S>(&self, _: S) -> Result<S::Ok, S::Error>
            where
                S: serde::Serializer,
            {
                use serde::ser::Error as _;

                Err(S::Error::custom("kaboom"))
            }
        }

        let obj: &dyn Serialize = &Kaboom;

        let err = serde_json::to_vec(obj).unwrap_err();
        assert_eq!(err.to_string(), "kaboom");
    }

    #[test]
    fn assert_serialize() {
        fn assert<T: serde::Serialize>() {}

        assert::<&dyn Serialize>();
        assert::<&(dyn Serialize + Send)>();
        assert::<&(dyn Serialize + Sync)>();
        assert::<&(dyn Serialize + Send + Sync)>();
        assert::<&(dyn Serialize + Sync + Send)>();
        assert::<Vec<&dyn Serialize>>();
        assert::<Vec<&(dyn Serialize + Send)>>();

        assert::<Box<dyn Serialize>>();
        assert::<Box<dyn Serialize + Send>>();
        assert::<Box<dyn Serialize + Sync>>();
        assert::<Box<dyn Serialize + Send + Sync>>();
        assert::<Box<dyn Serialize + Sync + Send>>();
        assert::<Vec<Box<dyn Serialize>>>();
        assert::<Vec<Box<dyn Serialize + Send>>>();
    }
}
