use serde::ser::{self, Serialize}; use std::cell::Cell; use std::error; use std::fmt::{self, Display, Write}; /// 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. pub fn to_string(value: &T) -> Result where T: Serialize, { let mut dst = String::with_capacity(128); value.serialize(&mut Serializer::new(&mut dst))?; Ok(dst) } #[derive(Debug)] pub(crate) 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, /// 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, /// 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), } struct Serializer<'a> { dst: &'a mut String, state: State<'a>, } #[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, table_emitted: &'a Cell, }, Array { parent: &'a State<'a>, first: &'a Cell, type_: &'a Cell>, len: Option, }, End, } struct SerializeSeq<'a, 'b> { ser: &'b mut Serializer<'a>, first: Cell, type_: Cell>, len: Option, } struct SerializeTable<'a, 'b> { ser: &'b mut Serializer<'a>, key: String, first: Cell, table_emitted: Cell, } impl<'a> Serializer<'a> { fn new(dst: &'a mut String) -> Serializer<'a> { Serializer { dst, state: State::End, } } fn 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); Ok(()) } 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, _len: Option) { if first.get() { self.dst.push('['); } else { self.dst.push_str(", "); } } fn array_type(&mut self, type_: ArrayState) { let prev = match self.state { State::Array { type_, .. } => type_, _ => return, }; if prev.get().is_none() { prev.set(Some(type_)); } } fn escape_key(&mut self, key: &str) -> Result<(), Error> { let ok = !key.is_empty() && key.chars().all(|c| match c { 'a'..='z' | 'A'..='Z' | '0'..='9' | '-' | '_' => true, _ => false, }); if ok { write!(self.dst, "{}", key).map_err(ser::Error::custom)?; } else { self.emit_str(key)?; } Ok(()) } fn emit_str(&mut self, value: &str) -> Result<(), Error> { 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}' => self.dst.push_str("\\n"), '\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), } } 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, State::Table { .. } => 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'); } } } State::End => {} } 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 { 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 = ser::Impossible<(), Error>; 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)?; if let State::Table { .. } = self.state { self.dst.push('\n'); } Ok(()) } fn serialize_bytes(self, value: &[u8]) -> Result<(), Self::Error> { value.serialize(self) } fn serialize_none(self) -> Result<(), Self::Error> { Err(Error::UnsupportedNone) } fn serialize_some(self, value: &T) -> Result<(), Self::Error> where T: 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( self, _name: &'static str, value: &T, ) -> Result<(), Self::Error> where T: Serialize, { value.serialize(self) } fn serialize_newtype_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _value: &T, ) -> Result<(), Self::Error> where T: Serialize, { Err(Error::UnsupportedType) } fn serialize_seq(self, len: Option) -> Result { 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.serialize_seq(Some(len)) } fn serialize_tuple_struct( self, _name: &'static str, len: usize, ) -> Result { self.serialize_seq(Some(len)) } fn serialize_tuple_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize, ) -> Result { Err(Error::UnsupportedType) } fn serialize_map(self, _len: Option) -> Result { self.array_type(ArrayState::StartedAsATable); Ok(SerializeTable { 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.array_type(ArrayState::StartedAsATable); Ok(SerializeTable { 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 { Err(Error::UnsupportedType) } } impl<'a, 'b> ser::SerializeSeq for SerializeSeq<'a, 'b> { type Ok = (); type Error = Error; fn serialize_element(&mut self, value: &T) -> Result<(), Error> where T: 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, }, })?; self.first.set(false); Ok(()) } fn end(self) -> Result<(), Error> { match self.type_.get() { Some(ArrayState::StartedAsATable) => return Ok(()), Some(ArrayState::Started) => self.ser.dst.push(']'), 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(&mut self, value: &T) -> Result<(), Error> where T: 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(&mut self, value: &T) -> Result<(), Error> where T: 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(&mut self, input: &T) -> Result<(), Error> where T: Serialize, { self.key = input.serialize(StringExtractor)?; Ok(()) } fn serialize_value(&mut self, value: &T) -> Result<(), Error> where T: Serialize, { let res = value.serialize(&mut Serializer { dst: &mut *self.ser.dst, state: State::Table { key: &self.key, parent: &self.ser.state, first: &self.first, table_emitted: &self.table_emitted, }, }); match res { Ok(()) => self.first.set(false), Err(Error::UnsupportedNone) => {} Err(e) => return Err(e), } Ok(()) } fn end(self) -> Result<(), Error> { if self.first.get() { let state = self.ser.state.clone(); self.ser.emit_table_header(&state)?; } Ok(()) } } impl<'a, 'b> ser::SerializeStruct for SerializeTable<'a, 'b> { type Ok = (); type Error = Error; fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> where T: Serialize, { let res = value.serialize(&mut Serializer { dst: &mut *self.ser.dst, state: State::Table { key, parent: &self.ser.state, first: &self.first, table_emitted: &self.table_emitted, }, }); match res { Ok(()) => self.first.set(false), Err(Error::UnsupportedNone) => {} Err(e) => return Err(e), } Ok(()) } fn end(self) -> Result<(), Error> { if self.first.get() { let state = self.ser.state.clone(); self.ser.emit_table_header(&state)?; } Ok(()) } } struct StringExtractor; impl ser::Serializer for StringExtractor { type Ok = String; type Error = Error; type SerializeSeq = ser::Impossible; type SerializeTuple = ser::Impossible; type SerializeTupleStruct = ser::Impossible; type SerializeTupleVariant = ser::Impossible; type SerializeMap = ser::Impossible; type SerializeStruct = ser::Impossible; type SerializeStructVariant = ser::Impossible; fn serialize_bool(self, _v: bool) -> Result { Err(Error::KeyNotString) } fn serialize_i8(self, _v: i8) -> Result { Err(Error::KeyNotString) } fn serialize_i16(self, _v: i16) -> Result { Err(Error::KeyNotString) } fn serialize_i32(self, _v: i32) -> Result { Err(Error::KeyNotString) } fn serialize_i64(self, _v: i64) -> Result { Err(Error::KeyNotString) } fn serialize_u8(self, _v: u8) -> Result { Err(Error::KeyNotString) } fn serialize_u16(self, _v: u16) -> Result { Err(Error::KeyNotString) } fn serialize_u32(self, _v: u32) -> Result { Err(Error::KeyNotString) } fn serialize_u64(self, _v: u64) -> Result { Err(Error::KeyNotString) } fn serialize_f32(self, _v: f32) -> Result { Err(Error::KeyNotString) } fn serialize_f64(self, _v: f64) -> Result { Err(Error::KeyNotString) } fn serialize_char(self, _v: char) -> Result { Err(Error::KeyNotString) } fn serialize_str(self, value: &str) -> Result { Ok(value.to_string()) } fn serialize_bytes(self, _value: &[u8]) -> Result { Err(Error::KeyNotString) } fn serialize_none(self) -> Result { Err(Error::KeyNotString) } fn serialize_some(self, _value: &T) -> Result where T: Serialize, { Err(Error::KeyNotString) } fn serialize_unit(self) -> Result { Err(Error::KeyNotString) } fn serialize_unit_struct(self, _name: &'static str) -> Result { Err(Error::KeyNotString) } fn serialize_unit_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, ) -> Result { Err(Error::KeyNotString) } fn serialize_newtype_struct( self, _name: &'static str, value: &T, ) -> Result where T: Serialize, { value.serialize(self) } fn serialize_newtype_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _value: &T, ) -> Result where T: Serialize, { Err(Error::KeyNotString) } fn serialize_seq(self, _len: Option) -> Result { Err(Error::KeyNotString) } fn serialize_tuple(self, _len: usize) -> Result { Err(Error::KeyNotString) } fn serialize_tuple_struct( self, _name: &'static str, _len: usize, ) -> Result { Err(Error::KeyNotString) } fn serialize_tuple_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize, ) -> Result { Err(Error::KeyNotString) } fn serialize_map(self, _len: Option) -> Result { Err(Error::KeyNotString) } fn serialize_struct( self, _name: &'static str, _len: usize, ) -> Result { Err(Error::KeyNotString) } fn serialize_struct_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize, ) -> Result { Err(Error::KeyNotString) } } impl 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::UnsupportedNone => "unsupported None value".fmt(f), Error::Custom(ref s) => s.fmt(f), } } } impl error::Error for Error {} impl ser::Error for Error { fn custom(msg: T) -> Error { Error::Custom(msg.to_string()) } }