use std::fmt::{self, Write};
use std::io;
use std::mem;

use serde::ser::{
    Error as SerdeError,
    Serialize, Serializer,
    SerializeSeq, SerializeTuple, SerializeTupleStruct,
    SerializeTupleVariant, SerializeMap, SerializeStruct,
    SerializeStructVariant,
};

use error::{Error, ErrorKind, new_error};
use writer::{Writer, SingleFieldWriter};

/// Serialize the given value to the given writer, and return an error if
/// anything went wrong.
pub fn serialize<S: Serialize, W: io::Write>(wtr: &mut Writer<W>, value: S) -> Result<(), Error> {
    value.serialize(&mut SeRecord { wtr: wtr })
}

struct SeRecord<'w, W: 'w + io::Write> {
    wtr: &'w mut Writer<W>,
}

impl<'a, 'w, W: io::Write> Serializer for &'a mut SeRecord<'w, W> {
    type Ok = ();
    type Error = Error;
    type SerializeSeq = Self;
    type SerializeTuple = Self;
    type SerializeTupleStruct = Self;
    type SerializeTupleVariant = Self;
    type SerializeMap = Self;
    type SerializeStruct = Self;
    type SerializeStructVariant = Self;

    fn collect_str<T: ?Sized + fmt::Display>(self, v: &T) -> Result<(), Error> {
        let mut sfw = SingleFieldWriter::start_field(self.wtr)?;
        let _ = write!(sfw, "{}", v);
        sfw.take_formatting_error()
    }

    fn serialize_bool(self, v: bool) -> Result<Self::Ok, Self::Error> {
        if v {
            self.wtr.write_field("true")
        } else {
            self.wtr.write_field("false")
        }
    }

    fn serialize_i8(self, v: i8) -> Result<Self::Ok, Self::Error> {
        self.collect_str(&v)
    }

    fn serialize_i16(self, v: i16) -> Result<Self::Ok, Self::Error> {
        self.collect_str(&v)
    }

    fn serialize_i32(self, v: i32) -> Result<Self::Ok, Self::Error> {
        self.collect_str(&v)
    }

    fn serialize_i64(self, v: i64) -> Result<Self::Ok, Self::Error> {
        self.collect_str(&v)
    }

    fn serialize_u8(self, v: u8) -> Result<Self::Ok, Self::Error> {
        self.collect_str(&v)
    }

    fn serialize_u16(self, v: u16) -> Result<Self::Ok, Self::Error> {
        self.collect_str(&v)
    }

    fn serialize_u32(self, v: u32) -> Result<Self::Ok, Self::Error> {
        self.collect_str(&v)
    }

    fn serialize_u64(self, v: u64) -> Result<Self::Ok, Self::Error> {
        self.collect_str(&v)
    }

    fn serialize_f32(self, v: f32) -> Result<Self::Ok, Self::Error> {
        self.collect_str(&v)
    }

    fn serialize_f64(self, v: f64) -> Result<Self::Ok, Self::Error> {
        self.collect_str(&v)
    }

    fn serialize_char(self, v: char) -> Result<Self::Ok, Self::Error> {
        self.collect_str(&v)
    }

    fn serialize_str(self, value: &str) -> Result<Self::Ok, Self::Error> {
        self.wtr.write_field(value)
    }

    fn serialize_bytes(self, value: &[u8]) -> Result<Self::Ok, Self::Error> {
        self.wtr.write_field(value)
    }

    fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
        self.wtr.write_field(&[])
    }

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

    fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
        None::<()>.serialize(self)
    }

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

    fn serialize_unit_variant(
        self,
        _name: &'static str,
        _variant_index: u32,
        variant: &'static str,
    ) -> Result<Self::Ok, Self::Error> {
        self.wtr.write_field(variant)
    }

    fn serialize_newtype_struct<T: ?Sized + Serialize>(
        self,
        _name: &'static str,
        value: &T,
    ) -> Result<Self::Ok, Self::Error> {
        value.serialize(self)
    }

    fn serialize_newtype_variant<T: ?Sized + Serialize>(
        self,
        _name: &'static str,
        _variant_index: u32,
        _variant: &'static str,
        value: &T,
    ) -> Result<Self::Ok, Self::Error> {
        value.serialize(self)
    }

    fn serialize_seq(
        self,
        _len: Option<usize>,
    ) -> Result<Self::SerializeSeq, Self::Error> {
        Ok(self)
    }

    fn serialize_tuple(
        self,
        _len: usize,
    ) -> Result<Self::SerializeTuple, Self::Error> {
        Ok(self)
    }

    fn serialize_tuple_struct(
        self,
        _name: &'static str,
        _len: usize,
    ) -> Result<Self::SerializeTupleStruct, Self::Error> {
        Ok(self)
    }

    fn serialize_tuple_variant(
        self,
        _name: &'static str,
        _variant_index: u32,
        _variant: &'static str,
        _len: usize,
    ) -> Result<Self::SerializeTupleVariant, Self::Error> {
        Err(Error::custom("serializing enum tuple variants is not supported"))
    }

    fn serialize_map(
        self,
        _len: Option<usize>,
    ) -> Result<Self::SerializeMap, Self::Error> {
        // The right behavior for serializing maps isn't clear.
        Err(Error::custom(
            "serializing maps is not supported, \
             if you have a use case, please file an issue at \
             https://github.com/BurntSushi/rust-csv"))
    }

    fn serialize_struct(
        self,
        _name: &'static str,
        _len: usize,
    ) -> Result<Self::SerializeStruct, Self::Error> {
        Ok(self)
    }

    fn serialize_struct_variant(
        self,
        _name: &'static str,
        _variant_index: u32,
        _variant: &'static str,
        _len: usize,
    ) -> Result<Self::SerializeStructVariant, Self::Error> {
        Err(Error::custom("serializing enum struct variants is not supported"))
    }
}

impl<'a, 'w, W: io::Write> SerializeSeq for &'a mut SeRecord<'w, W> {
    type Ok = ();
    type Error = Error;

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

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

impl<'a, 'w, W: io::Write> SerializeTuple for &'a mut SeRecord<'w, W> {
    type Ok = ();
    type Error = Error;

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

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

impl<'a, 'w, W: io::Write> SerializeTupleStruct for &'a mut SeRecord<'w, W> {
    type Ok = ();
    type Error = Error;

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

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

impl<'a, 'w, W: io::Write> SerializeTupleVariant for &'a mut SeRecord<'w, W> {
    type Ok = ();
    type Error = Error;

    fn serialize_field<T: ?Sized + Serialize>(
        &mut self,
        _value: &T,
    ) -> Result<(), Self::Error> {
        unreachable!()
    }

    fn end(self) -> Result<Self::Ok, Self::Error> {
        unreachable!()
    }
}

impl<'a, 'w, W: io::Write> SerializeMap for &'a mut SeRecord<'w, W> {
    type Ok = ();
    type Error = Error;

    fn serialize_key<T: ?Sized + Serialize>(
        &mut self,
        _key: &T,
    ) -> Result<(), Self::Error> {
        unreachable!()
    }

    fn serialize_value<T: ?Sized + Serialize>(
        &mut self,
        _value: &T,
    ) -> Result<(), Self::Error> {
        unreachable!()
    }

    fn end(self) -> Result<Self::Ok, Self::Error> {
        unreachable!()
    }
}

impl<'a, 'w, W: io::Write> SerializeStruct for &'a mut SeRecord<'w, W> {
    type Ok = ();
    type Error = Error;

    fn serialize_field<T: ?Sized + Serialize>(
        &mut self,
        _key: &'static str,
        value: &T,
    ) -> Result<(), Self::Error> {
        value.serialize(&mut **self)
    }

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

impl<'a, 'w, W: io::Write> SerializeStructVariant for &'a mut SeRecord<'w, W> {
    type Ok = ();
    type Error = Error;

    fn serialize_field<T: ?Sized + Serialize>(
        &mut self,
        _key: &'static str,
        _value: &T,
    ) -> Result<(), Self::Error> {
        unreachable!()
    }

