use alloc::{borrow::Cow, string::String}; use core::fmt; use serde::{ser, ser::Serialize}; use serde_derive::{Deserialize, Serialize}; use unicode_ident::is_xid_continue; use crate::{ error::{Error, Result}, extensions::Extensions, options::Options, parse::{is_ident_first_char, is_ident_raw_char, is_whitespace_char, LargeSInt, LargeUInt}, }; pub mod path_meta; mod raw; #[cfg(test)] mod tests; mod value; /// Serializes `value` into `writer`. /// /// This function does not generate any newlines or nice formatting; /// if you want that, you can use [`to_writer_pretty`] instead. pub fn to_writer(writer: W, value: &T) -> Result<()> where W: fmt::Write, T: ?Sized + Serialize, { Options::default().to_writer(writer, value) } /// Serializes `value` into `writer` in a pretty way. pub fn to_writer_pretty(writer: W, value: &T, config: PrettyConfig) -> Result<()> where W: fmt::Write, T: ?Sized + Serialize, { Options::default().to_writer_pretty(writer, value, config) } /// Serializes `value` and returns it as string. /// /// This function does not generate any newlines or nice formatting; /// if you want that, you can use [`to_string_pretty`] instead. pub fn to_string(value: &T) -> Result where T: ?Sized + Serialize, { Options::default().to_string(value) } /// Serializes `value` in the recommended RON layout in a pretty way. pub fn to_string_pretty(value: &T, config: PrettyConfig) -> Result where T: ?Sized + Serialize, { Options::default().to_string_pretty(value, config) } /// Pretty serializer state struct Pretty { indent: usize, } /// Pretty serializer configuration. /// /// # Examples /// /// ``` /// use ron::ser::PrettyConfig; /// /// let my_config = PrettyConfig::new() /// .depth_limit(4) /// // definitely superior (okay, just joking) /// .indentor("\t"); /// ``` #[allow(clippy::struct_excessive_bools)] #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(default)] #[non_exhaustive] pub struct PrettyConfig { /// Limit the pretty-ness up to the given depth. pub depth_limit: usize, /// New line string pub new_line: Cow<'static, str>, /// Indentation string pub indentor: Cow<'static, str>, /// Separator string pub separator: Cow<'static, str>, // Whether to emit struct names pub struct_names: bool, /// Separate tuple members with indentation pub separate_tuple_members: bool, /// Enumerate array items in comments pub enumerate_arrays: bool, /// Enable extensions. Only configures `implicit_some`, /// `unwrap_newtypes`, and `unwrap_variant_newtypes` for now. pub extensions: Extensions, /// Enable compact arrays, which do not insert new lines and indentation /// between the elements of an array pub compact_arrays: bool, /// Whether to serialize strings as escaped strings, /// or fall back onto raw strings if necessary. pub escape_strings: bool, /// Enable compact structs, which do not insert new lines and indentation /// between the fields of a struct pub compact_structs: bool, /// Enable compact maps, which do not insert new lines and indentation /// between the entries of a struct pub compact_maps: bool, /// Enable explicit number type suffixes like `1u16` pub number_suffixes: bool, /// Additional path-based field metadata to serialize pub path_meta: Option, } impl PrettyConfig { /// Creates a default [`PrettyConfig`]. #[must_use] pub fn new() -> Self { Self::default() } /// Limits the pretty-formatting based on the number of indentations. /// I.e., with a depth limit of 5, starting with an element of depth /// (indentation level) 6, everything will be put into the same line, /// without pretty formatting. /// /// Default: [`usize::MAX`] #[must_use] pub fn depth_limit(mut self, depth_limit: usize) -> Self { self.depth_limit = depth_limit; self } /// Configures the newlines used for serialization. /// /// Default: `\r\n` on Windows, `\n` otherwise #[must_use] pub fn new_line(mut self, new_line: impl Into>) -> Self { self.new_line = new_line.into(); self } /// Configures the string sequence used for indentation. /// /// Default: 4 spaces #[must_use] pub fn indentor(mut self, indentor: impl Into>) -> Self { self.indentor = indentor.into(); self } /// Configures the string sequence used to separate items inline. /// /// Default: 1 space #[must_use] pub fn separator(mut self, separator: impl Into>) -> Self { self.separator = separator.into(); self } /// Configures whether to emit struct names. /// /// See also [`Extensions::EXPLICIT_STRUCT_NAMES`] for the extension equivalent. /// /// Default: `false` #[must_use] pub fn struct_names(mut self, struct_names: bool) -> Self { self.struct_names = struct_names; self } /// Configures whether tuples are single- or multi-line. /// If set to `true`, tuples will have their fields indented and in new /// lines. If set to `false`, tuples will be serialized without any /// newlines or indentations. /// /// Default: `false` #[must_use] pub fn separate_tuple_members(mut self, separate_tuple_members: bool) -> Self { self.separate_tuple_members = separate_tuple_members; self } /// Configures whether a comment shall be added to every array element, /// indicating the index. /// /// Default: `false` #[must_use] pub fn enumerate_arrays(mut self, enumerate_arrays: bool) -> Self { self.enumerate_arrays = enumerate_arrays; self } /// Configures whether every array should be a single line (`true`) /// or a multi line one (`false`). /// /// When `false`, `["a","b"]` will serialize to /// ``` /// [ /// "a", /// "b", /// ] /// # ; /// ``` /// When `true`, `["a","b"]` will instead serialize to /// ``` /// ["a","b"] /// # ; /// ``` /// /// Default: `false` #[must_use] pub fn compact_arrays(mut self, compact_arrays: bool) -> Self { self.compact_arrays = compact_arrays; self } /// Configures extensions /// /// Default: [`Extensions::empty()`] #[must_use] pub fn extensions(mut self, extensions: Extensions) -> Self { self.extensions = extensions; self } /// Configures whether strings should be serialized using escapes (true) /// or fall back to raw strings if the string contains a `"` (false). /// /// When `true`, `"a\nb"` will serialize to /// ``` /// "a\nb" /// # ; /// ``` /// When `false`, `"a\nb"` will instead serialize to /// ``` /// "a /// b" /// # ; /// ``` /// /// Default: `true` #[must_use] pub fn escape_strings(mut self, escape_strings: bool) -> Self { self.escape_strings = escape_strings; self } /// Configures whether every struct should be a single line (`true`) /// or a multi line one (`false`). /// /// When `false`, `Struct { a: 4, b: 2 }` will serialize to /// ```ignore /// Struct( /// a: 4, /// b: 2, /// ) /// # ; /// ``` /// When `true`, `Struct { a: 4, b: 2 }` will instead serialize to /// ```ignore /// Struct(a: 4, b: 2) /// # ; /// ``` /// /// Default: `false` #[must_use] pub fn compact_structs(mut self, compact_structs: bool) -> Self { self.compact_structs = compact_structs; self } /// Configures whether every map should be a single line (`true`) /// or a multi line one (`false`). /// /// When `false`, a map with entries `{ "a": 4, "b": 2 }` will serialize to /// ```ignore /// { /// "a": 4, /// "b": 2, /// } /// # ; /// ``` /// When `true`, a map with entries `{ "a": 4, "b": 2 }` will instead /// serialize to /// ```ignore /// {"a": 4, "b": 2} /// # ; /// ``` /// /// Default: `false` #[must_use] pub fn compact_maps(mut self, compact_maps: bool) -> Self { self.compact_maps = compact_maps; self } /// Configures whether numbers should be printed without (`false`) or /// with (`true`) their explicit type suffixes. /// /// When `false`, the integer `12345u16` will serialize to /// ```ignore /// 12345 /// # ; /// ``` /// and the float `12345.6789f64` will serialize to /// ```ignore /// 12345.6789 /// # ; /// ``` /// When `true`, the integer `12345u16` will serialize to /// ```ignore /// 12345u16 /// # ; /// ``` /// and the float `12345.6789f64` will serialize to /// ```ignore /// 12345.6789f64 /// # ; /// ``` /// /// Default: `false` #[must_use] pub fn number_suffixes(mut self, number_suffixes: bool) -> Self { self.number_suffixes = number_suffixes; self } } impl Default for PrettyConfig { fn default() -> Self { PrettyConfig { depth_limit: usize::MAX, new_line: if cfg!(not(target_os = "windows")) { Cow::Borrowed("\n") } else { Cow::Borrowed("\r\n") // GRCOV_EXCL_LINE }, indentor: Cow::Borrowed(" "), separator: Cow::Borrowed(" "), struct_names: false, separate_tuple_members: false, enumerate_arrays: false, extensions: Extensions::empty(), compact_arrays: false, escape_strings: true, compact_structs: false, compact_maps: false, number_suffixes: false, path_meta: None, } } } /// The RON serializer. /// /// You can just use [`to_string`] for deserializing a value. /// If you want it pretty-printed, take a look at [`to_string_pretty`]. pub struct Serializer { output: W, pretty: Option<(PrettyConfig, Pretty)>, default_extensions: Extensions, is_empty: Option, newtype_variant: bool, recursion_limit: Option, // Tracks the number of opened implicit `Some`s, set to 0 on backtracking implicit_some_depth: usize, } fn indent(output: &mut W, config: &PrettyConfig, pretty: &Pretty) -> fmt::Result { if pretty.indent <= config.depth_limit { for _ in 0..pretty.indent { output.write_str(&config.indentor)?; } } Ok(()) } impl Serializer { /// Creates a new [`Serializer`]. /// /// Most of the time you can just use [`to_string`] or /// [`to_string_pretty`]. pub fn new(writer: W, config: Option) -> Result { Self::with_options(writer, config, &Options::default()) } /// Creates a new [`Serializer`]. /// /// Most of the time you can just use [`to_string`] or /// [`to_string_pretty`]. pub fn with_options( mut writer: W, config: Option, options: &Options, ) -> Result { if let Some(conf) = &config { if !conf.new_line.chars().all(is_whitespace_char) { return Err(Error::Message(String::from( "Invalid non-whitespace `PrettyConfig::new_line`", ))); } if !conf.indentor.chars().all(is_whitespace_char) { return Err(Error::Message(String::from( "Invalid non-whitespace `PrettyConfig::indentor`", ))); } if !conf.separator.chars().all(is_whitespace_char) { return Err(Error::Message(String::from( "Invalid non-whitespace `PrettyConfig::separator`", ))); } let non_default_extensions = !options.default_extensions; for (extension_name, _) in (non_default_extensions & conf.extensions).iter_names() { write!(writer, "#![enable({})]", extension_name.to_lowercase())?; writer.write_str(&conf.new_line)?; } }; Ok(Serializer { output: writer, pretty: config.map(|conf| (conf, Pretty { indent: 0 })), default_extensions: options.default_extensions, is_empty: None, newtype_variant: false, recursion_limit: options.recursion_limit, implicit_some_depth: 0, }) } /// Unwrap the `Writer` from the `Serializer`. #[inline] pub fn into_inner(self) -> W { self.output } fn separate_tuple_members(&self) -> bool { self.pretty .as_ref() .map_or(false, |(ref config, _)| config.separate_tuple_members) } fn compact_arrays(&self) -> bool { self.pretty .as_ref() .map_or(false, |(ref config, _)| config.compact_arrays) } fn compact_structs(&self) -> bool { self.pretty .as_ref() .map_or(false, |(ref config, _)| config.compact_structs) } fn compact_maps(&self) -> bool { self.pretty .as_ref() .map_or(false, |(ref config, _)| config.compact_maps) } fn number_suffixes(&self) -> bool { self.pretty .as_ref() .map_or(false, |(ref config, _)| config.number_suffixes) } fn extensions(&self) -> Extensions { self.default_extensions | self .pretty .as_ref() .map_or(Extensions::empty(), |(ref config, _)| config.extensions) } fn escape_strings(&self) -> bool { self.pretty .as_ref() .map_or(true, |(ref config, _)| config.escape_strings) } fn start_indent(&mut self) -> Result<()> { if let Some((ref config, ref mut pretty)) = self.pretty { pretty.indent += 1; if pretty.indent <= config.depth_limit { let is_empty = self.is_empty.unwrap_or(false); if !is_empty { self.output.write_str(&config.new_line)?; } } } Ok(()) } fn indent(&mut self) -> fmt::Result { if let Some((ref config, ref pretty)) = self.pretty { indent(&mut self.output, config, pretty)?; } Ok(()) } fn end_indent(&mut self) -> fmt::Result { if let Some((ref config, ref mut pretty)) = self.pretty { if pretty.indent <= config.depth_limit { let is_empty = self.is_empty.unwrap_or(false); if !is_empty { for _ in 1..pretty.indent { self.output.write_str(&config.indentor)?; } } } pretty.indent -= 1; self.is_empty = None; } Ok(()) } fn serialize_escaped_str(&mut self, value: &str) -> fmt::Result { self.output.write_char('"')?; let mut scalar = [0u8; 4]; for c in value.chars().flat_map(char::escape_debug) { self.output.write_str(c.encode_utf8(&mut scalar))?; } self.output.write_char('"')?; Ok(()) } fn serialize_unescaped_or_raw_str(&mut self, value: &str) -> fmt::Result { if value.contains('"') || value.contains('\\') { let (_, num_consecutive_hashes) = value.chars().fold((0, 0), |(count, max), c| match c { '#' => (count + 1, max.max(count + 1)), _ => (0_usize, max), }); let hashes: String = "#".repeat(num_consecutive_hashes + 1); self.output.write_char('r')?; self.output.write_str(&hashes)?; self.output.write_char('"')?; self.output.write_str(value)?; self.output.write_char('"')?; self.output.write_str(&hashes)?; } else { self.output.write_char('"')?; self.output.write_str(value)?; self.output.write_char('"')?; } Ok(()) } fn serialize_escaped_byte_str(&mut self, value: &[u8]) -> fmt::Result { self.output.write_str("b\"")?; for c in value.iter().flat_map(|c| core::ascii::escape_default(*c)) { self.output.write_char(char::from(c))?; } self.output.write_char('"')?; Ok(()) } fn serialize_unescaped_or_raw_byte_str(&mut self, value: &str) -> fmt::Result { if value.contains('"') || value.contains('\\') { let (_, num_consecutive_hashes) = value.chars().fold((0, 0), |(count, max), c| match c { '#' => (count + 1, max.max(count + 1)), _ => (0_usize, max), }); let hashes: String = "#".repeat(num_consecutive_hashes + 1); self.output.write_str("br")?; self.output.write_str(&hashes)?; self.output.write_char('"')?; self.output.write_str(value)?; self.output.write_char('"')?; self.output.write_str(&hashes)?; } else { self.output.write_str("b\"")?; self.output.write_str(value)?; self.output.write_char('"')?; } Ok(()) } fn serialize_sint(&mut self, value: impl Into, suffix: &str) -> Result<()> { // TODO optimize write!(self.output, "{}", value.into())?; if self.number_suffixes() { write!(self.output, "{}", suffix)?; } Ok(()) } fn serialize_uint(&mut self, value: impl Into, suffix: &str) -> Result<()> { // TODO optimize write!(self.output, "{}", value.into())?; if self.number_suffixes() { write!(self.output, "{}", suffix)?; } Ok(()) } fn write_identifier(&mut self, name: &str) -> Result<()> { self.validate_identifier(name)?; let mut chars = name.chars(); if !chars.next().map_or(false, is_ident_first_char) || !chars.all(is_xid_continue) || [ "true", "false", "Some", "None", "inf", "inff32", "inff64", "NaN", "NaNf32", "NaNf64", ] .contains(&name) { self.output.write_str("r#")?; } self.output.write_str(name)?; Ok(()) } #[allow(clippy::unused_self)] fn validate_identifier(&self, name: &str) -> Result<()> { if name.is_empty() || !name.chars().all(is_ident_raw_char) { return Err(Error::InvalidIdentifier(name.into())); } Ok(()) } /// Checks if struct names should be emitted /// /// Note that when using the `explicit_struct_names` extension, this method will use an OR operation on the extension and the [`PrettyConfig::struct_names`] option. See also [`Extensions::EXPLICIT_STRUCT_NAMES`] for the extension equivalent. fn struct_names(&self) -> bool { self.extensions() .contains(Extensions::EXPLICIT_STRUCT_NAMES) || self .pretty .as_ref() .map_or(false, |(pc, _)| pc.struct_names) } } macro_rules! guard_recursion { ($self:expr => $expr:expr) => {{ if let Some(limit) = &mut $self.recursion_limit { if let Some(new_limit) = limit.checked_sub(1) { *limit = new_limit; } else { return Err(Error::ExceededRecursionLimit); } } let result = $expr; if let Some(limit) = &mut $self.recursion_limit { *limit = limit.saturating_add(1); } result }}; } impl<'a, W: fmt::Write> ser::Serializer for &'a mut Serializer { type Error = Error; type Ok = (); type SerializeMap = Compound<'a, W>; type SerializeSeq = Compound<'a, W>; type SerializeStruct = Compound<'a, W>; type SerializeStructVariant = Compound<'a, W>; type SerializeTuple = Compound<'a, W>; type SerializeTupleStruct = Compound<'a, W>; type SerializeTupleVariant = Compound<'a, W>; fn serialize_bool(self, v: bool) -> Result<()> { self.output.write_str(if v { "true" } else { "false" })?; Ok(()) } fn serialize_i8(self, v: i8) -> Result<()> { self.serialize_sint(v, "i8") } fn serialize_i16(self, v: i16) -> Result<()> { self.serialize_sint(v, "i16") } fn serialize_i32(self, v: i32) -> Result<()> { self.serialize_sint(v, "i32") } fn serialize_i64(self, v: i64) -> Result<()> { self.serialize_sint(v, "i64") } #[cfg(feature = "integer128")] fn serialize_i128(self, v: i128) -> Result<()> { self.serialize_sint(v, "i128") } fn serialize_u8(self, v: u8) -> Result<()> { self.serialize_uint(v, "u8") } fn serialize_u16(self, v: u16) -> Result<()> { self.serialize_uint(v, "u16") } fn serialize_u32(self, v: u32) -> Result<()> { self.serialize_uint(v, "u32") } fn serialize_u64(self, v: u64) -> Result<()> { self.serialize_uint(v, "u64") } #[cfg(feature = "integer128")] fn serialize_u128(self, v: u128) -> Result<()> { self.serialize_uint(v, "u128") } fn serialize_f32(self, v: f32) -> Result<()> { if v.is_nan() && v.is_sign_negative() { write!(self.output, "-")?; } write!(self.output, "{}", v)?; // Equivalent to v.fract() == 0.0 // See: https://docs.rs/num-traits/0.2.19/src/num_traits/float.rs.html#459-465 if v % 1. == 0.0 { write!(self.output, ".0")?; } if self.number_suffixes() { write!(self.output, "f32")?; } Ok(()) } fn serialize_f64(self, v: f64) -> Result<()> { if v.is_nan() && v.is_sign_negative() { write!(self.output, "-")?; } write!(self.output, "{}", v)?; // Equivalent to v.fract() == 0.0 // See: https://docs.rs/num-traits/0.2.19/src/num_traits/float.rs.html#459-465 if v % 1. == 0.0 { write!(self.output, ".0")?; } if self.number_suffixes() { write!(self.output, "f64")?; } Ok(()) } fn serialize_char(self, v: char) -> Result<()> { self.output.write_char('\'')?; if v == '\\' || v == '\'' { self.output.write_char('\\')?; } write!(self.output, "{}", v)?; self.output.write_char('\'')?; Ok(()) } fn serialize_str(self, v: &str) -> Result<()> { if self.escape_strings() { self.serialize_escaped_str(v)?; } else { self.serialize_unescaped_or_raw_str(v)?; } Ok(()) } fn serialize_bytes(self, v: &[u8]) -> Result<()> { // We need to fall back to escaping if the byte string would be invalid UTF-8 if !self.escape_strings() { if let Ok(v) = core::str::from_utf8(v) { return self .serialize_unescaped_or_raw_byte_str(v) .map_err(Error::from); } } self.serialize_escaped_byte_str(v)?; Ok(()) } fn serialize_none(self) -> Result<()> { // We no longer need to keep track of the depth let implicit_some_depth = self.implicit_some_depth; self.implicit_some_depth = 0; for _ in 0..implicit_some_depth { self.output.write_str("Some(")?; } self.output.write_str("None")?; for _ in 0..implicit_some_depth { self.output.write_char(')')?; } Ok(()) } fn serialize_some(self, value: &T) -> Result<()> where T: ?Sized + Serialize, { let implicit_some = self.extensions().contains(Extensions::IMPLICIT_SOME); if implicit_some { self.implicit_some_depth += 1; } else { self.newtype_variant = self .extensions() .contains(Extensions::UNWRAP_VARIANT_NEWTYPES); self.output.write_str("Some(")?; } guard_recursion! { self => value.serialize(&mut *self)? }; if implicit_some { self.implicit_some_depth = 0; } else { self.output.write_char(')')?; self.newtype_variant = false; } Ok(()) } fn serialize_unit(self) -> Result<()> { if !self.newtype_variant { self.output.write_str("()")?; } Ok(()) } fn serialize_unit_struct(self, name: &'static str) -> Result<()> { if self.struct_names() && !self.newtype_variant { self.write_identifier(name)?; Ok(()) } else { self.validate_identifier(name)?; self.serialize_unit() } } fn serialize_unit_variant( self, name: &'static str, _variant_index: u32, variant: &'static str, ) -> Result<()> { self.validate_identifier(name)?; self.write_identifier(variant)?; Ok(()) } fn serialize_newtype_struct(self, name: &'static str, value: &T) -> Result<()> where T: ?Sized + Serialize, { if name == crate::value::raw::RAW_VALUE_TOKEN { let implicit_some_depth = self.implicit_some_depth; self.implicit_some_depth = 0; for _ in 0..implicit_some_depth { self.output.write_str("Some(")?; } guard_recursion! { self => value.serialize(raw::Serializer::new(self)) }?; for _ in 0..implicit_some_depth { self.output.write_char(')')?; } return Ok(()); } if self.extensions().contains(Extensions::UNWRAP_NEWTYPES) || self.newtype_variant { self.newtype_variant = false; self.validate_identifier(name)?; return guard_recursion! { self => value.serialize(&mut *self) }; } if self.struct_names() { self.write_identifier(name)?; } else { self.validate_identifier(name)?; } self.implicit_some_depth = 0; self.output.write_char('(')?; guard_recursion! { self => value.serialize(&mut *self)? }; self.output.write_char(')')?; Ok(()) } fn serialize_newtype_variant( self, name: &'static str, _variant_index: u32, variant: &'static str, value: &T, ) -> Result<()> where T: ?Sized + Serialize, { self.validate_identifier(name)?; self.write_identifier(variant)?; self.output.write_char('(')?; self.newtype_variant = self .extensions() .contains(Extensions::UNWRAP_VARIANT_NEWTYPES); self.implicit_some_depth = 0; guard_recursion! { self => value.serialize(&mut *self)? }; self.newtype_variant = false; self.output.write_char(')')?; Ok(()) } fn serialize_seq(self, len: Option) -> Result { self.newtype_variant = false; self.implicit_some_depth = 0; self.output.write_char('[')?; if !self.compact_arrays() { if let Some(len) = len { self.is_empty = Some(len == 0); } self.start_indent()?; } Ok(Compound::new(self, false)) } fn serialize_tuple(self, len: usize) -> Result { let old_newtype_variant = self.newtype_variant; self.newtype_variant = false; self.implicit_some_depth = 0; if !old_newtype_variant { self.output.write_char('(')?; } if self.separate_tuple_members() { self.is_empty = Some(len == 0); self.start_indent()?; } Ok(Compound::new(self, old_newtype_variant)) } fn serialize_tuple_struct( self, name: &'static str, len: usize, ) -> Result { if self.struct_names() && !self.newtype_variant { self.write_identifier(name)?; } else { self.validate_identifier(name)?; } self.serialize_tuple(len) } fn serialize_tuple_variant( self, name: &'static str, _variant_index: u32, variant: &'static str, len: usize, ) -> Result { self.newtype_variant = false; self.implicit_some_depth = 0; self.validate_identifier(name)?; self.write_identifier(variant)?; self.output.write_char('(')?; if self.separate_tuple_members() { self.is_empty = Some(len == 0); self.start_indent()?; } Ok(Compound::new(self, false)) } fn serialize_map(self, len: Option) -> Result { self.newtype_variant = false; self.implicit_some_depth = 0; self.output.write_char('{')?; if !self.compact_maps() { if let Some(len) = len { self.is_empty = Some(len == 0); } self.start_indent()?; } Ok(Compound::new(self, false)) } fn serialize_struct(self, name: &'static str, len: usize) -> Result { let old_newtype_variant = self.newtype_variant; self.newtype_variant = false; self.implicit_some_depth = 0; if old_newtype_variant { self.validate_identifier(name)?; } else { if self.struct_names() { self.write_identifier(name)?; } else { self.validate_identifier(name)?; } self.output.write_char('(')?; } if !self.compact_structs() { self.is_empty = Some(len == 0); self.start_indent()?; } Ok(Compound::new(self, old_newtype_variant)) } fn serialize_struct_variant( self, name: &'static str, _variant_index: u32, variant: &'static str, len: usize, ) -> Result { self.newtype_variant = false; self.implicit_some_depth = 0; self.validate_identifier(name)?; self.write_identifier(variant)?; self.output.write_char('(')?; if !self.compact_structs() { self.is_empty = Some(len == 0); self.start_indent()?; } Ok(Compound::new(self, false)) } } enum State { First, Rest, } #[doc(hidden)] pub struct Compound<'a, W: fmt::Write> { ser: &'a mut Serializer, state: State, newtype_variant: bool, sequence_index: usize, } impl<'a, W: fmt::Write> Compound<'a, W> { fn new(ser: &'a mut Serializer, newtype_variant: bool) -> Self { Compound { ser, state: State::First, newtype_variant, sequence_index: 0, } } } impl<'a, W: fmt::Write> Drop for Compound<'a, W> { fn drop(&mut self) { if let Some(limit) = &mut self.ser.recursion_limit { *limit = limit.saturating_add(1); } } } impl<'a, W: fmt::Write> ser::SerializeSeq for Compound<'a, W> { type Error = Error; type Ok = (); fn serialize_element(&mut self, value: &T) -> Result<()> where T: ?Sized + Serialize, { if let State::First = self.state { self.state = State::Rest; } else { self.ser.output.write_char(',')?; if let Some((ref config, ref mut pretty)) = self.ser.pretty { if pretty.indent <= config.depth_limit && !config.compact_arrays { self.ser.output.write_str(&config.new_line)?; } else { self.ser.output.write_str(&config.separator)?; } } } if !self.ser.compact_arrays() { self.ser.indent()?; } if let Some((ref mut config, ref mut pretty)) = self.ser.pretty { if pretty.indent <= config.depth_limit && config.enumerate_arrays { write!(self.ser.output, "/*[{}]*/ ", self.sequence_index)?; self.sequence_index += 1; } } guard_recursion! { self.ser => value.serialize(&mut *self.ser)? }; Ok(()) } fn end(self) -> Result<()> { if let State::Rest = self.state { if let Some((ref config, ref mut pretty)) = self.ser.pretty { if pretty.indent <= config.depth_limit && !config.compact_arrays { self.ser.output.write_char(',')?; self.ser.output.write_str(&config.new_line)?; } } } if !self.ser.compact_arrays() { self.ser.end_indent()?; } // seq always disables `self.newtype_variant` self.ser.output.write_char(']')?; Ok(()) } } impl<'a, W: fmt::Write> ser::SerializeTuple for Compound<'a, W> { type Error = Error; type Ok = (); fn serialize_element(&mut self, value: &T) -> Result<()> where T: ?Sized + Serialize, { if let State::First = self.state { self.state = State::Rest; } else { self.ser.output.write_char(',')?; if let Some((ref config, ref pretty)) = self.ser.pretty { if pretty.indent <= config.depth_limit && self.ser.separate_tuple_members() { self.ser.output.write_str(&config.new_line)?; } else { self.ser.output.write_str(&config.separator)?; } } } if self.ser.separate_tuple_members() { self.ser.indent()?; } guard_recursion! { self.ser => value.serialize(&mut *self.ser)? }; Ok(()) } fn end(self) -> Result<()> { if let State::Rest = self.state { if let Some((ref config, ref pretty)) = self.ser.pretty { if self.ser.separate_tuple_members() && pretty.indent <= config.depth_limit { self.ser.output.write_char(',')?; self.ser.output.write_str(&config.new_line)?; } } } if self.ser.separate_tuple_members() { self.ser.end_indent()?; } if !self.newtype_variant { self.ser.output.write_char(')')?; } Ok(()) } } // Same thing but for tuple structs. impl<'a, W: fmt::Write> ser::SerializeTupleStruct for Compound<'a, W> { type Error = Error; type Ok = (); fn serialize_field(&mut self, value: &T) -> Result<()> where T: ?Sized + Serialize, { ser::SerializeTuple::serialize_element(self, value) } fn end(self) -> Result<()> { ser::SerializeTuple::end(self) } } impl<'a, W: fmt::Write> ser::SerializeTupleVariant for Compound<'a, W> { type Error = Error; type Ok = (); fn serialize_field(&mut self, value: &T) -> Result<()> where T: ?Sized + Serialize, { ser::SerializeTuple::serialize_element(self, value) } fn end(self) -> Result<()> { ser::SerializeTuple::end(self) } } impl<'a, W: fmt::Write> ser::SerializeMap for Compound<'a, W> { type Error = Error; type Ok = (); fn serialize_key(&mut self, key: &T) -> Result<()> where T: ?Sized + Serialize, { if let State::First = self.state { self.state = State::Rest; } else { self.ser.output.write_char(',')?; if let Some((ref config, ref pretty)) = self.ser.pretty { if pretty.indent <= config.depth_limit && !config.compact_maps { self.ser.output.write_str(&config.new_line)?; } else { self.ser.output.write_str(&config.separator)?; } } } if !self.ser.compact_maps() { self.ser.indent()?; } guard_recursion! { self.ser => key.serialize(&mut *self.ser) } } fn serialize_value(&mut self, value: &T) -> Result<()> where T: ?Sized + Serialize, { self.ser.output.write_char(':')?; if let Some((ref config, _)) = self.ser.pretty { self.ser.output.write_str(&config.separator)?; } guard_recursion! { self.ser => value.serialize(&mut *self.ser)? }; Ok(()) } fn end(self) -> Result<()> { if let State::Rest = self.state { if let Some((ref config, ref pretty)) = self.ser.pretty { if pretty.indent <= config.depth_limit && !config.compact_maps { self.ser.output.write_char(',')?; self.ser.output.write_str(&config.new_line)?; } } } if !self.ser.compact_maps() { self.ser.end_indent()?; } // map always disables `self.newtype_variant` self.ser.output.write_char('}')?; Ok(()) } } impl<'a, W: fmt::Write> ser::SerializeStruct for Compound<'a, W> { type Error = Error; type Ok = (); fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<()> where T: ?Sized + Serialize, { let mut restore_field = self.ser.pretty.as_mut().and_then(|(config, _)| { config.path_meta.take().map(|mut field| { if let Some(fields) = field.fields_mut() { config.path_meta = fields.remove(key); } field }) }); if let State::First = self.state { self.state = State::Rest; } else { self.ser.output.write_char(',')?; if let Some((ref config, ref pretty)) = self.ser.pretty { if pretty.indent <= config.depth_limit && !config.compact_structs { self.ser.output.write_str(&config.new_line)?; } else { self.ser.output.write_str(&config.separator)?; } } } if !self.ser.compact_structs() { if let Some((ref config, ref pretty)) = self.ser.pretty { indent(&mut self.ser.output, config, pretty)?; if let Some(ref field) = config.path_meta { for doc_line in field.doc().lines() { self.ser.output.write_str("/// ")?; self.ser.output.write_str(doc_line)?; self.ser.output.write_char('\n')?; indent(&mut self.ser.output, config, pretty)?; } } } } self.ser.write_identifier(key)?; self.ser.output.write_char(':')?; if let Some((ref config, _)) = self.ser.pretty { self.ser.output.write_str(&config.separator)?; } guard_recursion! { self.ser => value.serialize(&mut *self.ser)? }; if let Some((ref mut config, _)) = self.ser.pretty { core::mem::swap(&mut config.path_meta, &mut restore_field); if let Some(ref mut field) = config.path_meta { if let Some(fields) = field.fields_mut() { if let Some(restore_field) = restore_field { fields.insert(key, restore_field); } } } }; Ok(()) } fn end(self) -> Result<()> { if let State::Rest = self.state { if let Some((ref config, ref pretty)) = self.ser.pretty { if pretty.indent <= config.depth_limit && !config.compact_structs { self.ser.output.write_char(',')?; self.ser.output.write_str(&config.new_line)?; } } } if !self.ser.compact_structs() { self.ser.end_indent()?; } if !self.newtype_variant { self.ser.output.write_char(')')?; } Ok(()) } } impl<'a, W: fmt::Write> ser::SerializeStructVariant for Compound<'a, W> { type Error = Error; type Ok = (); fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<()> where T: ?Sized + Serialize, { ser::SerializeStruct::serialize_field(self, key, value) } fn end(self) -> Result<()> { ser::SerializeStruct::end(self) } }