Split json compact and pretty serializer. Recover 20MB/s

This commit is contained in:
Erick Tryzelaar
2015-03-12 21:15:47 -07:00
parent dc87288f48
commit aedd5f57cf
+143 -92
View File
@@ -6,41 +6,33 @@ use std::string::FromUtf8Error;
use ser; use ser;
/// A structure for implementing serialization to JSON. /// A structure for implementing serialization to JSON.
pub struct Serializer<W> { pub struct Serializer<W, F=CompactFormatter> {
writer: W, writer: W,
format: Format, formatter: F,
current_indent: usize,
indent: usize,
} }
#[derive(Copy, PartialEq)] impl<W> Serializer<W>
enum Format { where W: io::Write,
Compact, {
Pretty,
}
impl<W: io::Write> Serializer<W> {
/// Creates a new JSON visitr whose output will be written to the writer /// Creates a new JSON visitr whose output will be written to the writer
/// specified. /// specified.
#[inline] #[inline]
pub fn new(writer: W) -> Serializer<W> { pub fn new(writer: W) -> Serializer<W> {
Serializer { Serializer::new_with_formatter(writer, CompactFormatter)
writer: writer,
format: Format::Compact,
current_indent: 0,
indent: 0,
}
} }
}
impl<W, F> Serializer<W, F>
where W: io::Write,
F: Formatter,
{
/// Creates a new JSON visitr whose output will be written to the writer /// Creates a new JSON visitr whose output will be written to the writer
/// specified. /// specified.
#[inline] #[inline]
pub fn new_pretty(writer: W) -> Serializer<W> { pub fn new_with_formatter(writer: W, formatter: F) -> Serializer<W, F> {
Serializer { Serializer {
writer: writer, writer: writer,
format: Format::Pretty, formatter: formatter,
current_indent: 0,
indent: 2,
} }
} }
@@ -49,49 +41,11 @@ impl<W: io::Write> Serializer<W> {
pub fn into_inner(self) -> W { pub fn into_inner(self) -> W {
self.writer self.writer
} }
fn serialize_sep(&mut self, first: bool) -> io::Result<()> {
match self.format {
Format::Compact => {
if first {
Ok(())
} else {
self.writer.write_all(b",")
}
}
Format::Pretty => {
if first {
self.current_indent += self.indent;
try!(self.writer.write_all(b"\n"));
} else {
try!(self.writer.write_all(b",\n"));
}
spaces(&mut self.writer, self.current_indent)
}
}
}
fn serialize_colon(&mut self) -> io::Result<()> {
match self.format {
Format::Compact => self.writer.write_all(b":"),
Format::Pretty => self.writer.write_all(b": "),
}
}
fn serialize_end(&mut self, current_indent: usize, s: &[u8]) -> io::Result<()> {
if self.format == Format::Pretty && current_indent != self.current_indent {
self.current_indent -= self.indent;
try!(self.writer.write(b"\n"));
try!(spaces(&mut self.writer, self.current_indent));
}
self.writer.write_all(s)
}
} }
impl<W> ser::Serializer for Serializer<W> impl<W, F> ser::Serializer for Serializer<W, F>
where W: io::Write, where W: io::Write,
F: Formatter,
{ {
type Error = io::Error; type Error = io::Error;
@@ -193,48 +147,50 @@ impl<W> ser::Serializer for Serializer<W>
#[inline] #[inline]
fn visit_enum_unit(&mut self, _name: &str, variant: &str) -> io::Result<()> { fn visit_enum_unit(&mut self, _name: &str, variant: &str) -> io::Result<()> {
let current_indent = self.current_indent; try!(self.formatter.open(&mut self.writer, b'{'));
try!(self.formatter.comma(&mut self.writer, true));
try!(self.writer.write_all(b"{"));
try!(self.serialize_sep(true));
try!(self.visit_str(variant)); try!(self.visit_str(variant));
try!(self.serialize_colon()); try!(self.formatter.colon(&mut self.writer));
try!(self.writer.write_all(b"[]")); try!(self.writer.write_all(b"[]"));
self.serialize_end(current_indent, b"}") self.formatter.close(&mut self.writer, b'}')
} }
#[inline] #[inline]
fn visit_seq<V>(&mut self, mut visitor: V) -> io::Result<()> fn visit_seq<V>(&mut self, mut visitor: V) -> io::Result<()>
where V: ser::SeqVisitor, where V: ser::SeqVisitor,
{ {
let current_indent = self.current_indent; match visitor.len() {
Some(len) if len == 0 => {
self.writer.write_all(b"[]")
}
_ => {
try!(self.formatter.open(&mut self.writer, b'['));
try!(self.writer.write_all(b"[")); while let Some(()) = try!(visitor.visit(self)) { }
while let Some(()) = try!(visitor.visit(self)) { } self.formatter.close(&mut self.writer, b']')
}
}
self.serialize_end(current_indent, b"]")
} }
#[inline] #[inline]
fn visit_enum_seq<V>(&mut self, _name: &str, variant: &str, visitor: V) -> io::Result<()> fn visit_enum_seq<V>(&mut self, _name: &str, variant: &str, visitor: V) -> io::Result<()>
where V: ser::SeqVisitor, where V: ser::SeqVisitor,
{ {
let current_indent = self.current_indent; try!(self.formatter.open(&mut self.writer, b'{'));
try!(self.formatter.comma(&mut self.writer, true));
try!(self.writer.write_all(b"{"));
try!(self.serialize_sep(true));
try!(self.visit_str(variant)); try!(self.visit_str(variant));
try!(self.serialize_colon()); try!(self.formatter.colon(&mut self.writer));
try!(self.visit_seq(visitor)); try!(self.visit_seq(visitor));
self.serialize_end(current_indent, b"}") self.formatter.close(&mut self.writer, b'}')
} }
#[inline] #[inline]
fn visit_seq_elt<T>(&mut self, first: bool, value: T) -> io::Result<()> fn visit_seq_elt<T>(&mut self, first: bool, value: T) -> io::Result<()>
where T: ser::Serialize, where T: ser::Serialize,
{ {
try!(self.serialize_sep(first)); try!(self.formatter.comma(&mut self.writer, first));
value.serialize(self) value.serialize(self)
} }
@@ -243,27 +199,31 @@ impl<W> ser::Serializer for Serializer<W>
fn visit_map<V>(&mut self, mut visitor: V) -> io::Result<()> fn visit_map<V>(&mut self, mut visitor: V) -> io::Result<()>
where V: ser::MapVisitor, where V: ser::MapVisitor,
{ {
let current_indent = self.current_indent; match visitor.len() {
Some(len) if len == 0 => {
self.writer.write_all(b"{}")
}
_ => {
try!(self.formatter.open(&mut self.writer, b'{'));
try!(self.writer.write_all(b"{")); while let Some(()) = try!(visitor.visit(self)) { }
while let Some(()) = try!(visitor.visit(self)) { } self.formatter.close(&mut self.writer, b'}')
}
self.serialize_end(current_indent, b"}") }
} }
#[inline] #[inline]
fn visit_enum_map<V>(&mut self, _name: &str, variant: &str, visitor: V) -> io::Result<()> fn visit_enum_map<V>(&mut self, _name: &str, variant: &str, visitor: V) -> io::Result<()>
where V: ser::MapVisitor, where V: ser::MapVisitor,
{ {
let current_indent = self.current_indent; try!(self.formatter.open(&mut self.writer, b'{'));
try!(self.formatter.comma(&mut self.writer, true));
try!(self.writer.write_all(b"{"));
try!(self.serialize_sep(true));
try!(self.visit_str(variant)); try!(self.visit_str(variant));
try!(self.serialize_colon()); try!(self.formatter.colon(&mut self.writer));
try!(self.visit_map(visitor)); try!(self.visit_map(visitor));
self.serialize_end(current_indent, b"}")
self.formatter.close(&mut self.writer, b'}')
} }
#[inline] #[inline]
@@ -271,13 +231,101 @@ impl<W> ser::Serializer for Serializer<W>
where K: ser::Serialize, where K: ser::Serialize,
V: ser::Serialize, V: ser::Serialize,
{ {
try!(self.serialize_sep(first)); try!(self.formatter.comma(&mut self.writer, first));
try!(key.serialize(self)); try!(key.serialize(self));
try!(self.serialize_colon()); try!(self.formatter.colon(&mut self.writer));
value.serialize(self) value.serialize(self)
} }
} }
pub trait Formatter {
fn open<W>(&mut self, writer: &mut W, ch: u8) -> io::Result<()>
where W: io::Write;
fn comma<W>(&mut self, writer: &mut W, first: bool) -> io::Result<()>
where W: io::Write;
fn colon<W>(&mut self, writer: &mut W) -> io::Result<()>
where W: io::Write;
fn close<W>(&mut self, writer: &mut W, ch: u8) -> io::Result<()>
where W: io::Write;
}
pub struct CompactFormatter;
impl Formatter for CompactFormatter {
fn open<W>(&mut self, writer: &mut W, ch: u8) -> io::Result<()>
where W: io::Write,
{
writer.write_all(&[ch])
}
fn comma<W>(&mut self, writer: &mut W, first: bool) -> io::Result<()>
where W: io::Write,
{
if first {
Ok(())
} else {
writer.write_all(b",")
}
}
fn colon<W>(&mut self, writer: &mut W) -> io::Result<()>
where W: io::Write,
{
writer.write_all(b":")
}
fn close<W>(&mut self, writer: &mut W, ch: u8) -> io::Result<()>
where W: io::Write,
{
writer.write_all(&[ch])
}
}
pub struct PrettyFormatter {
current_indent: usize,
indent: usize,
}
impl Formatter for PrettyFormatter {
fn open<W>(&mut self, writer: &mut W, ch: u8) -> io::Result<()>
where W: io::Write,
{
self.current_indent += self.indent;
writer.write_all(&[ch])
}
fn comma<W>(&mut self, writer: &mut W, first: bool) -> io::Result<()>
where W: io::Write,
{
if first {
try!(writer.write_all(b"\n"));
} else {
try!(writer.write_all(b",\n"));
}
spaces(writer, self.current_indent)
}
fn colon<W>(&mut self, writer: &mut W) -> io::Result<()>
where W: io::Write,
{
writer.write_all(b": ")
}
fn close<W>(&mut self, writer: &mut W, ch: u8) -> io::Result<()>
where W: io::Write,
{
self.current_indent -= self.indent;
try!(writer.write(b"\n"));
try!(spaces(writer, self.current_indent));
writer.write_all(&[ch])
}
}
#[inline] #[inline]
pub fn escape_bytes<W>(wr: &mut W, bytes: &[u8]) -> io::Result<()> pub fn escape_bytes<W>(wr: &mut W, bytes: &[u8]) -> io::Result<()>
where W: io::Write where W: io::Write
@@ -366,7 +414,10 @@ pub fn to_writer_pretty<W, T>(writer: &mut W, value: &T) -> io::Result<()>
where W: io::Write, where W: io::Write,
T: ser::Serialize, T: ser::Serialize,
{ {
let mut ser = Serializer::new_pretty(writer); let mut ser = Serializer::new_with_formatter(writer, PrettyFormatter {
current_indent: 0,
indent: 2,
});
try!(value.serialize(&mut ser)); try!(value.serialize(&mut ser));
Ok(()) Ok(())
} }