    fn end(self) -> Result<Self::Ok, Self::Error> {
        unreachable!()
    }
}

impl SerdeError for Error {
    fn custom<T: fmt::Display>(msg: T) -> Error {
        new_error(ErrorKind::Serialize(msg.to_string()))
    }
}

fn error_scalar_outside_struct<T: fmt::Display>(name: T) -> Error {
    Error::custom(format!(
        "cannot serialize {} scalar outside struct when writing headers from structs",
        name
    ))
}

fn error_container_inside_struct<T: fmt::Display>(name: T) -> Error {
    Error::custom(format!(
        "cannot serialize {} container inside struct when writing headers from structs",
        name
    ))
}

/// Write header names corresponding to the field names of the value (if the
/// value has field names).
///
/// If the type to be serialized has field names (e.g. it's a struct), then
/// header names are written, and the `Ok` return value is `true`.
///
/// If the type to be serialized doesn't have field names, then nothing is
/// written, and the `Ok` return value is `false`.
pub fn serialize_header<S: Serialize, W: io::Write>(
    wtr: &mut Writer<W>,
    value: S,
) -> Result<bool, Error> {
    let mut ser = SeHeader::new(wtr);
    value.serialize(&mut ser).map(|_| ser.wrote_header())
}

/// State machine for `SeHeader`.
///
/// This is a diagram of the transitions in the state machine. Note that only
/// some serialization events cause a state transition, and only for certain
/// states. For example, encountering a scalar causes a transition if the state
/// is `Write` or `EncounteredStructField`, but not if the state is
/// `ErrorIfWrite(err)` or `InStructField`.
///
/// ```text
///                              +-----+
///                              |Write|
///                              +-----+
///                                 |
///              /------------------+------------------\
///              |                  |                  |
///          encounter            finish           encounter
///            scalar               |             struct field
///              |                  |                  |
///              v                  v                  v
///     +-----------------+       Ok(())        +-------------+
///     |ErrorIfWrite(err)|                     |InStructField|<--------\
///     +-----------------+                     +-------------+         |
///              |                                     |                |
///       /------+------\            /-----------------+                |
///       |             |            |                 |                |
///   encounter       finish     encounter          finish          encounter
///  struct field       |        container           field         struct field
///       |             |            |                 |                |
///       v             v            v                 v                |
///   Err(err)       Ok(())        Err(_)   +----------------------+    |
///                                         |EncounteredStructField|    |
///                                         +----------------------+    |
///                                                    |                |
///                                         /----------+----------------/
///                                         |          |
///                                     encounter    finish
///                                       scalar       |
///                                         |          |
///                                         v          v
///                                       Err(_)    Ok(())
/// ```
enum HeaderState {
    /// Start here. Headers need to be written if the type has field names.
    Write,
    /// The serializer still has not encountered a struct field. If one is
    /// encountered (headers need to be written), return the enclosed error.
    ErrorIfWrite(Error),
    /// The serializer encountered one or more struct fields (and wrote their names).
    EncounteredStructField,
    /// The serializer is currently in a struct field value.
    InStructField,
}

struct SeHeader<'w, W: 'w + io::Write> {
    wtr: &'w mut Writer<W>,
    state: HeaderState,
}

impl<'w, W: io::Write> SeHeader<'w, W> {
    fn new(wtr: &'w mut Writer<W>) -> Self {
        SeHeader {
            wtr: wtr,
            state: HeaderState::Write,
        }
    }

    fn wrote_header(&self) -> bool {
        use self::HeaderState::*;
        match self.state {
            Write | ErrorIfWrite(_) => false,
            EncounteredStructField | InStructField => true,
        }
    }

    fn handle_scalar<T: fmt::Display>(&mut self, name: T) -> Result<(), Error> {
        use self::HeaderState::*;
        match self.state {
            Write => {
                self.state = ErrorIfWrite(error_scalar_outside_struct(name));
                Ok(())
            }
            ErrorIfWrite(_) | InStructField => Ok(()),
            EncounteredStructField => Err(error_scalar_outside_struct(name)),
        }
    }

