From aedd5f57cf581f7698ab2c6aa8c0217c2496f617 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Thu, 12 Mar 2015 21:15:47 -0700 Subject: [PATCH] Split json compact and pretty serializer. Recover 20MB/s --- src/json/ser.rs | 235 +++++++++++++++++++++++++++++------------------- 1 file changed, 143 insertions(+), 92 deletions(-) diff --git a/src/json/ser.rs b/src/json/ser.rs index c6d32309..5544fd51 100644 --- a/src/json/ser.rs +++ b/src/json/ser.rs @@ -6,41 +6,33 @@ use std::string::FromUtf8Error; use ser; /// A structure for implementing serialization to JSON. -pub struct Serializer { +pub struct Serializer { writer: W, - format: Format, - current_indent: usize, - indent: usize, + formatter: F, } -#[derive(Copy, PartialEq)] -enum Format { - Compact, - Pretty, -} - -impl Serializer { +impl Serializer + where W: io::Write, +{ /// Creates a new JSON visitr whose output will be written to the writer /// specified. #[inline] pub fn new(writer: W) -> Serializer { - Serializer { - writer: writer, - format: Format::Compact, - current_indent: 0, - indent: 0, - } + Serializer::new_with_formatter(writer, CompactFormatter) } +} +impl Serializer + where W: io::Write, + F: Formatter, +{ /// Creates a new JSON visitr whose output will be written to the writer /// specified. #[inline] - pub fn new_pretty(writer: W) -> Serializer { + pub fn new_with_formatter(writer: W, formatter: F) -> Serializer { Serializer { writer: writer, - format: Format::Pretty, - current_indent: 0, - indent: 2, + formatter: formatter, } } @@ -49,49 +41,11 @@ impl Serializer { pub fn into_inner(self) -> W { 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 ser::Serializer for Serializer +impl ser::Serializer for Serializer where W: io::Write, + F: Formatter, { type Error = io::Error; @@ -193,48 +147,50 @@ impl ser::Serializer for Serializer #[inline] fn visit_enum_unit(&mut self, _name: &str, variant: &str) -> io::Result<()> { - let current_indent = self.current_indent; - - try!(self.writer.write_all(b"{")); - try!(self.serialize_sep(true)); + try!(self.formatter.open(&mut self.writer, b'{')); + try!(self.formatter.comma(&mut self.writer, true)); try!(self.visit_str(variant)); - try!(self.serialize_colon()); + try!(self.formatter.colon(&mut self.writer)); try!(self.writer.write_all(b"[]")); - self.serialize_end(current_indent, b"}") + self.formatter.close(&mut self.writer, b'}') } #[inline] fn visit_seq(&mut self, mut visitor: V) -> io::Result<()> 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] fn visit_enum_seq(&mut self, _name: &str, variant: &str, visitor: V) -> io::Result<()> where V: ser::SeqVisitor, { - let current_indent = self.current_indent; - - try!(self.writer.write_all(b"{")); - try!(self.serialize_sep(true)); + try!(self.formatter.open(&mut self.writer, b'{')); + try!(self.formatter.comma(&mut self.writer, true)); try!(self.visit_str(variant)); - try!(self.serialize_colon()); + try!(self.formatter.colon(&mut self.writer)); try!(self.visit_seq(visitor)); - self.serialize_end(current_indent, b"}") + self.formatter.close(&mut self.writer, b'}') } #[inline] fn visit_seq_elt(&mut self, first: bool, value: T) -> io::Result<()> where T: ser::Serialize, { - try!(self.serialize_sep(first)); + try!(self.formatter.comma(&mut self.writer, first)); value.serialize(self) } @@ -243,27 +199,31 @@ impl ser::Serializer for Serializer fn visit_map(&mut self, mut visitor: V) -> io::Result<()> 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.serialize_end(current_indent, b"}") + self.formatter.close(&mut self.writer, b'}') + } + } } #[inline] fn visit_enum_map(&mut self, _name: &str, variant: &str, visitor: V) -> io::Result<()> where V: ser::MapVisitor, { - let current_indent = self.current_indent; - - try!(self.writer.write_all(b"{")); - try!(self.serialize_sep(true)); + try!(self.formatter.open(&mut self.writer, b'{')); + try!(self.formatter.comma(&mut self.writer, true)); try!(self.visit_str(variant)); - try!(self.serialize_colon()); + try!(self.formatter.colon(&mut self.writer)); try!(self.visit_map(visitor)); - self.serialize_end(current_indent, b"}") + + self.formatter.close(&mut self.writer, b'}') } #[inline] @@ -271,13 +231,101 @@ impl ser::Serializer for Serializer where K: ser::Serialize, V: ser::Serialize, { - try!(self.serialize_sep(first)); + try!(self.formatter.comma(&mut self.writer, first)); try!(key.serialize(self)); - try!(self.serialize_colon()); + try!(self.formatter.colon(&mut self.writer)); value.serialize(self) } } +pub trait Formatter { + fn open(&mut self, writer: &mut W, ch: u8) -> io::Result<()> + where W: io::Write; + + fn comma(&mut self, writer: &mut W, first: bool) -> io::Result<()> + where W: io::Write; + + fn colon(&mut self, writer: &mut W) -> io::Result<()> + where W: io::Write; + + fn close(&mut self, writer: &mut W, ch: u8) -> io::Result<()> + where W: io::Write; +} + +pub struct CompactFormatter; + +impl Formatter for CompactFormatter { + fn open(&mut self, writer: &mut W, ch: u8) -> io::Result<()> + where W: io::Write, + { + writer.write_all(&[ch]) + } + + fn comma(&mut self, writer: &mut W, first: bool) -> io::Result<()> + where W: io::Write, + { + if first { + Ok(()) + } else { + writer.write_all(b",") + } + } + + fn colon(&mut self, writer: &mut W) -> io::Result<()> + where W: io::Write, + { + writer.write_all(b":") + } + + fn close(&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(&mut self, writer: &mut W, ch: u8) -> io::Result<()> + where W: io::Write, + { + self.current_indent += self.indent; + writer.write_all(&[ch]) + } + + fn comma(&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(&mut self, writer: &mut W) -> io::Result<()> + where W: io::Write, + { + writer.write_all(b": ") + } + + fn close(&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] pub fn escape_bytes(wr: &mut W, bytes: &[u8]) -> io::Result<()> where W: io::Write @@ -366,7 +414,10 @@ pub fn to_writer_pretty(writer: &mut W, value: &T) -> io::Result<()> where W: io::Write, 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)); Ok(()) }