diff options
Diffstat (limited to 'third_party/rust/toml/src/ser.rs')
-rw-r--r-- | third_party/rust/toml/src/ser.rs | 1853 |
1 files changed, 1853 insertions, 0 deletions
diff --git a/third_party/rust/toml/src/ser.rs b/third_party/rust/toml/src/ser.rs new file mode 100644 index 0000000000..ecee1a296b --- /dev/null +++ b/third_party/rust/toml/src/ser.rs @@ -0,0 +1,1853 @@ +//! Serializing Rust structures into TOML. +//! +//! This module contains all the Serde support for serializing Rust structures +//! into TOML documents (as strings). Note that some top-level functions here +//! are also provided at the top of the crate. +//! +//! Note that the TOML format has a restriction that if a table itself contains +//! tables, all keys with non-table values must be emitted first. This is +//! typically easy to ensure happens when you're defining a `struct` as you can +//! reorder the fields manually, but when working with maps (such as `BTreeMap` +//! or `HashMap`) this can lead to serialization errors. In those situations you +//! may use the `tables_last` function in this module like so: +//! +//! ```rust +//! # use serde_derive::Serialize; +//! # use std::collections::HashMap; +//! #[derive(Serialize)] +//! struct Manifest { +//! package: Package, +//! #[serde(serialize_with = "toml::ser::tables_last")] +//! dependencies: HashMap<String, Dependency>, +//! } +//! # type Package = String; +//! # type Dependency = String; +//! # fn main() {} +//! ``` + +use std::cell::Cell; +use std::error; +use std::fmt::{self, Write}; +use std::marker; +use std::rc::Rc; + +use crate::datetime; +use serde::ser; + +/// Serialize the given data structure as a TOML byte vector. +/// +/// Serialization can fail if `T`'s implementation of `Serialize` decides to +/// fail, if `T` contains a map with non-string keys, or if `T` attempts to +/// serialize an unsupported datatype such as an enum, tuple, or tuple struct. +pub fn to_vec<T: ?Sized>(value: &T) -> Result<Vec<u8>, Error> +where + T: ser::Serialize, +{ + to_string(value).map(|e| e.into_bytes()) +} + +/// Serialize the given data structure as a String of TOML. +/// +/// Serialization can fail if `T`'s implementation of `Serialize` decides to +/// fail, if `T` contains a map with non-string keys, or if `T` attempts to +/// serialize an unsupported datatype such as an enum, tuple, or tuple struct. +/// +/// # Examples +/// +/// ``` +/// use serde_derive::Serialize; +/// +/// #[derive(Serialize)] +/// struct Config { +/// database: Database, +/// } +/// +/// #[derive(Serialize)] +/// struct Database { +/// ip: String, +/// port: Vec<u16>, +/// connection_max: u32, +/// enabled: bool, +/// } +/// +/// let config = Config { +/// database: Database { +/// ip: "192.168.1.1".to_string(), +/// port: vec![8001, 8002, 8003], +/// connection_max: 5000, +/// enabled: false, +/// }, +/// }; +/// +/// let toml = toml::to_string(&config).unwrap(); +/// println!("{}", toml) +/// ``` +pub fn to_string<T: ?Sized>(value: &T) -> Result<String, Error> +where + T: ser::Serialize, +{ + let mut dst = String::with_capacity(128); + value.serialize(&mut Serializer::new(&mut dst))?; + Ok(dst) +} + +/// Serialize the given data structure as a "pretty" String of TOML. +/// +/// This is identical to `to_string` except the output string has a more +/// "pretty" output. See `Serializer::pretty` for more details. +pub fn to_string_pretty<T: ?Sized>(value: &T) -> Result<String, Error> +where + T: ser::Serialize, +{ + let mut dst = String::with_capacity(128); + value.serialize(&mut Serializer::pretty(&mut dst))?; + Ok(dst) +} + +/// Errors that can occur when serializing a type. +#[derive(Debug, PartialEq, Eq, Clone)] +#[non_exhaustive] +pub enum Error { + /// Indicates that a Rust type was requested to be serialized but it was not + /// supported. + /// + /// Currently the TOML format does not support serializing types such as + /// enums, tuples and tuple structs. + UnsupportedType, + + /// The key of all TOML maps must be strings, but serialization was + /// attempted where the key of a map was not a string. + KeyNotString, + + /// An error that we never omit but keep for backwards compatibility + #[doc(hidden)] + KeyNewline, + + /// An array had to be homogeneous, but now it is allowed to be heterogeneous. + #[doc(hidden)] + ArrayMixedType, + + /// All values in a TOML table must be emitted before further tables are + /// emitted. If a value is emitted *after* a table then this error is + /// generated. + ValueAfterTable, + + /// A serialized date was invalid. + DateInvalid, + + /// A serialized number was invalid. + NumberInvalid, + + /// None was attempted to be serialized, but it's not supported. + UnsupportedNone, + + /// A custom error which could be generated when serializing a particular + /// type. + Custom(String), +} + +#[derive(Debug, Default, Clone)] +/// Internal place for holding array settings +struct ArraySettings { + indent: usize, + trailing_comma: bool, +} + +impl ArraySettings { + fn pretty() -> ArraySettings { + ArraySettings { + indent: 4, + trailing_comma: true, + } + } +} + +#[derive(Debug, Default, Clone)] +/// String settings +struct StringSettings { + /// Whether to use literal strings when possible + literal: bool, +} + +impl StringSettings { + fn pretty() -> StringSettings { + StringSettings { literal: true } + } +} + +#[derive(Debug, Default, Clone)] +/// Internal struct for holding serialization settings +struct Settings { + array: Option<ArraySettings>, + string: Option<StringSettings>, +} + +/// Serialization implementation for TOML. +/// +/// This structure implements serialization support for TOML to serialize an +/// arbitrary type to TOML. Note that the TOML format does not support all +/// datatypes in Rust, such as enums, tuples, and tuple structs. These types +/// will generate an error when serialized. +/// +/// Currently a serializer always writes its output to an in-memory `String`, +/// which is passed in when creating the serializer itself. +pub struct Serializer<'a> { + dst: &'a mut String, + state: State<'a>, + settings: Rc<Settings>, +} + +#[derive(Debug, Copy, Clone)] +enum ArrayState { + Started, + StartedAsATable, +} + +#[derive(Debug, Clone)] +enum State<'a> { + Table { + key: &'a str, + parent: &'a State<'a>, + first: &'a Cell<bool>, + table_emitted: &'a Cell<bool>, + }, + Array { + parent: &'a State<'a>, + first: &'a Cell<bool>, + type_: &'a Cell<Option<ArrayState>>, + len: Option<usize>, + }, + End, +} + +#[doc(hidden)] +pub struct SerializeSeq<'a, 'b> { + ser: &'b mut Serializer<'a>, + first: Cell<bool>, + type_: Cell<Option<ArrayState>>, + len: Option<usize>, +} + +#[doc(hidden)] +pub enum SerializeTable<'a, 'b> { + Datetime(&'b mut Serializer<'a>), + Table { + ser: &'b mut Serializer<'a>, + key: String, + first: Cell<bool>, + table_emitted: Cell<bool>, + }, +} + +impl<'a> Serializer<'a> { + /// Creates a new serializer which will emit TOML into the buffer provided. + /// + /// The serializer can then be used to serialize a type after which the data + /// will be present in `dst`. + pub fn new(dst: &'a mut String) -> Serializer<'a> { + Serializer { + dst, + state: State::End, + settings: Rc::new(Settings::default()), + } + } + + /// Instantiate a "pretty" formatter + /// + /// By default this will use: + /// + /// - pretty strings: strings with newlines will use the `'''` syntax. See + /// `Serializer::pretty_string` + /// - pretty arrays: each item in arrays will be on a newline, have an indentation of 4 and + /// have a trailing comma. See `Serializer::pretty_array` + pub fn pretty(dst: &'a mut String) -> Serializer<'a> { + Serializer { + dst, + state: State::End, + settings: Rc::new(Settings { + array: Some(ArraySettings::pretty()), + string: Some(StringSettings::pretty()), + }), + } + } + + /// Enable or Disable pretty strings + /// + /// If enabled, literal strings will be used when possible and strings with + /// one or more newlines will use triple quotes (i.e.: `'''` or `"""`) + /// + /// # Examples + /// + /// Instead of: + /// + /// ```toml,ignore + /// single = "no newlines" + /// text = "\nfoo\nbar\n" + /// ``` + /// + /// You will have: + /// + /// ```toml,ignore + /// single = 'no newlines' + /// text = ''' + /// foo + /// bar + /// ''' + /// ``` + pub fn pretty_string(&mut self, value: bool) -> &mut Self { + Rc::get_mut(&mut self.settings).unwrap().string = if value { + Some(StringSettings::pretty()) + } else { + None + }; + self + } + + /// Enable or Disable Literal strings for pretty strings + /// + /// If enabled, literal strings will be used when possible and strings with + /// one or more newlines will use triple quotes (i.e.: `'''` or `"""`) + /// + /// If disabled, literal strings will NEVER be used and strings with one or + /// more newlines will use `"""` + /// + /// # Examples + /// + /// Instead of: + /// + /// ```toml,ignore + /// single = "no newlines" + /// text = "\nfoo\nbar\n" + /// ``` + /// + /// You will have: + /// + /// ```toml,ignore + /// single = "no newlines" + /// text = """ + /// foo + /// bar + /// """ + /// ``` + pub fn pretty_string_literal(&mut self, value: bool) -> &mut Self { + let use_default = if let Some(ref mut s) = Rc::get_mut(&mut self.settings).unwrap().string { + s.literal = value; + false + } else { + true + }; + + if use_default { + let mut string = StringSettings::pretty(); + string.literal = value; + Rc::get_mut(&mut self.settings).unwrap().string = Some(string); + } + self + } + + /// Enable or Disable pretty arrays + /// + /// If enabled, arrays will always have each item on their own line. + /// + /// Some specific features can be controlled via other builder methods: + /// + /// - `Serializer::pretty_array_indent`: set the indent to a value other + /// than 4. + /// - `Serializer::pretty_array_trailing_comma`: enable/disable the trailing + /// comma on the last item. + /// + /// # Examples + /// + /// Instead of: + /// + /// ```toml,ignore + /// array = ["foo", "bar"] + /// ``` + /// + /// You will have: + /// + /// ```toml,ignore + /// array = [ + /// "foo", + /// "bar", + /// ] + /// ``` + pub fn pretty_array(&mut self, value: bool) -> &mut Self { + Rc::get_mut(&mut self.settings).unwrap().array = if value { + Some(ArraySettings::pretty()) + } else { + None + }; + self + } + + /// Set the indent for pretty arrays + /// + /// See `Serializer::pretty_array` for more details. + pub fn pretty_array_indent(&mut self, value: usize) -> &mut Self { + let use_default = if let Some(ref mut a) = Rc::get_mut(&mut self.settings).unwrap().array { + a.indent = value; + false + } else { + true + }; + + if use_default { + let mut array = ArraySettings::pretty(); + array.indent = value; + Rc::get_mut(&mut self.settings).unwrap().array = Some(array); + } + self + } + + /// Specify whether to use a trailing comma when serializing pretty arrays + /// + /// See `Serializer::pretty_array` for more details. + pub fn pretty_array_trailing_comma(&mut self, value: bool) -> &mut Self { + let use_default = if let Some(ref mut a) = Rc::get_mut(&mut self.settings).unwrap().array { + a.trailing_comma = value; + false + } else { + true + }; + + if use_default { + let mut array = ArraySettings::pretty(); + array.trailing_comma = value; + Rc::get_mut(&mut self.settings).unwrap().array = Some(array); + } + self + } + + fn display<T: fmt::Display>(&mut self, t: T, type_: ArrayState) -> Result<(), Error> { + self.emit_key(type_)?; + write!(self.dst, "{}", t).map_err(ser::Error::custom)?; + if let State::Table { .. } = self.state { + self.dst.push('\n'); + } + Ok(()) + } + + fn emit_key(&mut self, type_: ArrayState) -> Result<(), Error> { + self.array_type(type_)?; + let state = self.state.clone(); + self._emit_key(&state) + } + + // recursive implementation of `emit_key` above + fn _emit_key(&mut self, state: &State<'_>) -> Result<(), Error> { + match *state { + State::End => Ok(()), + State::Array { + parent, + first, + type_, + len, + } => { + assert!(type_.get().is_some()); + if first.get() { + self._emit_key(parent)?; + } + self.emit_array(first, len) + } + State::Table { + parent, + first, + table_emitted, + key, + } => { + if table_emitted.get() { + return Err(Error::ValueAfterTable); + } + if first.get() { + self.emit_table_header(parent)?; + first.set(false); + } + self.escape_key(key)?; + self.dst.push_str(" = "); + Ok(()) + } + } + } + + fn emit_array(&mut self, first: &Cell<bool>, len: Option<usize>) -> Result<(), Error> { + match (len, &self.settings.array) { + (Some(0..=1), _) | (_, &None) => { + if first.get() { + self.dst.push('[') + } else { + self.dst.push_str(", ") + } + } + (_, &Some(ref a)) => { + if first.get() { + self.dst.push_str("[\n") + } else { + self.dst.push_str(",\n") + } + for _ in 0..a.indent { + self.dst.push(' '); + } + } + } + Ok(()) + } + + fn array_type(&mut self, type_: ArrayState) -> Result<(), Error> { + let prev = match self.state { + State::Array { type_, .. } => type_, + _ => return Ok(()), + }; + if prev.get().is_none() { + prev.set(Some(type_)); + } + Ok(()) + } + + fn escape_key(&mut self, key: &str) -> Result<(), Error> { + let ok = !key.is_empty() + && key + .chars() + .all(|c| matches!(c,'a'..='z' | 'A'..='Z' | '0'..='9' | '-' | '_')); + if ok { + write!(self.dst, "{}", key).map_err(ser::Error::custom)?; + } else { + self.emit_str(key, true)?; + } + Ok(()) + } + + fn emit_str(&mut self, value: &str, is_key: bool) -> Result<(), Error> { + #[derive(PartialEq)] + enum Type { + NewlineTripple, + OnelineTripple, + OnelineSingle, + } + + enum Repr { + /// represent as a literal string (using '') + Literal(String, Type), + /// represent the std way (using "") + Std(Type), + } + + fn do_pretty(value: &str) -> Repr { + // For doing pretty prints we store in a new String + // because there are too many cases where pretty cannot + // work. We need to determine: + // - if we are a "multi-line" pretty (if there are \n) + // - if ['''] appears if multi or ['] if single + // - if there are any invalid control characters + // + // Doing it any other way would require multiple passes + // to determine if a pretty string works or not. + let mut out = String::with_capacity(value.len() * 2); + let mut ty = Type::OnelineSingle; + // found consecutive single quotes + let mut max_found_singles = 0; + let mut found_singles = 0; + let mut can_be_pretty = true; + + for ch in value.chars() { + if can_be_pretty { + if ch == '\'' { + found_singles += 1; + if found_singles >= 3 { + can_be_pretty = false; + } + } else { + if found_singles > max_found_singles { + max_found_singles = found_singles; + } + found_singles = 0 + } + match ch { + '\t' => {} + '\n' => ty = Type::NewlineTripple, + // Escape codes are needed if any ascii control + // characters are present, including \b \f \r. + c if c <= '\u{1f}' || c == '\u{7f}' => can_be_pretty = false, + _ => {} + } + out.push(ch); + } else { + // the string cannot be represented as pretty, + // still check if it should be multiline + if ch == '\n' { + ty = Type::NewlineTripple; + } + } + } + if can_be_pretty && found_singles > 0 && value.ends_with('\'') { + // We cannot escape the ending quote so we must use """ + can_be_pretty = false; + } + if !can_be_pretty { + debug_assert!(ty != Type::OnelineTripple); + return Repr::Std(ty); + } + if found_singles > max_found_singles { + max_found_singles = found_singles; + } + debug_assert!(max_found_singles < 3); + if ty == Type::OnelineSingle && max_found_singles >= 1 { + // no newlines, but must use ''' because it has ' in it + ty = Type::OnelineTripple; + } + Repr::Literal(out, ty) + } + + let repr = if !is_key && self.settings.string.is_some() { + match (&self.settings.string, do_pretty(value)) { + (&Some(StringSettings { literal: false, .. }), Repr::Literal(_, ty)) => { + Repr::Std(ty) + } + (_, r) => r, + } + } else { + Repr::Std(Type::OnelineSingle) + }; + match repr { + Repr::Literal(literal, ty) => { + // A pretty string + match ty { + Type::NewlineTripple => self.dst.push_str("'''\n"), + Type::OnelineTripple => self.dst.push_str("'''"), + Type::OnelineSingle => self.dst.push('\''), + } + self.dst.push_str(&literal); + match ty { + Type::OnelineSingle => self.dst.push('\''), + _ => self.dst.push_str("'''"), + } + } + Repr::Std(ty) => { + match ty { + Type::NewlineTripple => self.dst.push_str("\"\"\"\n"), + // note: OnelineTripple can happen if do_pretty wants to do + // '''it's one line''' + // but settings.string.literal == false + Type::OnelineSingle | Type::OnelineTripple => self.dst.push('"'), + } + for ch in value.chars() { + match ch { + '\u{8}' => self.dst.push_str("\\b"), + '\u{9}' => self.dst.push_str("\\t"), + '\u{a}' => match ty { + Type::NewlineTripple => self.dst.push('\n'), + Type::OnelineSingle => self.dst.push_str("\\n"), + _ => unreachable!(), + }, + '\u{c}' => self.dst.push_str("\\f"), + '\u{d}' => self.dst.push_str("\\r"), + '\u{22}' => self.dst.push_str("\\\""), + '\u{5c}' => self.dst.push_str("\\\\"), + c if c <= '\u{1f}' || c == '\u{7f}' => { + write!(self.dst, "\\u{:04X}", ch as u32).map_err(ser::Error::custom)?; + } + ch => self.dst.push(ch), + } + } + match ty { + Type::NewlineTripple => self.dst.push_str("\"\"\""), + Type::OnelineSingle | Type::OnelineTripple => self.dst.push('"'), + } + } + } + Ok(()) + } + + fn emit_table_header(&mut self, state: &State<'_>) -> Result<(), Error> { + let array_of_tables = match *state { + State::End => return Ok(()), + State::Array { .. } => true, + _ => false, + }; + + // Unlike [..]s, we can't omit [[..]] ancestors, so be sure to emit table + // headers for them. + let mut p = state; + if let State::Array { first, parent, .. } = *state { + if first.get() { + p = parent; + } + } + while let State::Table { first, parent, .. } = *p { + p = parent; + if !first.get() { + break; + } + if let State::Array { + parent: &State::Table { .. }, + .. + } = *parent + { + self.emit_table_header(parent)?; + break; + } + } + + match *state { + State::Table { first, .. } => { + if !first.get() { + // Newline if we are a table that is not the first + // table in the document. + self.dst.push('\n'); + } + } + State::Array { parent, first, .. } => { + if !first.get() { + // Always newline if we are not the first item in the + // table-array + self.dst.push('\n'); + } else if let State::Table { first, .. } = *parent { + if !first.get() { + // Newline if we are not the first item in the document + self.dst.push('\n'); + } + } + } + _ => {} + } + self.dst.push('['); + if array_of_tables { + self.dst.push('['); + } + self.emit_key_part(state)?; + if array_of_tables { + self.dst.push(']'); + } + self.dst.push_str("]\n"); + Ok(()) + } + + fn emit_key_part(&mut self, key: &State<'_>) -> Result<bool, Error> { + match *key { + State::Array { parent, .. } => self.emit_key_part(parent), + State::End => Ok(true), + State::Table { + key, + parent, + table_emitted, + .. + } => { + table_emitted.set(true); + let first = self.emit_key_part(parent)?; + if !first { + self.dst.push('.'); + } + self.escape_key(key)?; + Ok(false) + } + } + } +} + +macro_rules! serialize_float { + ($this:expr, $v:expr) => {{ + $this.emit_key(ArrayState::Started)?; + match ($v.is_sign_negative(), $v.is_nan(), $v == 0.0) { + (true, true, _) => write!($this.dst, "-nan"), + (false, true, _) => write!($this.dst, "nan"), + (true, false, true) => write!($this.dst, "-0.0"), + (false, false, true) => write!($this.dst, "0.0"), + (_, false, false) => write!($this.dst, "{}", $v).and_then(|_| { + if $v % 1.0 == 0.0 { + write!($this.dst, ".0") + } else { + Ok(()) + } + }), + } + .map_err(ser::Error::custom)?; + + if let State::Table { .. } = $this.state { + $this.dst.push_str("\n"); + } + return Ok(()); + }}; +} + +impl<'a, 'b> ser::Serializer for &'b mut Serializer<'a> { + type Ok = (); + type Error = Error; + type SerializeSeq = SerializeSeq<'a, 'b>; + type SerializeTuple = SerializeSeq<'a, 'b>; + type SerializeTupleStruct = SerializeSeq<'a, 'b>; + type SerializeTupleVariant = SerializeSeq<'a, 'b>; + type SerializeMap = SerializeTable<'a, 'b>; + type SerializeStruct = SerializeTable<'a, 'b>; + type SerializeStructVariant = ser::Impossible<(), Error>; + + fn serialize_bool(self, v: bool) -> Result<(), Self::Error> { + self.display(v, ArrayState::Started) + } + + fn serialize_i8(self, v: i8) -> Result<(), Self::Error> { + self.display(v, ArrayState::Started) + } + + fn serialize_i16(self, v: i16) -> Result<(), Self::Error> { + self.display(v, ArrayState::Started) + } + + fn serialize_i32(self, v: i32) -> Result<(), Self::Error> { + self.display(v, ArrayState::Started) + } + + fn serialize_i64(self, v: i64) -> Result<(), Self::Error> { + self.display(v, ArrayState::Started) + } + + fn serialize_u8(self, v: u8) -> Result<(), Self::Error> { + self.display(v, ArrayState::Started) + } + + fn serialize_u16(self, v: u16) -> Result<(), Self::Error> { + self.display(v, ArrayState::Started) + } + + fn serialize_u32(self, v: u32) -> Result<(), Self::Error> { + self.display(v, ArrayState::Started) + } + + fn serialize_u64(self, v: u64) -> Result<(), Self::Error> { + self.display(v, ArrayState::Started) + } + + fn serialize_f32(self, v: f32) -> Result<(), Self::Error> { + serialize_float!(self, v) + } + + fn serialize_f64(self, v: f64) -> Result<(), Self::Error> { + serialize_float!(self, v) + } + + fn serialize_char(self, v: char) -> Result<(), Self::Error> { + let mut buf = [0; 4]; + self.serialize_str(v.encode_utf8(&mut buf)) + } + + fn serialize_str(self, value: &str) -> Result<(), Self::Error> { + self.emit_key(ArrayState::Started)?; + self.emit_str(value, false)?; + if let State::Table { .. } = self.state { + self.dst.push('\n'); + } + Ok(()) + } + + fn serialize_bytes(self, value: &[u8]) -> Result<(), Self::Error> { + use serde::ser::Serialize; + value.serialize(self) + } + + fn serialize_none(self) -> Result<(), Self::Error> { + Err(Error::UnsupportedNone) + } + + fn serialize_some<T: ?Sized>(self, value: &T) -> Result<(), Self::Error> + where + T: ser::Serialize, + { + value.serialize(self) + } + + fn serialize_unit(self) -> Result<(), Self::Error> { + Err(Error::UnsupportedType) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result<(), Self::Error> { + Err(Error::UnsupportedType) + } + + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + ) -> Result<(), Self::Error> { + self.serialize_str(variant) + } + + fn serialize_newtype_struct<T: ?Sized>( + self, + _name: &'static str, + value: &T, + ) -> Result<(), Self::Error> + where + T: ser::Serialize, + { + value.serialize(self) + } + + fn serialize_newtype_variant<T: ?Sized>( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> Result<(), Self::Error> + where + T: ser::Serialize, + { + Err(Error::UnsupportedType) + } + + fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> { + self.array_type(ArrayState::Started)?; + Ok(SerializeSeq { + ser: self, + first: Cell::new(true), + type_: Cell::new(None), + len, + }) + } + + fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> { + self.serialize_seq(Some(len)) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + len: usize, + ) -> Result<Self::SerializeTupleStruct, Self::Error> { + self.serialize_seq(Some(len)) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + len: usize, + ) -> Result<Self::SerializeTupleVariant, Self::Error> { + self.serialize_seq(Some(len)) + } + + fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> { + self.array_type(ArrayState::StartedAsATable)?; + Ok(SerializeTable::Table { + ser: self, + key: String::new(), + first: Cell::new(true), + table_emitted: Cell::new(false), + }) + } + + fn serialize_struct( + self, + name: &'static str, + _len: usize, + ) -> Result<Self::SerializeStruct, Self::Error> { + if name == datetime::NAME { + self.array_type(ArrayState::Started)?; + Ok(SerializeTable::Datetime(self)) + } else { + self.array_type(ArrayState::StartedAsATable)?; + Ok(SerializeTable::Table { + ser: self, + key: String::new(), + first: Cell::new(true), + table_emitted: Cell::new(false), + }) + } + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result<Self::SerializeStructVariant, Self::Error> { + Err(Error::UnsupportedType) + } +} + +impl<'a, 'b> ser::SerializeSeq for SerializeSeq<'a, 'b> { + type Ok = (); + type Error = Error; + + fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Error> + where + T: ser::Serialize, + { + value.serialize(&mut Serializer { + dst: &mut *self.ser.dst, + state: State::Array { + parent: &self.ser.state, + first: &self.first, + type_: &self.type_, + len: self.len, + }, + settings: self.ser.settings.clone(), + })?; + self.first.set(false); + Ok(()) + } + + fn end(self) -> Result<(), Error> { + match self.type_.get() { + Some(ArrayState::StartedAsATable) => return Ok(()), + Some(ArrayState::Started) => match (self.len, &self.ser.settings.array) { + (Some(0..=1), _) | (_, &None) => { + self.ser.dst.push(']'); + } + (_, &Some(ref a)) => { + if a.trailing_comma { + self.ser.dst.push(','); + } + self.ser.dst.push_str("\n]"); + } + }, + None => { + assert!(self.first.get()); + self.ser.emit_key(ArrayState::Started)?; + self.ser.dst.push_str("[]") + } + } + if let State::Table { .. } = self.ser.state { + self.ser.dst.push('\n'); + } + Ok(()) + } +} + +impl<'a, 'b> ser::SerializeTuple for SerializeSeq<'a, 'b> { + type Ok = (); + type Error = Error; + + fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Error> + where + T: ser::Serialize, + { + ser::SerializeSeq::serialize_element(self, value) + } + + fn end(self) -> Result<(), Error> { + ser::SerializeSeq::end(self) + } +} + +impl<'a, 'b> ser::SerializeTupleVariant for SerializeSeq<'a, 'b> { + type Ok = (); + type Error = Error; + + fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Error> + where + T: ser::Serialize, + { + ser::SerializeSeq::serialize_element(self, value) + } + + fn end(self) -> Result<(), Error> { + ser::SerializeSeq::end(self) + } +} + +impl<'a, 'b> ser::SerializeTupleStruct for SerializeSeq<'a, 'b> { + type Ok = (); + type Error = Error; + + fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Error> + where + T: ser::Serialize, + { + ser::SerializeSeq::serialize_element(self, value) + } + + fn end(self) -> Result<(), Error> { + ser::SerializeSeq::end(self) + } +} + +impl<'a, 'b> ser::SerializeMap for SerializeTable<'a, 'b> { + type Ok = (); + type Error = Error; + + fn serialize_key<T: ?Sized>(&mut self, input: &T) -> Result<(), Error> + where + T: ser::Serialize, + { + match *self { + SerializeTable::Datetime(_) => panic!(), // shouldn't be possible + SerializeTable::Table { ref mut key, .. } => { + key.truncate(0); + *key = input.serialize(StringExtractor)?; + } + } + Ok(()) + } + + fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Error> + where + T: ser::Serialize, + { + match *self { + SerializeTable::Datetime(_) => panic!(), // shouldn't be possible + SerializeTable::Table { + ref mut ser, + ref key, + ref first, + ref table_emitted, + .. + } => { + let res = value.serialize(&mut Serializer { + dst: &mut *ser.dst, + state: State::Table { + key, + parent: &ser.state, + first, + table_emitted, + }, + settings: ser.settings.clone(), + }); + match res { + Ok(()) => first.set(false), + Err(Error::UnsupportedNone) => {} + Err(e) => return Err(e), + } + } + } + Ok(()) + } + + fn end(self) -> Result<(), Error> { + match self { + SerializeTable::Datetime(_) => panic!(), // shouldn't be possible + SerializeTable::Table { ser, first, .. } => { + if first.get() { + let state = ser.state.clone(); + ser.emit_table_header(&state)?; + } + } + } + Ok(()) + } +} + +impl<'a, 'b> ser::SerializeStruct for SerializeTable<'a, 'b> { + type Ok = (); + type Error = Error; + + fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), Error> + where + T: ser::Serialize, + { + match *self { + SerializeTable::Datetime(ref mut ser) => { + if key == datetime::FIELD { + value.serialize(DateStrEmitter(*ser))?; + } else { + return Err(Error::DateInvalid); + } + } + SerializeTable::Table { + ref mut ser, + ref first, + ref table_emitted, + .. + } => { + let res = value.serialize(&mut Serializer { + dst: &mut *ser.dst, + state: State::Table { + key, + parent: &ser.state, + first, + table_emitted, + }, + settings: ser.settings.clone(), + }); + match res { + Ok(()) => first.set(false), + Err(Error::UnsupportedNone) => {} + Err(e) => return Err(e), + } + } + } + Ok(()) + } + + fn end(self) -> Result<(), Error> { + match self { + SerializeTable::Datetime(_) => {} + SerializeTable::Table { ser, first, .. } => { + if first.get() { + let state = ser.state.clone(); + ser.emit_table_header(&state)?; + } + } + } + Ok(()) + } +} + +struct DateStrEmitter<'a, 'b>(&'b mut Serializer<'a>); + +impl<'a, 'b> ser::Serializer for DateStrEmitter<'a, 'b> { + type Ok = (); + type Error = Error; + type SerializeSeq = ser::Impossible<(), Error>; + type SerializeTuple = ser::Impossible<(), Error>; + type SerializeTupleStruct = ser::Impossible<(), Error>; + type SerializeTupleVariant = ser::Impossible<(), Error>; + type SerializeMap = ser::Impossible<(), Error>; + type SerializeStruct = ser::Impossible<(), Error>; + type SerializeStructVariant = ser::Impossible<(), Error>; + + fn serialize_bool(self, _v: bool) -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_i8(self, _v: i8) -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_i16(self, _v: i16) -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_i32(self, _v: i32) -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_i64(self, _v: i64) -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_u8(self, _v: u8) -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_u16(self, _v: u16) -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_u32(self, _v: u32) -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_u64(self, _v: u64) -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_f32(self, _v: f32) -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_f64(self, _v: f64) -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_char(self, _v: char) -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_str(self, value: &str) -> Result<(), Self::Error> { + self.0.display(value, ArrayState::Started)?; + Ok(()) + } + + fn serialize_bytes(self, _value: &[u8]) -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_none(self) -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_some<T: ?Sized>(self, _value: &T) -> Result<(), Self::Error> + where + T: ser::Serialize, + { + Err(Error::DateInvalid) + } + + fn serialize_unit(self) -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + ) -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_newtype_struct<T: ?Sized>( + self, + _name: &'static str, + _value: &T, + ) -> Result<(), Self::Error> + where + T: ser::Serialize, + { + Err(Error::DateInvalid) + } + + fn serialize_newtype_variant<T: ?Sized>( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> Result<(), Self::Error> + where + T: ser::Serialize, + { + Err(Error::DateInvalid) + } + + fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result<Self::SerializeTupleStruct, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result<Self::SerializeTupleVariant, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result<Self::SerializeStruct, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result<Self::SerializeStructVariant, Self::Error> { + Err(Error::DateInvalid) + } +} + +struct StringExtractor; + +impl ser::Serializer for StringExtractor { + type Ok = String; + type Error = Error; + type SerializeSeq = ser::Impossible<String, Error>; + type SerializeTuple = ser::Impossible<String, Error>; + type SerializeTupleStruct = ser::Impossible<String, Error>; + type SerializeTupleVariant = ser::Impossible<String, Error>; + type SerializeMap = ser::Impossible<String, Error>; + type SerializeStruct = ser::Impossible<String, Error>; + type SerializeStructVariant = ser::Impossible<String, Error>; + + fn serialize_bool(self, _v: bool) -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_i8(self, _v: i8) -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_i16(self, _v: i16) -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_i32(self, _v: i32) -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_i64(self, _v: i64) -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_u8(self, _v: u8) -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_u16(self, _v: u16) -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_u32(self, _v: u32) -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_u64(self, _v: u64) -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_f32(self, _v: f32) -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_f64(self, _v: f64) -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_char(self, _v: char) -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_str(self, value: &str) -> Result<String, Self::Error> { + Ok(value.to_string()) + } + + fn serialize_bytes(self, _value: &[u8]) -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_none(self) -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_some<T: ?Sized>(self, _value: &T) -> Result<String, Self::Error> + where + T: ser::Serialize, + { + Err(Error::KeyNotString) + } + + fn serialize_unit(self) -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + ) -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_newtype_struct<T: ?Sized>( + self, + _name: &'static str, + value: &T, + ) -> Result<String, Self::Error> + where + T: ser::Serialize, + { + value.serialize(self) + } + + fn serialize_newtype_variant<T: ?Sized>( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> Result<String, Self::Error> + where + T: ser::Serialize, + { + Err(Error::KeyNotString) + } + + fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result<Self::SerializeTupleStruct, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result<Self::SerializeTupleVariant, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result<Self::SerializeStruct, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result<Self::SerializeStructVariant, Self::Error> { + Err(Error::KeyNotString) + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Error::UnsupportedType => "unsupported Rust type".fmt(f), + Error::KeyNotString => "map key was not a string".fmt(f), + Error::ValueAfterTable => "values must be emitted before tables".fmt(f), + Error::DateInvalid => "a serialized date was invalid".fmt(f), + Error::NumberInvalid => "a serialized number was invalid".fmt(f), + Error::UnsupportedNone => "unsupported None value".fmt(f), + Error::Custom(ref s) => s.fmt(f), + Error::KeyNewline => unreachable!(), + Error::ArrayMixedType => unreachable!(), + } + } +} + +impl error::Error for Error {} + +impl ser::Error for Error { + fn custom<T: fmt::Display>(msg: T) -> Error { + Error::Custom(msg.to_string()) + } +} + +enum Category { + Primitive, + Array, + Table, +} + +/// Convenience function to serialize items in a map in an order valid with +/// TOML. +/// +/// TOML carries the restriction that keys in a table must be serialized last if +/// their value is a table itself. This isn't always easy to guarantee, so this +/// helper can be used like so: +/// +/// ```rust +/// # use serde_derive::Serialize; +/// # use std::collections::HashMap; +/// #[derive(Serialize)] +/// struct Manifest { +/// package: Package, +/// #[serde(serialize_with = "toml::ser::tables_last")] +/// dependencies: HashMap<String, Dependency>, +/// } +/// # type Package = String; +/// # type Dependency = String; +/// # fn main() {} +/// ``` +pub fn tables_last<'a, I, K, V, S>(data: &'a I, serializer: S) -> Result<S::Ok, S::Error> +where + &'a I: IntoIterator<Item = (K, V)>, + K: ser::Serialize, + V: ser::Serialize, + S: ser::Serializer, +{ + use serde::ser::SerializeMap; + + let mut map = serializer.serialize_map(None)?; + for (k, v) in data { + if let Category::Primitive = v.serialize(Categorize::new())? { + map.serialize_entry(&k, &v)?; + } + } + for (k, v) in data { + if let Category::Array = v.serialize(Categorize::new())? { + map.serialize_entry(&k, &v)?; + } + } + for (k, v) in data { + if let Category::Table = v.serialize(Categorize::new())? { + map.serialize_entry(&k, &v)?; + } + } + map.end() +} + +struct Categorize<E>(marker::PhantomData<E>); + +impl<E> Categorize<E> { + fn new() -> Self { + Categorize(marker::PhantomData) + } +} + +impl<E: ser::Error> ser::Serializer for Categorize<E> { + type Ok = Category; + type Error = E; + type SerializeSeq = Self; + type SerializeTuple = Self; + type SerializeTupleStruct = Self; + type SerializeTupleVariant = Self; + type SerializeMap = Self; + type SerializeStruct = Self; + type SerializeStructVariant = ser::Impossible<Category, E>; + + fn serialize_bool(self, _: bool) -> Result<Self::Ok, Self::Error> { + Ok(Category::Primitive) + } + + fn serialize_i8(self, _: i8) -> Result<Self::Ok, Self::Error> { + Ok(Category::Primitive) + } + + fn serialize_i16(self, _: i16) -> Result<Self::Ok, Self::Error> { + Ok(Category::Primitive) + } + + fn serialize_i32(self, _: i32) -> Result<Self::Ok, Self::Error> { + Ok(Category::Primitive) + } + + fn serialize_i64(self, _: i64) -> Result<Self::Ok, Self::Error> { + Ok(Category::Primitive) + } + + fn serialize_u8(self, _: u8) -> Result<Self::Ok, Self::Error> { + Ok(Category::Primitive) + } + + fn serialize_u16(self, _: u16) -> Result<Self::Ok, Self::Error> { + Ok(Category::Primitive) + } + + fn serialize_u32(self, _: u32) -> Result<Self::Ok, Self::Error> { + Ok(Category::Primitive) + } + + fn serialize_u64(self, _: u64) -> Result<Self::Ok, Self::Error> { + Ok(Category::Primitive) + } + + fn serialize_f32(self, _: f32) -> Result<Self::Ok, Self::Error> { + Ok(Category::Primitive) + } + + fn serialize_f64(self, _: f64) -> Result<Self::Ok, Self::Error> { + Ok(Category::Primitive) + } + + fn serialize_char(self, _: char) -> Result<Self::Ok, Self::Error> { + Ok(Category::Primitive) + } + + fn serialize_str(self, _: &str) -> Result<Self::Ok, Self::Error> { + Ok(Category::Primitive) + } + + fn serialize_bytes(self, _: &[u8]) -> Result<Self::Ok, Self::Error> { + Ok(Category::Array) + } + + fn serialize_none(self) -> Result<Self::Ok, Self::Error> { + Err(ser::Error::custom("unsupported")) + } + + fn serialize_some<T: ?Sized + ser::Serialize>(self, v: &T) -> Result<Self::Ok, Self::Error> { + v.serialize(self) + } + + fn serialize_unit(self) -> Result<Self::Ok, Self::Error> { + Err(ser::Error::custom("unsupported")) + } + + fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> { + Err(ser::Error::custom("unsupported")) + } + + fn serialize_unit_variant( + self, + _: &'static str, + _: u32, + _: &'static str, + ) -> Result<Self::Ok, Self::Error> { + Err(ser::Error::custom("unsupported")) + } + + fn serialize_newtype_struct<T: ?Sized + ser::Serialize>( + self, + _: &'static str, + v: &T, + ) -> Result<Self::Ok, Self::Error> { + v.serialize(self) + } + + fn serialize_newtype_variant<T: ?Sized + ser::Serialize>( + self, + _: &'static str, + _: u32, + _: &'static str, + _: &T, + ) -> Result<Self::Ok, Self::Error> { + Err(ser::Error::custom("unsupported")) + } + + fn serialize_seq(self, _: Option<usize>) -> Result<Self, Self::Error> { + Ok(self) + } + + fn serialize_tuple(self, _: usize) -> Result<Self::SerializeTuple, Self::Error> { + Ok(self) + } + + fn serialize_tuple_struct( + self, + _: &'static str, + _: usize, + ) -> Result<Self::SerializeTupleStruct, Self::Error> { + Ok(self) + } + + fn serialize_tuple_variant( + self, + _: &'static str, + _: u32, + _: &'static str, + _: usize, + ) -> Result<Self::SerializeTupleVariant, Self::Error> { + Ok(self) + } + + fn serialize_map(self, _: Option<usize>) -> Result<Self, Self::Error> { + Ok(self) + } + + fn serialize_struct(self, _: &'static str, _: usize) -> Result<Self, Self::Error> { + Ok(self) + } + + fn serialize_struct_variant( + self, + _: &'static str, + _: u32, + _: &'static str, + _: usize, + ) -> Result<Self::SerializeStructVariant, Self::Error> { + Err(ser::Error::custom("unsupported")) + } +} + +impl<E: ser::Error> ser::SerializeSeq for Categorize<E> { + type Ok = Category; + type Error = E; + + fn serialize_element<T: ?Sized + ser::Serialize>(&mut self, _: &T) -> Result<(), Self::Error> { + Ok(()) + } + + fn end(self) -> Result<Self::Ok, Self::Error> { + Ok(Category::Array) + } +} + +impl<E: ser::Error> ser::SerializeTuple for Categorize<E> { + type Ok = Category; + type Error = E; + + fn serialize_element<T: ?Sized + ser::Serialize>(&mut self, _: &T) -> Result<(), Self::Error> { + Ok(()) + } + + fn end(self) -> Result<Self::Ok, Self::Error> { + Ok(Category::Array) + } +} + +impl<E: ser::Error> ser::SerializeTupleVariant for Categorize<E> { + type Ok = Category; + type Error = E; + + fn serialize_field<T: ?Sized + ser::Serialize>(&mut self, _: &T) -> Result<(), Self::Error> { + Ok(()) + } + + fn end(self) -> Result<Self::Ok, Self::Error> { + Ok(Category::Array) + } +} + +impl<E: ser::Error> ser::SerializeTupleStruct for Categorize<E> { + type Ok = Category; + type Error = E; + + fn serialize_field<T: ?Sized + ser::Serialize>(&mut self, _: &T) -> Result<(), Self::Error> { + Ok(()) + } + + fn end(self) -> Result<Self::Ok, Self::Error> { + Ok(Category::Array) + } +} + +impl<E: ser::Error> ser::SerializeMap for Categorize<E> { + type Ok = Category; + type Error = E; + + fn serialize_key<T: ?Sized + ser::Serialize>(&mut self, _: &T) -> Result<(), Self::Error> { + Ok(()) + } + + fn serialize_value<T: ?Sized + ser::Serialize>(&mut self, _: &T) -> Result<(), Self::Error> { + Ok(()) + } + + fn end(self) -> Result<Self::Ok, Self::Error> { + Ok(Category::Table) + } +} + +impl<E: ser::Error> ser::SerializeStruct for Categorize<E> { + type Ok = Category; + type Error = E; + + fn serialize_field<T: ?Sized>(&mut self, _: &'static str, _: &T) -> Result<(), Self::Error> + where + T: ser::Serialize, + { + Ok(()) + } + + fn end(self) -> Result<Self::Ok, Self::Error> { + Ok(Category::Table) + } +} |