Repository: ron-rs/ron (rust)

Issue:
Add function to serialize to a Writer
Bincode has [`serialize_into`](https://docs.rs/bincode/1.2.1/bincode/fn.serialize_into.html) which supports an arbitrary Writer, this would be very useful for RON as well, especially with `BufWriter`, because the data gets very large.

I'm seeing huge RAM spikes because of RON serialization: From ~90 MB baseline RAM usage to over 700 MB when it's serializing. Btw, the resulting ron file is 20 MB large.

![image](https://user-images.githubusercontent.com/535593/75310821-3271ba80-5855-11ea-9318-2f0295dd594f.png)

---

In the above application, I'm serializing app state to disk every 10s.
Btw, the CPU usage is also quite high. This is the CPU & RAM usage when serializing to bincode instead. With ROM, the CPU usage is almost always at ~27% (probably because it takes so long), with bincode, it only shows short spikes (to 24%) when serializing:

![image](https://user-images.githubusercontent.com/535593/75310907-76fd5600-5855-11ea-9275-32bf815ff0e2.png)

---

Anyway, with a function like `serialize_into`+`BufWriter` we could at least reduce the RAM spikes.
This would also allow chaining it with e.g. a Gzip encoder for streaming compression, e.g. like with bincode:
```rust
	bincode::serialize_into(
		GzBuilder::new()
			.write(BufWriter::new(File::create(path)?), Compression::best()),
		&data,
	)?;
```

Pull request description:
Port `ser::Serializer` to `io::Write`
Makes the `Serializer` struct generic over `io::Write`, allowing it to be used with more types (and less allocation). As a side-effect, the trailing commas are also removed from the output.

This was a quick implementation, written in response to compiler messages, so it could probably do with some cleaning up. It might be a good time to approach #175 

Closes #202 

## TODO

- [ ] Update docs


Patch:
diff --git a/src/de/mod.rs b/src/de/mod.rs
index e3bf242a..14cd9af6 100644
--- a/src/de/mod.rs
+++ b/src/de/mod.rs
@@ -5,10 +5,11 @@ pub use crate::parse::Position;
 use serde::de::{self, DeserializeSeed, Deserializer as SerdeError, Visitor};
 use std::{borrow::Cow, io, str};
 
-use self::id::IdDeserializer;
-use self::tag::TagDeserializer;
-use crate::extensions::Extensions;
-use crate::parse::{AnyNum, Bytes, ParsedStr};
+use self::{id::IdDeserializer, tag::TagDeserializer};
+use crate::{
+    extensions::Extensions,
+    parse::{AnyNum, Bytes, ParsedStr},
+};
 
 mod id;
 mod tag;
diff --git a/src/parse.rs b/src/parse.rs
index 69f0ed66..96b8f666 100644
--- a/src/parse.rs
+++ b/src/parse.rs
@@ -4,8 +4,10 @@ use std::{
     str::{from_utf8, from_utf8_unchecked, FromStr},
 };
 
-use crate::error::{Error, ErrorCode, Result};
-use crate::extensions::Extensions;
+use crate::{
+    error::{Error, ErrorCode, Result},
+    extensions::Extensions,
+};
 
 const DIGITS: &[u8] = b"0123456789ABCDEFabcdef_";
 const FLOAT_CHARS: &[u8] = b"0123456789.+-eE";
diff --git a/src/ser/mod.rs b/src/ser/mod.rs
index 1909bb70..53e11f65 100644
--- a/src/ser/mod.rs
+++ b/src/ser/mod.rs
@@ -1,11 +1,21 @@
 use serde::{ser, Deserialize, Serialize};
-use std::fmt::Write;
+use std::io;
 
 use crate::error::{Error, Result};
 use crate::extensions::Extensions;
 
 mod value;
 
+/// Serializes `value` into `writer`
+pub fn to_writer<W, T>(writer: W, value: &T) -> Result<()>
+where
+    W: io::Write,
+    T: Serialize,
+{
+    let mut s = Serializer::new(writer, None, false)?;
+    value.serialize(&mut s)
+}
+
 /// Serializes `value` and returns it as string.
 ///
 /// This function does not generate any newlines or nice formatting;
@@ -14,9 +24,10 @@ pub fn to_string<T>(value: &T) -> Result<String>
 where
     T: Serialize,
 {
-    let mut s = Serializer::new(None, false);
+    let buf = Vec::new();
+    let mut s = Serializer::new(buf, None, false)?;
     value.serialize(&mut s)?;
-    Ok(s.output)
+    Ok(String::from_utf8(s.output).expect("Ron should be utf-8"))
 }
 
 /// Serializes `value` in the recommended RON layout in a pretty way.
@@ -24,9 +35,10 @@ pub fn to_string_pretty<T>(value: &T, config: PrettyConfig) -> Result<String>
 where
     T: Serialize,
 {
-    let mut s = Serializer::new(Some(config), false);
+    let buf = Vec::new();
+    let mut s = Serializer::new(buf, Some(config), false)?;
     value.serialize(&mut s)?;
-    Ok(s.output)
+    Ok(String::from_utf8(s.output).expect("Ron should be utf-8"))
 }
 
 /// Pretty serializer state
@@ -78,8 +90,9 @@ impl PrettyConfig {
     }
 
     /// 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.
+    /// 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: [std::usize::MAX]
     pub fn with_depth_limit(mut self, depth_limit: usize) -> Self {
@@ -107,8 +120,9 @@ impl PrettyConfig {
     }
 
     /// 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.
+    /// 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`
     pub fn with_separate_tuple_members(mut self, separate_tuple_members: bool) -> Self {
@@ -117,8 +131,8 @@ impl PrettyConfig {
         self
     }
 
-    /// Configures whether a comment shall be added to every array element, indicating
-    /// the index.
+    /// Configures whether a comment shall be added to every array element,
+    /// indicating the index.
     ///
     /// Default: `false`
     pub fn with_enumerate_arrays(mut self, enumerate_arrays: bool) -> Self {
@@ -180,29 +194,26 @@ impl Default for PrettyConfig {
 ///
 /// You can just use `to_string` for deserializing a value.
 /// If you want it pretty-printed, take a look at the `pretty` module.
-pub struct Serializer {
-    output: String,
+pub struct Serializer<W: io::Write> {
+    output: W,
     pretty: Option<(PrettyConfig, Pretty)>,
     struct_names: bool,
     is_empty: Option<bool>,
 }
 
-impl Serializer {
+impl<W: io::Write> Serializer<W> {
     /// Creates a new `Serializer`.
     ///
     /// Most of the time you can just use `to_string` or `to_string_pretty`.
-    pub fn new(config: Option<PrettyConfig>, struct_names: bool) -> Self {
-        let initial_output = if let Some(conf) = &config {
+    pub fn new(mut writer: W, config: Option<PrettyConfig>, struct_names: bool) -> Result<Self> {
+        if let Some(conf) = &config {
             if conf.extensions.contains(Extensions::IMPLICIT_SOME) {
-                "#![enable(implicit_some)]".to_string() + &conf.new_line
-            } else {
-                String::new()
-            }
-        } else {
-            String::new()
+                writer.write_all(b"#![enable(implicit_some)]")?;
+                writer.write_all(conf.new_line.as_bytes())?;
+            };
         };
-        Serializer {
-            output: initial_output,
+        Ok(Serializer {
+            output: writer,
             pretty: config.map(|conf| {
                 (
                     conf,
@@ -214,12 +225,7 @@ impl Serializer {
             }),
             struct_names,
             is_empty: None,
-        }
-    }
-
-    /// Consumes `self` and returns the built `String`.
-    pub fn into_output_string(self) -> String {
-        self.output
+        })
     }
 
     fn is_pretty(&self) -> bool {
@@ -241,65 +247,74 @@ impl Serializer {
             .map_or(Extensions::empty(), |&(ref config, _)| config.extensions)
     }
 
-    fn start_indent(&mut self) {
+    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 += &config.new_line;
+                    self.output.write_all(config.new_line.as_bytes())?;
                 }
             }
         }
+        Ok(())
     }
 
-    fn indent(&mut self) {
+    fn indent(&mut self) -> io::Result<()> {
         if let Some((ref config, ref pretty)) = self.pretty {
             if pretty.indent <= config.depth_limit {
-                self.output
-                    .extend((0..pretty.indent).map(|_| config.indentor.as_str()));
+                for _ in 0..pretty.indent {
+                    self.output.write_all(config.indentor.as_bytes())?;
+                }
             }
         }
+        Ok(())
     }
 
-    fn end_indent(&mut self) {
+    fn end_indent(&mut self) -> io::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 {
-                    self.output
-                        .extend((1..pretty.indent).map(|_| config.indentor.as_str()));
+                    for _ in 1..pretty.indent {
+                        self.output.write_all(config.indentor.as_bytes())?;
+                    }
                 }
             }
             pretty.indent -= 1;
 
             self.is_empty = None;
         }
+        Ok(())
     }
 
-    fn serialize_escaped_str(&mut self, value: &str) {
-        let value = value.chars().flat_map(|c| c.escape_debug());
-        self.output += "\"";
-        self.output.extend(value);
-        self.output += "\"";
+    fn serialize_escaped_str(&mut self, value: &str) -> io::Result<()> {
+        self.output.write_all(b"\"")?;
+        let mut scalar = [0u8; 4];
+        for c in value.chars().flat_map(|c| c.escape_debug()) {
+            self.output
+                .write_all(c.encode_utf8(&mut scalar).as_bytes())?;
+        }
+        self.output.write_all(b"\"")?;
+        Ok(())
     }
 }
 
-impl<'a> ser::Serializer for &'a mut Serializer {
+impl<'a, W: io::Write> ser::Serializer for &'a mut Serializer<W> {
     type Error = Error;
     type Ok = ();
-    type SerializeMap = Self;
-    type SerializeSeq = Self;
-    type SerializeStruct = Self;
-    type SerializeStructVariant = Self;
-    type SerializeTuple = Self;
-    type SerializeTupleStruct = Self;
-    type SerializeTupleVariant = Self;
+    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 += if v { "true" } else { "false" };
+        self.output.write_all(if v { b"true" } else { b"false" })?;
         Ok(())
     }
 
@@ -321,7 +336,7 @@ impl<'a> ser::Serializer for &'a mut Serializer {
 
     fn serialize_i128(self, v: i128) -> Result<()> {
         // TODO optimize
-        self.output += &v.to_string();
+        write!(self.output, "{}", v)?;
         Ok(())
     }
 
@@ -342,32 +357,32 @@ impl<'a> ser::Serializer for &'a mut Serializer {
     }
 
     fn serialize_u128(self, v: u128) -> Result<()> {
-        self.output += &v.to_string();
+        write!(self.output, "{}", v)?;
         Ok(())
     }
 
     fn serialize_f32(self, v: f32) -> Result<()> {
-        self.output += &v.to_string();
+        write!(self.output, "{}", v)?;
         Ok(())
     }
 
     fn serialize_f64(self, v: f64) -> Result<()> {
-        self.output += &v.to_string();
+        write!(self.output, "{}", v)?;
         Ok(())
     }
 
     fn serialize_char(self, v: char) -> Result<()> {
-        self.output += "'";
+        self.output.write_all(b"'")?;
         if v == '\\' || v == '\'' {
-            self.output.push('\\');
+            self.output.write_all(b"\\")?;
         }
-        self.output.push(v);
-        self.output += "'";
+        write!(self.output, "{}", v)?;
+        self.output.write_all(b"'")?;
         Ok(())
     }
 
     fn serialize_str(self, v: &str) -> Result<()> {
-        self.serialize_escaped_str(v);
+        self.serialize_escaped_str(v)?;
 
         Ok(())
     }
@@ -377,7 +392,7 @@ impl<'a> ser::Serializer for &'a mut Serializer {
     }
 
     fn serialize_none(self) -> Result<()> {
-        self.output += "None";
+        self.output.write_all(b"None")?;
 
         Ok(())
     }
@@ -388,25 +403,25 @@ impl<'a> ser::Serializer for &'a mut Serializer {
     {
         let implicit_some = self.extensions().contains(Extensions::IMPLICIT_SOME);
         if !implicit_some {
-            self.output += "Some(";
+            self.output.write_all(b"Some(")?;
         }
         value.serialize(&mut *self)?;
         if !implicit_some {
-            self.output += ")";
+            self.output.write_all(b")")?;
         }
 
         Ok(())
     }
 
     fn serialize_unit(self) -> Result<()> {
-        self.output += "()";
+        self.output.write_all(b"()")?;
 
         Ok(())
     }
 
     fn serialize_unit_struct(self, name: &'static str) -> Result<()> {
         if self.struct_names {
-            self.output += name;
+            self.output.write_all(name.as_bytes())?;
 
             Ok(())
         } else {
@@ -415,7 +430,7 @@ impl<'a> ser::Serializer for &'a mut Serializer {
     }
 
     fn serialize_unit_variant(self, _: &'static str, _: u32, variant: &'static str) -> Result<()> {
-        self.output += variant;
+        self.output.write_all(variant.as_bytes())?;
 
         Ok(())
     }
@@ -425,12 +440,12 @@ impl<'a> ser::Serializer for &'a mut Serializer {
         T: ?Sized + Serialize,
     {
         if self.struct_names {
-            self.output += name;
+            self.output.write_all(name.as_bytes())?;
         }
 
-        self.output += "(";
+        self.output.write_all(b"(")?;
         value.serialize(&mut *self)?;
-        self.output += ")";
+        self.output.write_all(b")")?;
         Ok(())
     }
 
@@ -444,41 +459,47 @@ impl<'a> ser::Serializer for &'a mut Serializer {
     where
         T: ?Sized + Serialize,
     {
-        self.output += variant;
-        self.output += "(";
+        self.output.write_all(variant.as_bytes())?;
+        self.output.write_all(b"(")?;
 
         value.serialize(&mut *self)?;
 
-        self.output += ")";
+        self.output.write_all(b")")?;
         Ok(())
     }
 
     fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq> {
-        self.output += "[";
+        self.output.write_all(b"[")?;
 
         if let Some(len) = len {
             self.is_empty = Some(len == 0);
         }
 
-        self.start_indent();
+        self.start_indent()?;
 
         if let Some((_, ref mut pretty)) = self.pretty {
             pretty.sequence_index.push(0);
         }
 
-        Ok(self)
+        Ok(Compound::Map {
+            ser: self,
+            state: State::First,
+        })
     }
 
     fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple> {
-        self.output += "(";
+        self.output.write_all(b"(")?;
 
         if self.separate_tuple_members() {
             self.is_empty = Some(len == 0);
 
-            self.start_indent();
+            self.start_indent()?;
         }
 
-        Ok(self)
+        Ok(Compound::Map {
+            ser: self,
+            state: State::First,
+        })
     }
 
     fn serialize_tuple_struct(
@@ -487,7 +508,7 @@ impl<'a> ser::Serializer for &'a mut Serializer {
         len: usize,
     ) -> Result<Self::SerializeTupleStruct> {
         if self.struct_names {
-            self.output += name;
+            self.output.write_all(name.as_bytes())?;
         }
 
         self.serialize_tuple(len)
@@ -500,40 +521,49 @@ impl<'a> ser::Serializer for &'a mut Serializer {
         variant: &'static str,
         len: usize,
     ) -> Result<Self::SerializeTupleVariant> {
-        self.output += variant;
-        self.output += "(";
+        self.output.write_all(variant.as_bytes())?;
+        self.output.write_all(b"(")?;
 
         if self.separate_tuple_members() {
             self.is_empty = Some(len == 0);
 
-            self.start_indent();
+            self.start_indent()?;
         }
 
-        Ok(self)
+        Ok(Compound::Map {
+            ser: self,
+            state: State::First,
+        })
     }
 
     fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap> {
-        self.output += "{";
+        self.output.write_all(b"{")?;
 
         if let Some(len) = len {
             self.is_empty = Some(len == 0);
         }
 
-        self.start_indent();
+        self.start_indent()?;
 
-        Ok(self)
+        Ok(Compound::Map {
+            ser: self,
+            state: State::First,
+        })
     }
 
     fn serialize_struct(self, name: &'static str, len: usize) -> Result<Self::SerializeStruct> {
         if self.struct_names {
-            self.output += name;
+            self.output.write_all(name.as_bytes())?;
         }
-        self.output += "(";
+        self.output.write_all(b"(")?;
 
         self.is_empty = Some(len == 0);
-        self.start_indent();
+        self.start_indent()?;
 
-        Ok(self)
+        Ok(Compound::Map {
+            ser: self,
+            state: State::First,
+        })
     }
 
     fn serialize_struct_variant(
@@ -543,17 +573,20 @@ impl<'a> ser::Serializer for &'a mut Serializer {
         variant: &'static str,
         len: usize,
     ) -> Result<Self::SerializeStructVariant> {
-        self.output += variant;
-        self.output += "(";
+        self.output.write_all(variant.as_bytes())?;
+        self.output.write_all(b"(")?;
 
         self.is_empty = Some(len == 0);
-        self.start_indent();
+        self.start_indent()?;
 
-        Ok(self)
+        Ok(Compound::Map {
+            ser: self,
+            state: State::First,
+        })
     }
 }
 
-impl<'a> ser::SerializeSeq for &'a mut Serializer {
+impl<'a, W: io::Write> ser::SerializeSeq for Compound<'a, W> {
     type Error = Error;
     type Ok = ();
 
@@ -561,41 +594,78 @@ impl<'a> ser::SerializeSeq for &'a mut Serializer {
     where
         T: ?Sized + Serialize,
     {
-        self.indent();
-
-        value.serialize(&mut **self)?;
-        self.output += ",";
-
-        if let Some((ref config, ref mut pretty)) = self.pretty {
+        let ser = match self {
+            Compound::Map {
+                state: ref mut s @ State::First,
+                ser,
+            } => {
+                *s = State::Rest;
+                ser
+            }
+            Compound::Map {
+                state: State::Rest,
+                ser,
+            } => {
+                ser.output.write_all(b",")?;
+                ser
+            }
+        };
+        if let Some((ref config, ref mut pretty)) = ser.pretty {
             if pretty.indent <= config.depth_limit {
                 if config.enumerate_arrays {
                     assert!(config.new_line.contains('\n'));
                     let index = pretty.sequence_index.last_mut().unwrap();
                     //TODO: when /**/ comments are supported, prepend the index
                     // to an element instead of appending it.
-                    write!(self.output, "// [{}]", index).unwrap();
+                    write!(ser.output, "// [{}]", index).unwrap();
                     *index += 1;
                 }
-                self.output += &config.new_line;
+                ser.output.write_all(config.new_line.as_bytes())?;
             }
         }
+        ser.indent()?;
+
+        value.serialize(&mut **ser)?;
 
         Ok(())
     }
 
     fn end(self) -> Result<()> {
-        self.end_indent();
+        let ser = match self {
+            Compound::Map {
+                ser,
+                state: State::Rest,
+            } => {
+                if let Some((ref config, ref mut pretty)) = ser.pretty {
+                    if pretty.indent <= config.depth_limit {
+                        ser.output.write_all(b",")?;
+                    }
+                }
+                ser
+            }
+            Compound::Map { ser, .. } => ser,
+        };
+        ser.end_indent()?;
 
-        if let Some((_, ref mut pretty)) = self.pretty {
+        if let Some((_, ref mut pretty)) = ser.pretty {
             pretty.sequence_index.pop();
         }
 
-        self.output += "]";
+        ser.output.write_all(b"]")?;
         Ok(())
     }
 }
-
-impl<'a> ser::SerializeTuple for &'a mut Serializer {
+pub enum State {
+    First,
+    Rest,
+}
+pub enum Compound<'a, W: io::Write> {
+    Map {
+        ser: &'a mut Serializer<W>,
+        state: State,
+    },
+}
+impl<'a, W: io::Write> ser::SerializeTuple for Compound<'a, W> {
     type Error = Error;
     type Ok = ();
 
@@ -603,42 +673,66 @@ impl<'a> ser::SerializeTuple for &'a mut Serializer {
     where
         T: ?Sized + Serialize,
     {
-        if self.separate_tuple_members() {
-            self.indent();
-        }
-
-        value.serialize(&mut **self)?;
-        self.output += ",";
-
-        if let Some((ref config, ref pretty)) = self.pretty {
-            if pretty.indent <= config.depth_limit {
-                self.output += if self.separate_tuple_members() {
-                    &config.new_line
-                } else {
-                    " "
-                };
+        let ser = match self {
+            Compound::Map {
+                ser,
+                state: ref mut s @ State::First,
+            } => {
+                *s = State::Rest;
+                ser
             }
+            Compound::Map { ser, .. } => {
+                ser.output.write_all(b",")?;
+                if let Some((ref config, ref pretty)) = ser.pretty {
+                    if pretty.indent <= config.depth_limit {
+                        ser.output.write_all(if ser.separate_tuple_members() {
+                            config.new_line.as_bytes()
+                        } else {
+                            b" "
+                        })?;
+                    }
+                }
+                ser
+            }
+        };
+
+        if ser.separate_tuple_members() {
+            ser.indent()?;
         }
 
+        value.serialize(&mut **ser)?;
+
         Ok(())
     }
 
     fn end(self) -> Result<()> {
-        if self.separate_tuple_members() {
-            self.end_indent();
-        } else if self.is_pretty() {
-            self.output.pop();
-            self.output.pop();
+        let ser = match self {
+            Compound::Map {
+                ser,
+                state: State::Rest,
+            } => {
+                if let Some((ref config, ref pretty)) = ser.pretty {
+                    if ser.separate_tuple_members() && pretty.indent <= config.depth_limit {
+                        ser.output.write_all(b",")?;
+                        ser.output.write_all(config.new_line.as_bytes())?;
+                    }
+                }
+                ser
+            }
+            Compound::Map { ser, .. } => ser,
+        };
+        if ser.separate_tuple_members() {
+            ser.end_indent()?;
         }
 
-        self.output += ")";
+        ser.output.write_all(b")")?;
 
         Ok(())
     }
 }
 
 // Same thing but for tuple structs.
-impl<'a> ser::SerializeTupleStruct for &'a mut Serializer {
+impl<'a, W: io::Write> ser::SerializeTupleStruct for Compound<'a, W> {
     type Error = Error;
     type Ok = ();
 
@@ -654,7 +748,7 @@ impl<'a> ser::SerializeTupleStruct for &'a mut Serializer {
     }
 }
 
-impl<'a> ser::SerializeTupleVariant for &'a mut Serializer {
+impl<'a, W: io::Write> ser::SerializeTupleVariant for Compound<'a, W> {
     type Error = Error;
     type Ok = ();
 
@@ -670,7 +764,7 @@ impl<'a> ser::SerializeTupleVariant for &'a mut Serializer {
     }
 }
 
-impl<'a> ser::SerializeMap for &'a mut Serializer {
+impl<'a, W: io::Write> ser::SerializeMap for Compound<'a, W> {
     type Error = Error;
     type Ok = ();
 
@@ -678,27 +772,45 @@ impl<'a> ser::SerializeMap for &'a mut Serializer {
     where
         T: ?Sized + Serialize,
     {
-        self.indent();
-
-        key.serialize(&mut **self)
+        let ser = match self {
+            Compound::Map {
+                ser,
+                state: ref mut s @ State::First,
+            } => {
+                *s = State::Rest;
+                ser
+            }
+            Compound::Map {
+                ser,
+                state: State::Rest,
+            } => {
+                ser.output.write_all(b",")?;
+
+                if let Some((ref config, ref pretty)) = ser.pretty {
+                    if pretty.indent <= config.depth_limit {
+                        ser.output.write_all(config.new_line.as_bytes())?;
+                    }
+                }
+                ser
+            }
+        };
+        ser.indent()?;
+        key.serialize(&mut **ser)
     }
 
     fn serialize_value<T>(&mut self, value: &T) -> Result<()>
     where
         T: ?Sized + Serialize,
     {
-        self.output += ":";
+        match self {
+            Compound::Map { ser, .. } => {
+                ser.output.write_all(b":")?;
 
-        if self.is_pretty() {
-            self.output += " ";
-        }
-
-        value.serialize(&mut **self)?;
-        self.output += ",";
+                if ser.is_pretty() {
+                    ser.output.write_all(b" ")?;
+                }
 
-        if let Some((ref config, ref pretty)) = self.pretty {
-            if pretty.indent <= config.depth_limit {
-                self.output += &config.new_line;
+                value.serialize(&mut **ser)?;
             }
         }
 
@@ -706,14 +818,29 @@ impl<'a> ser::SerializeMap for &'a mut Serializer {
     }
 
     fn end(self) -> Result<()> {
-        self.end_indent();
+        let ser = match self {
+            Compound::Map {
+                ser,
+                state: State::Rest,
+            } => {
+                if let Some((ref config, ref pretty)) = ser.pretty {
+                    if pretty.indent <= config.depth_limit {
+                        ser.output.write_all(b",")?;
+                        ser.output.write_all(config.new_line.as_bytes())?;
+                    }
+                }
 
-        self.output += "}";
+                ser
+            }
+            Compound::Map { ser, .. } => ser,
+        };
+        ser.end_indent()?;
+        ser.output.write_all(b"}")?;
         Ok(())
     }
 }
 
-impl<'a> ser::SerializeStruct for &'a mut Serializer {
+impl<'a, W: io::Write> ser::SerializeStruct for Compound<'a, W> {
     type Error = Error;
     type Ok = ();
 
@@ -721,36 +848,61 @@ impl<'a> ser::SerializeStruct for &'a mut Serializer {
     where
         T: ?Sized + Serialize,
     {
-        self.indent();
+        let ser = match self {
+            Compound::Map {
+                ser,
+                state: ref mut s @ State::First,
+            } => {
+                *s = State::Rest;
+                ser
+            }
+            Compound::Map { ser, .. } => {
+                ser.output.write_all(b",")?;
 
-        self.output += key;
-        self.output += ":";
+                if let Some((ref config, ref pretty)) = ser.pretty {
+                    if pretty.indent <= config.depth_limit {
+                        ser.output.write_all(config.new_line.as_bytes())?;
+                    }
+                }
+                ser
+            }
+        };
+        ser.indent()?;
+        ser.output.write_all(key.as_bytes())?;
+        ser.output.write_all(b":")?;
 
-        if self.is_pretty() {
-            self.output += " ";
+        if ser.is_pretty() {
+            ser.output.write_all(b" ")?;
         }
 
-        value.serialize(&mut **self)?;
-        self.output += ",";
-
-        if let Some((ref config, ref pretty)) = self.pretty {
-            if pretty.indent <= config.depth_limit {
-                self.output += &config.new_line;
-            }
-        }
+        value.serialize(&mut **ser)?;
 
         Ok(())
     }
 
     fn end(self) -> Result<()> {
-        self.end_indent();
-
-        self.output += ")";
+        let ser = match self {
+            Compound::Map {
+                ser,
+                state: State::Rest,
+            } => {
+                if let Some((ref config, ref pretty)) = ser.pretty {
+                    if pretty.indent <= config.depth_limit {
+                        ser.output.write_all(b",")?;
+                        ser.output.write_all(config.new_line.as_bytes())?;
+                    }
+                }
+                ser
+            }
+            Compound::Map { ser, .. } => ser,
+        };
+        ser.end_indent()?;
+        ser.output.write_all(b")")?;
         Ok(())
     }
 }
 
-impl<'a> ser::SerializeStructVariant for &'a mut Serializer {
+impl<'a, W: io::Write> ser::SerializeStructVariant for Compound<'a, W> {
     type Error = Error;
     type Ok = ();
 
@@ -800,7 +952,7 @@ mod tests {
     fn test_struct() {
         let my_struct = MyStruct { x: 4.0, y: 7.0 };
 
-        assert_eq!(to_string(&my_struct).unwrap(), "(x:4,y:7,)");
+        assert_eq!(to_string(&my_struct).unwrap(), "(x:4,y:7)");
 
         #[derive(Serialize)]
         struct NewType(i32);
@@ -810,7 +962,7 @@ mod tests {
         #[derive(Serialize)]
         struct TupleStruct(f32, f32);
 
-        assert_eq!(to_string(&TupleStruct(2.0, 5.0)).unwrap(), "(2,5,)");
+        assert_eq!(to_string(&TupleStruct(2.0, 5.0)).unwrap(), "(2,5)");
     }
 
     #[test]
@@ -823,8 +975,8 @@ mod tests {
     fn test_enum() {
         assert_eq!(to_string(&MyEnum::A).unwrap(), "A");
         assert_eq!(to_string(&MyEnum::B(true)).unwrap(), "B(true)");
-        assert_eq!(to_string(&MyEnum::C(true, 3.5)).unwrap(), "C(true,3.5,)");
-        assert_eq!(to_string(&MyEnum::D { a: 2, b: 3 }).unwrap(), "D(a:2,b:3,)");
+        assert_eq!(to_string(&MyEnum::C(true, 3.5)).unwrap(), "C(true,3.5)");
+        assert_eq!(to_string(&MyEnum::D { a: 2, b: 3 }).unwrap(), "D(a:2,b:3)");
     }
 
     #[test]
@@ -834,8 +986,8 @@ mod tests {
         let empty_ref: &[i32] = &empty;
         assert_eq!(to_string(&empty_ref).unwrap(), "[]");
 
-        assert_eq!(to_string(&[2, 3, 4i32]).unwrap(), "(2,3,4,)");
-        assert_eq!(to_string(&(&[2, 3, 4i32] as &[i32])).unwrap(), "[2,3,4,]");
+        assert_eq!(to_string(&[2, 3, 4i32]).unwrap(), "(2,3,4)");
+        assert_eq!(to_string(&(&[2, 3, 4i32] as &[i32])).unwrap(), "[2,3,4]");
     }
 
     #[test]
@@ -848,8 +1000,8 @@ mod tests {
 
         let s = to_string(&map).unwrap();
         s.starts_with("{");
-        s.contains("(true,false,):4");
-        s.contains("(false,false,):123");
+        s.contains("(true,false):4");
+        s.contains("(false,false):123");
         s.ends_with("}");
     }
 
@@ -875,7 +1027,7 @@ mod tests {
         let small: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
         assert_eq!(
             to_string(&small).unwrap(),
-            "(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,)"
+            "(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)"
         );
 
         let large = vec![255u8; 64];
diff --git a/src/value.rs b/src/value.rs
index a848c9f2..1998c39d 100644
--- a/src/value.rs
+++ b/src/value.rs
@@ -371,8 +371,7 @@ impl<'de> SeqAccess<'de> for Seq {
 mod tests {
     use super::*;
     use serde::Deserialize;
-    use std::collections::BTreeMap;
-    use std::fmt::Debug;
+    use std::{collections::BTreeMap, fmt::Debug};
 
     fn assert_same<'de, T>(s: &'de str)
     where


Test patch:
diff --git a/tests/117_untagged_tuple_variant.rs b/tests/117_untagged_tuple_variant.rs
index a11654e5..6d98deb6 100644
--- a/tests/117_untagged_tuple_variant.rs
+++ b/tests/117_untagged_tuple_variant.rs
@@ -54,6 +54,6 @@ enum Foo {
 fn test_vessd_case() {
     let foo_vec = vec![Foo::Bar(0); 5];
     let foo_str = to_string(&foo_vec).unwrap();
-    assert_eq!(foo_str.as_str(), "[0,0,0,0,0,]");
+    assert_eq!(foo_str.as_str(), "[0,0,0,0,0]");
     assert_eq!(from_str::<Vec<Foo>>(&foo_str).unwrap(), foo_vec);
 }
diff --git a/tests/123_enum_representation.rs b/tests/123_enum_representation.rs
index 8b0ac4eb..3f82b08c 100644
--- a/tests/123_enum_representation.rs
+++ b/tests/123_enum_representation.rs
@@ -1,8 +1,6 @@
-use ron::de::from_str;
-use ron::ser::to_string;
+use ron::{de::from_str, ser::to_string};
 use serde::{Deserialize, Serialize};
-use std::cmp::PartialEq;
-use std::fmt::Debug;
+use std::{cmp::PartialEq, fmt::Debug};
 
 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
 enum Inner {
@@ -73,14 +71,14 @@ fn test_externally_a_ser() {
         bar: 2,
         different: 3,
     };
-    let e = "VariantA(foo:1,bar:2,different:3,)";
+    let e = "VariantA(foo:1,bar:2,different:3)";
     test_ser(&v, e);
 }
 
 #[test]
 fn test_externally_b_ser() {
     let v = EnumStructExternally::VariantB { foo: 1, bar: 2 };
-    let e = "VariantB(foo:1,bar:2,)";
+    let e = "VariantB(foo:1,bar:2)";
     test_ser(&v, e);
 }
 
@@ -91,14 +89,14 @@ fn test_internally_a_ser() {
         bar: 2,
         different: 3,
     };
-    let e = "(type:\"VariantA\",foo:1,bar:2,different:3,)";
+    let e = "(type:\"VariantA\",foo:1,bar:2,different:3)";
     test_ser(&v, e);
 }
 
 #[test]
 fn test_internally_b_ser() {
     let v = EnumStructInternally::VariantB { foo: 1, bar: 2 };
-    let e = "(type:\"VariantB\",foo:1,bar:2,)";
+    let e = "(type:\"VariantB\",foo:1,bar:2)";
     test_ser(&v, e);
 }
 
@@ -109,14 +107,14 @@ fn test_adjacently_a_ser() {
         bar: 2,
         different: Inner::Foo,
     };
-    let e = "(type:\"VariantA\",content:(foo:1,bar:2,different:Foo,),)";
+    let e = "(type:\"VariantA\",content:(foo:1,bar:2,different:Foo))";
     test_ser(&v, e);
 }
 
 #[test]
 fn test_adjacently_b_ser() {
     let v = EnumStructAdjacently::VariantB { foo: 1, bar: 2 };
-    let e = "(type:\"VariantB\",content:(foo:1,bar:2,),)";
+    let e = "(type:\"VariantB\",content:(foo:1,bar:2))";
     test_ser(&v, e);
 }
 
@@ -127,20 +125,20 @@ fn test_untagged_a_ser() {
         bar: 2,
         different: 3,
     };
-    let e = "(foo:1,bar:2,different:3,)";
+    let e = "(foo:1,bar:2,different:3)";
     test_ser(&v, e);
 }
 
 #[test]
 fn test_untagged_b_ser() {
     let v = EnumStructUntagged::VariantB { foo: 1, bar: 2 };
-    let e = "(foo:1,bar:2,)";
+    let e = "(foo:1,bar:2)";
     test_ser(&v, e);
 }
 
 #[test]
 fn test_externally_a_de() {
-    let s = "VariantA(foo:1,bar:2,different:3,)";
+    let s = "VariantA(foo:1,bar:2,different:3)";
     let e = EnumStructExternally::VariantA {
         foo: 1,
         bar: 2,
@@ -151,14 +149,14 @@ fn test_externally_a_de() {
 
 #[test]
 fn test_externally_b_de() {
-    let s = "VariantB(foo:1,bar:2,)";
+    let s = "VariantB(foo:1,bar:2)";
     let e = EnumStructExternally::VariantB { foo: 1, bar: 2 };
     test_de(s, e);
 }
 
 #[test]
 fn test_internally_a_de() {
-    let s = "(type:\"VariantA\",foo:1,bar:2,different:3,)";
+    let s = "(type:\"VariantA\",foo:1,bar:2,different:3)";
     let e = EnumStructInternally::VariantA {
         foo: 1,
         bar: 2,
@@ -169,14 +167,14 @@ fn test_internally_a_de() {
 
 #[test]
 fn test_internally_b_de() {
-    let s = "(type:\"VariantB\",foo:1,bar:2,)";
+    let s = "(type:\"VariantB\",foo:1,bar:2)";
     let e = EnumStructInternally::VariantB { foo: 1, bar: 2 };
     test_de(s, e);
 }
 
 #[test]
 fn test_adjacently_a_de() {
-    let s = "(type:\"VariantA\",content:(foo:1,bar:2,different:Foo,),)";
+    let s = "(type:\"VariantA\",content:(foo:1,bar:2,different:Foo))";
     let e = EnumStructAdjacently::VariantA {
         foo: 1,
         bar: 2,
@@ -187,14 +185,14 @@ fn test_adjacently_a_de() {
 
 #[test]
 fn test_adjacently_b_de() {
-    let s = "(type:\"VariantB\",content:(foo:1,bar:2,),)";
+    let s = "(type:\"VariantB\",content:(foo:1,bar:2))";
     let e = EnumStructAdjacently::VariantB { foo: 1, bar: 2 };
     test_de(s, e);
 }
 
 #[test]
 fn test_untagged_a_de() {
-    let s = "(foo:1,bar:2,different:3,)";
+    let s = "(foo:1,bar:2,different:3)";
     let e = EnumStructUntagged::VariantA {
         foo: 1,
         bar: 2,
@@ -205,7 +203,7 @@ fn test_untagged_a_de() {
 
 #[test]
 fn test_untagged_b_de() {
-    let s = "(foo:1,bar:2,)";
+    let s = "(foo:1,bar:2)";
     let e = EnumStructUntagged::VariantB { foo: 1, bar: 2 };
     test_de(s, e);
 }
diff --git a/tests/129_indexmap.rs b/tests/129_indexmap.rs
index a19e351d..a10a11e2 100644
--- a/tests/129_indexmap.rs
+++ b/tests/129_indexmap.rs
@@ -15,9 +15,9 @@ tasks: {
         "-l",
         "-h",
       ]),
-      ch_dir: Some("/")
+      ch_dir: Some("/"),
     ),
-}
+},
 )
 "#;
 
diff --git a/tests/depth_limit.rs b/tests/depth_limit.rs
index 83d7f38e..5c74f282 100644
--- a/tests/depth_limit.rs
+++ b/tests/depth_limit.rs
@@ -26,12 +26,12 @@ struct Nested {
 }
 
 const EXPECTED: &str = "(
-    float: (2.18,-1.1,),
-    tuple: ((),false,),
-    map: {8:'1',},
-    nested: (a:\"a\",b:'b',),
-    var: A(255,\"\",),
-    array: [(),(),(),],
+    float: (2.18,-1.1),
+    tuple: ((),false),
+    map: {8:'1'},
+    nested: (a:\"a\",b:'b'),
+    var: A(255,\"\"),
+    array: [(),(),()],
 )";
 
 #[test]
diff --git a/tests/preserve_sequence.rs b/tests/preserve_sequence.rs
index 02cf8d81..db34a1d3 100644
--- a/tests/preserve_sequence.rs
+++ b/tests/preserve_sequence.rs
@@ -1,7 +1,8 @@
-use ron::de::from_str;
-use ron::ser::{to_string_pretty, PrettyConfig};
-use serde::Deserialize;
-use serde::Serialize;
+use ron::{
+    de::from_str,
+    ser::{to_string_pretty, PrettyConfig},
+};
+use serde::{Deserialize, Serialize};
 use std::collections::BTreeMap;
 
 #[derive(Debug, Deserialize, Serialize)]