    fn handle_container<T: fmt::Display>(&mut self, name: T) -> Result<&mut Self, Error> {
        if let HeaderState::InStructField = self.state {
            Err(error_container_inside_struct(name))
        } else {
            Ok(self)
        }
    }
}

impl<'a, 'w, W: io::Write> Serializer for &'a mut SeHeader<'w, W> {
    type Ok = ();
    type Error = Error;
    type SerializeSeq = Self;
    type SerializeTuple = Self;
    type SerializeTupleStruct = Self;
    type SerializeTupleVariant = Self;
    type SerializeMap = Self;
    type SerializeStruct = Self;
    type SerializeStructVariant = Self;

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

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

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

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

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

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

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

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

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

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

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

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

    fn serialize_str(self, value: &str) -> Result<Self::Ok, Self::Error> {
        self.handle_scalar(value)
    }

    fn serialize_bytes(self, _value: &[u8]) -> Result<Self::Ok, Self::Error> {
        self.handle_scalar("&[u8]")
    }

    fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
        self.handle_scalar("None")
    }

    fn serialize_some<T: ?Sized + Serialize>(self, _value: &T) -> Result<Self::Ok, Self::Error> {
        self.handle_scalar("Some(_)")
    }

    fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
        self.handle_scalar("()")
    }

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

    fn serialize_unit_variant(
        self,
        name: &'static str,
        _variant_index: u32,
        variant: &'static str,
    ) -> Result<Self::Ok, Self::Error> {
        self.handle_scalar(format!("{}::{}", name, variant))
    }

    fn serialize_newtype_struct<T: ?Sized + Serialize>(
        self,
        name: &'static str,
        _value: &T,
    ) -> Result<Self::Ok, Self::Error> {
        self.handle_scalar(format!("{}(_)", name))
    }

    fn serialize_newtype_variant<T: ?Sized + Serialize>(
        self,
        name: &'static str,
        _variant_index: u32,
        variant: &'static str,
        _value: &T,
    ) -> Result<Self::Ok, Self::Error> {
        self.handle_scalar(format!("{}::{}(_)", name, variant))
    }

    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
        self.handle_container("sequence")
    }

    fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
        self.handle_container("tuple")
    }

    fn serialize_tuple_struct(
        self,
        name: &'static str,
        _len: usize,
    ) -> Result<Self::SerializeTupleStruct, Self::Error> {
        self.handle_container(name)
    }

    fn serialize_tuple_variant(
        self,
        _name: &'static str,
        _variant_index: u32,
        _variant: &'static str,
        _len: usize,
    ) -> Result<Self::SerializeTupleVariant, Self::Error> {
        Err(Error::custom(
            "serializing enum tuple variants is not supported",
        ))
    }

    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
        // The right behavior for serializing maps isn't clear.
        Err(Error::custom(
            "serializing maps is not supported, \
             if you have a use case, please file an issue at \
             https://github.com/BurntSushi/rust-csv",
        ))
    }

    fn serialize_struct(
        self,
        name: &'static str,
        _len: usize,
    ) -> Result<Self::SerializeStruct, Self::Error> {
        self.handle_container(name)
    }

    fn serialize_struct_variant(
        self,
        _name: &'static str,
        _variant_index: u32,
        _variant: &'static str,
        _len: usize,
    ) -> Result<Self::SerializeStructVariant, Self::Error> {
        Err(Error::custom(
            "serializing enum struct variants is not supported",
        ))
    }
}

impl<'a, 'w, W: io::Write> SerializeSeq for &'a mut SeHeader<'w, W> {
    type Ok = ();
    type Error = Error;

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

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

impl<'a, 'w, W: io::Write> SerializeTuple for &'a mut SeHeader<'w, W> {
    type Ok = ();
    type Error = Error;

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

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

impl<'a, 'w, W: io::Write> SerializeTupleStruct for &'a mut SeHeader<'w, W> {
    type Ok = ();
    type Error = Error;

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

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

impl<'a, 'w, W: io::Write> SerializeTupleVariant for &'a mut SeHeader<'w, W> {
    type Ok = ();
    type Error = Error;

