summaryrefslogtreecommitdiffstats
path: root/third_party/rust/toml/src/ser.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/toml/src/ser.rs')
-rw-r--r--third_party/rust/toml/src/ser.rs1853
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)
+ }
+}