    fn serialize_field<T: ?Sized + Serialize>(&mut self, _value: &T) -> Result<(), Self::Error> {
        unreachable!()
    }

    fn end(self) -> Result<Self::Ok, Self::Error> {
        unreachable!()
    }
}

impl<'a, 'w, W: io::Write> SerializeMap for &'a mut SeHeader<'w, W> {
    type Ok = ();
    type Error = Error;

    fn serialize_key<T: ?Sized + Serialize>(&mut self, _key: &T) -> Result<(), Self::Error> {
        unreachable!()
    }

    fn serialize_value<T: ?Sized + Serialize>(&mut self, _value: &T) -> Result<(), Self::Error> {
        unreachable!()
    }

    fn end(self) -> Result<Self::Ok, Self::Error> {
        unreachable!()
    }
}

impl<'a, 'w, W: io::Write> SerializeStruct for &'a mut SeHeader<'w, W> {
    type Ok = ();
    type Error = Error;

    fn serialize_field<T: ?Sized + Serialize>(
        &mut self,
        key: &'static str,
        value: &T,
    ) -> Result<(), Self::Error> {
        // Grab old state and update state to `EncounteredStructField`.
        let old_state = mem::replace(&mut self.state, HeaderState::EncounteredStructField);
        if let HeaderState::ErrorIfWrite(err) = old_state {
            return Err(err);
        }
        self.wtr.write_field(key)?;

        // Check that there aren't any containers in the value.
        self.state = HeaderState::InStructField;
        value.serialize(&mut **self)?;
        self.state = HeaderState::EncounteredStructField;

        Ok(())
    }

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

impl<'a, 'w, W: io::Write> SerializeStructVariant for &'a mut SeHeader<'w, W> {
    type Ok = ();
    type Error = Error;

    fn serialize_field<T: ?Sized + Serialize>(
        &mut self,
        _key: &'static str,
        _value: &T,
    ) -> Result<(), Self::Error> {
        unreachable!()
    }

    fn end(self) -> Result<Self::Ok, Self::Error> {
        unreachable!()
    }
}

#[cfg(test)]
mod tests {
    use serde::Serialize;
    use serde_bytes::Bytes;

    use error::{Error, ErrorKind};
    use writer::Writer;

    use super::{SeHeader, SeRecord};

    fn serialize<S: Serialize>(s: S) -> String {
        let mut wtr = Writer::from_writer(vec![]);
        s.serialize(&mut SeRecord { wtr: &mut wtr }).unwrap();
        wtr.write_record(None::<&[u8]>).unwrap();
        String::from_utf8(wtr.into_inner().unwrap()).unwrap()
    }

    /// Serialize using `SeHeader`. Returns whether a header was written and
    /// the output of the writer.
    fn serialize_header<S: Serialize>(s: S) -> (bool, String) {
        let mut wtr = Writer::from_writer(vec![]);
        let wrote = {
            let mut ser = SeHeader::new(&mut wtr);
            s.serialize(&mut ser).unwrap();
            ser.wrote_header()
        };
        (wrote, String::from_utf8(wtr.into_inner().unwrap()).unwrap())
    }

    fn serialize_err<S: Serialize>(s: S) -> Error {
        let mut wtr = Writer::from_writer(vec![]);
        s.serialize(&mut SeRecord { wtr: &mut wtr }).unwrap_err()
    }

    fn serialize_header_err<S: Serialize>(s: S) -> Error {
        let mut wtr = Writer::from_writer(vec![]);
        s.serialize(&mut SeHeader::new(&mut wtr)).unwrap_err()
    }

    #[test]
    fn bool() {
        let got = serialize(true);
        assert_eq!(got, "true\n");
        let (wrote, got) = serialize_header(true);
        assert!(!wrote);
        assert_eq!(got, "");
    }

    #[test]
    fn integer() {
        let got = serialize(12345);
        assert_eq!(got, "12345\n");
        let (wrote, got) = serialize_header(12345);
        assert!(!wrote);
        assert_eq!(got, "");
    }

    #[test]
    fn float() {
        let got = serialize(1.23);
        assert_eq!(got, "1.23\n");
        let (wrote, got) = serialize_header(1.23);
        assert!(!wrote);
        assert_eq!(got, "");
    }

    #[test]
    fn char() {
        let got = serialize('☃');
        assert_eq!(got, "☃\n");
        let (wrote, got) = serialize_header('☃');
        assert!(!wrote);
        assert_eq!(got, "");
    }

    #[test]
    fn str() {
        let got = serialize("how\nare\n\"you\"?");
        assert_eq!(got, "\"how\nare\n\"\"you\"\"?\"\n");
        let (wrote, got) = serialize_header("how\nare\n\"you\"?");
        assert!(!wrote);
        assert_eq!(got, "");
    }

    #[test]
    fn bytes() {
        let got = serialize(Bytes::new(&b"how\nare\n\"you\"?"[..]));
        assert_eq!(got, "\"how\nare\n\"\"you\"\"?\"\n");
        let (wrote, got) = serialize_header(&b"how\nare\n\"you\"?"[..]);
        assert!(!wrote);
        assert_eq!(got, "");
    }

    #[test]
    fn option() {
        let got = serialize(None::<()>);
        assert_eq!(got, "\"\"\n");
        let (wrote, got) = serialize_header(None::<()>);
        assert!(!wrote);
        assert_eq!(got, "");

        let got = serialize(Some(5));
        assert_eq!(got, "5\n");
        let (wrote, got) = serialize_header(Some(5));
        assert!(!wrote);
        assert_eq!(got, "");
    }

    #[test]
    fn unit() {
        let got = serialize(());
        assert_eq!(got, "\"\"\n");
        let (wrote, got) = serialize_header(());
        assert!(!wrote);
        assert_eq!(got, "");

        let got = serialize((5, ()));
        assert_eq!(got, "5,\n");
        let (wrote, got) = serialize_header(());
        assert!(!wrote);
        assert_eq!(got, "");
    }

    #[test]
    fn struct_unit() {
        #[derive(Serialize)]
        struct Foo;

        let got = serialize(Foo);
        assert_eq!(got, "Foo\n");
        let (wrote, got) = serialize_header(Foo);
        assert!(!wrote);
        assert_eq!(got, "");
    }

    #[test]
    fn struct_newtype() {
        #[derive(Serialize)]
        struct Foo(f64);

        let got = serialize(Foo(1.5));
        assert_eq!(got, "1.5\n");
        let (wrote, got) = serialize_header(Foo(1.5));
        assert!(!wrote);
        assert_eq!(got, "");
    }

    #[test]
    fn enum_units() {
        #[derive(Serialize)]
        enum Wat { Foo, Bar, Baz }

        let got = serialize(Wat::Foo);
        assert_eq!(got, "Foo\n");
        let (wrote, got) = serialize_header(Wat::Foo);
        assert!(!wrote);
        assert_eq!(got, "");

        let got = serialize(Wat::Bar);
        assert_eq!(got, "Bar\n");
        let (wrote, got) = serialize_header(Wat::Bar);
        assert!(!wrote);
        assert_eq!(got, "");

        let got = serialize(Wat::Baz);
        assert_eq!(got, "Baz\n");
        let (wrote, got) = serialize_header(Wat::Baz);
        assert!(!wrote);
        assert_eq!(got, "");
    }

    #[test]
    fn enum_newtypes() {
        #[derive(Serialize)]
        enum Wat { Foo(i32), Bar(f32), Baz(bool) }

        let got = serialize(Wat::Foo(5));
        assert_eq!(got, "5\n");
        let (wrote, got) = serialize_header(Wat::Foo(5));
        assert!(!wrote);
        assert_eq!(got, "");

        let got = serialize(Wat::Bar(1.5));
        assert_eq!(got, "1.5\n");
        let (wrote, got) = serialize_header(Wat::Bar(1.5));
        assert!(!wrote);
        assert_eq!(got, "");

        let got = serialize(Wat::Baz(true));
        assert_eq!(got, "true\n");
        let (wrote, got) = serialize_header(Wat::Baz(true));
        assert!(!wrote);
        assert_eq!(got, "");
    }

    #[test]
    fn seq() {
        let got = serialize(vec![1, 2, 3]);
        assert_eq!(got, "1,2,3\n");
        let (wrote, got) = serialize_header(vec![1, 2, 3]);
        assert!(!wrote);
        assert_eq!(got, "");
    }

    #[test]
    fn tuple() {
        let row = (true, 1.5, "hi");
        let got = serialize(row.clone());
        assert_eq!(got, "true,1.5,hi\n");
        let (wrote, got) = serialize_header(row.clone());
        assert!(!wrote);
        assert_eq!(got, "");

        let row = (true, 1.5, vec![1, 2, 3]);
        let got = serialize(row.clone());
        assert_eq!(got, "true,1.5,1,2,3\n");
        let (wrote, got) = serialize_header(row.clone());
        assert!(!wrote);
        assert_eq!(got, "");
    }

    #[test]
    fn tuple_struct() {
        #[derive(Clone, Serialize)]
        struct Foo(bool, i32, String);

        let row = Foo(false, 42, "hi".to_string());
        let got = serialize(row.clone());
        assert_eq!(got, "false,42,hi\n");
        let (wrote, got) = serialize_header(row.clone());
        assert!(!wrote);
        assert_eq!(got, "");
    }

    #[test]
    fn tuple_variant() {
        #[derive(Clone, Serialize)]
        enum Foo {
            X(bool, i32, String),
        }

        let row = Foo::X(false, 42, "hi".to_string());
        let err = serialize_err(row.clone());
        match *err.kind() {
            ErrorKind::Serialize(_) => {}
            ref x => panic!("expected ErrorKind::Serialize but got '{:?}'", x),
        }
        let err = serialize_header_err(row.clone());
        match *err.kind() {
            ErrorKind::Serialize(_) => {}
            ref x => panic!("expected ErrorKind::Serialize but got '{:?}'", x),
        }
    }

    #[test]
    fn enum_struct_variant() {
        #[derive(Clone, Serialize)]
        enum Foo {
            X { a: bool, b: i32, c: String },
        }

        let row = Foo::X { a: false, b: 1, c: "hi".into() };
        let err = serialize_err(row.clone());
        match *err.kind() {
            ErrorKind::Serialize(_) => {}
            ref x => panic!("expected ErrorKind::Serialize but got '{:?}'", x),
        }
        let err = serialize_header_err(row.clone());
        match *err.kind() {
            ErrorKind::Serialize(_) => {}
            ref x => panic!("expected ErrorKind::Serialize but got '{:?}'", x),
        }
    }

    #[test]
    fn struct_no_headers() {
        #[derive(Serialize)]
        struct Foo {
            x: bool,
            y: i32,
            z: String,
        }

        let got = serialize(Foo { x: true, y: 5, z: "hi".into() });
        assert_eq!(got, "true,5,hi\n");
    }

    #[test]
    fn struct_headers() {
        #[derive(Clone, Serialize)]
        struct Foo {
            x: bool,
            y: i32,
            z: String,
        }

        let row = Foo { x: true, y: 5, z: "hi".into() };
        let (wrote, got) = serialize_header(row.clone());
        assert!(wrote);
        assert_eq!(got, "x,y,z");
        let got = serialize(row.clone());
        assert_eq!(got, "true,5,hi\n");
    }

    #[test]
    fn struct_headers_nested() {
        #[derive(Clone, Serialize)]
        struct Foo {
            label: String,
            nest: Nested,
        }
        #[derive(Clone, Serialize)]
        struct Nested {
            label2: String,
            value: i32,
        }

        let row = Foo {
            label: "foo".into(),
            nest: Nested {
                label2: "bar".into(),
                value: 5,
            },
        };

        let got = serialize(row.clone());
        assert_eq!(got, "foo,bar,5\n");

        let err = serialize_header_err(row.clone());
        match *err.kind() {
            ErrorKind::Serialize(_) => {}
            ref x => panic!("expected ErrorKind::Serialize but got '{:?}'", x),
        }
    }

    #[test]
    fn struct_headers_nested_seq() {
        #[derive(Clone, Serialize)]
        struct Foo {
            label: String,
            values: Vec<i32>,
        }
        let row = Foo { label: "foo".into(), values: vec![1, 2, 3] };

        let got = serialize(row.clone());
        assert_eq!(got, "foo,1,2,3\n");

        let err = serialize_header_err(row.clone());
        match *err.kind() {
            ErrorKind::Serialize(_) => {}
            ref x => panic!("expected ErrorKind::Serialize but got '{:?}'", x),
        }
    }

    #[test]
    fn struct_headers_inside_tuple() {
        #[derive(Clone, Serialize)]
        struct Foo {
            label: String,
            num: f64,
        }
        #[derive(Clone, Serialize)]
        struct Bar {
            label2: bool,
            value: i32,
            empty: (),
        }
        let row = (
            Foo {
                label: "hi".to_string(),
                num: 5.,
            },
            Bar {
                label2: true,
                value: 3,
                empty: (),
            },
            Foo {
                label: "baz".to_string(),
                num: 2.3,
            },
        );

        let got = serialize(row.clone());
        assert_eq!(got, "hi,5,true,3,,baz,2.3\n");

        let (wrote, got) = serialize_header(row.clone());
        assert!(wrote);
        assert_eq!(got, "label,num,label2,value,empty,label,num");
    }

    #[test]
    fn struct_headers_inside_tuple_scalar_before() {
        #[derive(Clone, Serialize)]
        struct Foo {
            label: String,
            num: f64,
        }
        let row = (
            3.14,
            Foo {
                label: "hi".to_string(),
                num: 5.,
            },
        );

        let got = serialize(row.clone());
        assert_eq!(got, "3.14,hi,5\n");

        let err = serialize_header_err(row.clone());
        match *err.kind() {
            ErrorKind::Serialize(_) => {}
            ref x => panic!("expected ErrorKind::Serialize but got '{:?}'", x),
        }
    }

    #[test]
    fn struct_headers_inside_tuple_scalar_after() {
        #[derive(Clone, Serialize)]
        struct Foo {
            label: String,
            num: f64,
        }
        let row = (
            Foo {
                label: "hi".to_string(),
                num: 5.,
            },
            3.14,
        );

        let got = serialize(row.clone());
        assert_eq!(got, "hi,5,3.14\n");

        let err = serialize_header_err(row.clone());
        match *err.kind() {
            ErrorKind::Serialize(_) => {}
            ref x => panic!("expected ErrorKind::Serialize but got '{:?}'", x),
        }
    }

    #[test]
    fn struct_headers_inside_seq() {
        #[derive(Clone, Serialize)]
        struct Foo {
            label: String,
            num: f64,
        }
        let row = vec![
            Foo {
                label: "hi".to_string(),
                num: 5.,
            },
            Foo {
                label: "baz".to_string(),
                num: 2.3,
            },
        ];

        let got = serialize(row.clone());
        assert_eq!(got, "hi,5,baz,2.3\n");

        let (wrote, got) = serialize_header(row.clone());
        assert!(wrote);
        assert_eq!(got, "label,num,label,num");
    }

    #[test]
    fn struct_headers_inside_nested_tuple_seq() {
        #[derive(Clone, Serialize)]
        struct Foo {
            label: String,
            num: f64,
        }
        #[derive(Clone, Serialize)]
        struct Bar {
            label2: Baz,
            value: i32,
            empty: (),
        }
        #[derive(Clone, Serialize)]
        struct Baz(bool);
        let row = (
            (
                Foo {
                    label: "hi".to_string(),
                    num: 5.,
                },
                Bar {
                    label2: Baz(true),
                    value: 3,
                    empty: (),
                },
            ),
            vec![
                (Foo {
                    label: "baz".to_string(),
                    num: 2.3,
                },),
            ],
        );

        let got = serialize(row.clone());
        assert_eq!(got, "hi,5,true,3,,baz,2.3\n");

        let (wrote, got) = serialize_header(row.clone());
        assert!(wrote);
        assert_eq!(got, "label,num,label2,value,empty,label,num");
    }
}
