1
Fork 0

serialize: Remove allocations from escaping strs and indenting spaces

This commit is contained in:
Erick Tryzelaar 2014-07-04 11:08:38 -07:00
parent 04ac2b087e
commit 83f9f07ec4

View file

@ -256,22 +256,38 @@ fn io_error_to_error(io: io::IoError) -> ParserError {
pub type EncodeResult = io::IoResult<()>; pub type EncodeResult = io::IoResult<()>;
pub type DecodeResult<T> = Result<T, DecoderError>; pub type DecodeResult<T> = Result<T, DecoderError>;
fn escape_str(s: &str) -> String { fn escape_bytes(writer: &mut io::Writer, s: &[u8]) -> Result<(), io::IoError> {
let mut escaped = String::from_str("\""); try!(writer.write_str("\""));
for c in s.chars() { for byte in s.iter() {
match c { match *byte {
'"' => escaped.push_str("\\\""), b'"' => try!(writer.write_str("\\\"")),
'\\' => escaped.push_str("\\\\"), b'\\' => try!(writer.write_str("\\\\")),
'\x08' => escaped.push_str("\\b"), b'\x08' => try!(writer.write_str("\\b")),
'\x0c' => escaped.push_str("\\f"), b'\x0c' => try!(writer.write_str("\\f")),
'\n' => escaped.push_str("\\n"), b'\n' => try!(writer.write_str("\\n")),
'\r' => escaped.push_str("\\r"), b'\r' => try!(writer.write_str("\\r")),
'\t' => escaped.push_str("\\t"), b'\t' => try!(writer.write_str("\\t")),
_ => escaped.push_char(c), _ => try!(writer.write_u8(*byte)),
} }
}; }
escaped.push_char('"'); writer.write_str("\"")
escaped }
fn escape_str(writer: &mut io::Writer, v: &str) -> Result<(), io::IoError> {
escape_bytes(writer, v.as_bytes())
}
fn escape_char(writer: &mut io::Writer, v: char) -> Result<(), io::IoError> {
let mut buf = [0, .. 4];
v.encode_utf8(buf);
escape_bytes(writer, buf)
}
fn spaces(writer: &mut io::Writer, n: uint) -> Result<(), io::IoError> {
for _ in range(0, n) {
try!(writer.write_str(" "));
}
Ok(())
} }
fn fmt_number_or_null(v: f64) -> String { fn fmt_number_or_null(v: f64) -> String {
@ -281,10 +297,6 @@ fn fmt_number_or_null(v: f64) -> String {
} }
} }
fn spaces(n: uint) -> String {
String::from_char(n, ' ')
}
/// A structure for implementing serialization to JSON. /// A structure for implementing serialization to JSON.
pub struct Encoder<'a> { pub struct Encoder<'a> {
writer: &'a mut io::Writer, writer: &'a mut io::Writer,
@ -348,10 +360,10 @@ impl<'a> ::Encoder<io::IoError> for Encoder<'a> {
fn emit_f32(&mut self, v: f32) -> EncodeResult { self.emit_f64(v as f64) } fn emit_f32(&mut self, v: f32) -> EncodeResult { self.emit_f64(v as f64) }
fn emit_char(&mut self, v: char) -> EncodeResult { fn emit_char(&mut self, v: char) -> EncodeResult {
self.emit_str(str::from_char(v).as_slice()) escape_char(self.writer, v)
} }
fn emit_str(&mut self, v: &str) -> EncodeResult { fn emit_str(&mut self, v: &str) -> EncodeResult {
write!(self.writer, "{}", escape_str(v)) escape_str(self.writer, v)
} }
fn emit_enum(&mut self, _name: &str, f: |&mut Encoder<'a>| -> EncodeResult) -> EncodeResult { fn emit_enum(&mut self, _name: &str, f: |&mut Encoder<'a>| -> EncodeResult) -> EncodeResult {
@ -367,10 +379,10 @@ impl<'a> ::Encoder<io::IoError> for Encoder<'a> {
// Bunny => "Bunny" // Bunny => "Bunny"
// Kangaroo(34,"William") => {"variant": "Kangaroo", "fields": [34,"William"]} // Kangaroo(34,"William") => {"variant": "Kangaroo", "fields": [34,"William"]}
if cnt == 0 { if cnt == 0 {
write!(self.writer, "{}", escape_str(name)) escape_str(self.writer, name)
} else { } else {
try!(write!(self.writer, "{{\"variant\":")); try!(write!(self.writer, "{{\"variant\":"));
try!(write!(self.writer, "{}", escape_str(name))); try!(escape_str(self.writer, name));
try!(write!(self.writer, ",\"fields\":[")); try!(write!(self.writer, ",\"fields\":["));
try!(f(self)); try!(f(self));
write!(self.writer, "]}}") write!(self.writer, "]}}")
@ -415,7 +427,8 @@ impl<'a> ::Encoder<io::IoError> for Encoder<'a> {
idx: uint, idx: uint,
f: |&mut Encoder<'a>| -> EncodeResult) -> EncodeResult { f: |&mut Encoder<'a>| -> EncodeResult) -> EncodeResult {
if idx != 0 { try!(write!(self.writer, ",")); } if idx != 0 { try!(write!(self.writer, ",")); }
try!(write!(self.writer, "{}:", escape_str(name))); try!(escape_str(self.writer, name));
try!(write!(self.writer, ":"));
f(self) f(self)
} }
@ -541,10 +554,10 @@ impl<'a> ::Encoder<io::IoError> for PrettyEncoder<'a> {
} }
fn emit_char(&mut self, v: char) -> EncodeResult { fn emit_char(&mut self, v: char) -> EncodeResult {
self.emit_str(str::from_char(v).as_slice()) escape_char(self.writer, v)
} }
fn emit_str(&mut self, v: &str) -> EncodeResult { fn emit_str(&mut self, v: &str) -> EncodeResult {
write!(self.writer, "{}", escape_str(v)) escape_str(self.writer, v)
} }
fn emit_enum(&mut self, fn emit_enum(&mut self,
@ -559,14 +572,18 @@ impl<'a> ::Encoder<io::IoError> for PrettyEncoder<'a> {
cnt: uint, cnt: uint,
f: |&mut PrettyEncoder<'a>| -> EncodeResult) -> EncodeResult { f: |&mut PrettyEncoder<'a>| -> EncodeResult) -> EncodeResult {
if cnt == 0 { if cnt == 0 {
write!(self.writer, "{}", escape_str(name)) escape_str(self.writer, name)
} else { } else {
self.indent += 2; self.indent += 2;
try!(write!(self.writer, "[\n{}{},\n", spaces(self.indent), try!(write!(self.writer, "[\n"));
escape_str(name))); try!(spaces(self.writer, self.indent));
try!(escape_str(self.writer, name));
try!(write!(self.writer, ",\n"));
try!(f(self)); try!(f(self));
self.indent -= 2; self.indent -= 2;
write!(self.writer, "\n{}]", spaces(self.indent)) try!(write!(self.writer, "\n"));
try!(spaces(self.writer, self.indent));
write!(self.writer, "]")
} }
} }
@ -576,7 +593,7 @@ impl<'a> ::Encoder<io::IoError> for PrettyEncoder<'a> {
if idx != 0 { if idx != 0 {
try!(write!(self.writer, ",\n")); try!(write!(self.writer, ",\n"));
} }
try!(write!(self.writer, "{}", spaces(self.indent))); try!(spaces(self.writer, self.indent));
f(self) f(self)
} }
@ -607,7 +624,9 @@ impl<'a> ::Encoder<io::IoError> for PrettyEncoder<'a> {
self.indent += 2; self.indent += 2;
try!(f(self)); try!(f(self));
self.indent -= 2; self.indent -= 2;
write!(self.writer, "\n{}}}", spaces(self.indent)) try!(write!(self.writer, "\n"));
try!(spaces(self.writer, self.indent));
write!(self.writer, "}}")
} }
} }
@ -620,7 +639,9 @@ impl<'a> ::Encoder<io::IoError> for PrettyEncoder<'a> {
} else { } else {
try!(write!(self.writer, ",\n")); try!(write!(self.writer, ",\n"));
} }
try!(write!(self.writer, "{}{}: ", spaces(self.indent), escape_str(name))); try!(spaces(self.writer, self.indent));
try!(escape_str(self.writer, name));
try!(write!(self.writer, ": "));
f(self) f(self)
} }
@ -665,7 +686,9 @@ impl<'a> ::Encoder<io::IoError> for PrettyEncoder<'a> {
self.indent += 2; self.indent += 2;
try!(f(self)); try!(f(self));
self.indent -= 2; self.indent -= 2;
write!(self.writer, "\n{}]", spaces(self.indent)) try!(write!(self.writer, "\n"));
try!(spaces(self.writer, self.indent));
write!(self.writer, "]")
} }
} }
@ -677,7 +700,7 @@ impl<'a> ::Encoder<io::IoError> for PrettyEncoder<'a> {
} else { } else {
try!(write!(self.writer, ",\n")); try!(write!(self.writer, ",\n"));
} }
try!(write!(self.writer, "{}", spaces(self.indent))); try!(spaces(self.writer, self.indent));
f(self) f(self)
} }
@ -691,7 +714,9 @@ impl<'a> ::Encoder<io::IoError> for PrettyEncoder<'a> {
self.indent += 2; self.indent += 2;
try!(f(self)); try!(f(self));
self.indent -= 2; self.indent -= 2;
write!(self.writer, "\n{}}}", spaces(self.indent)) try!(write!(self.writer, "\n"));
try!(spaces(self.writer, self.indent));
write!(self.writer, "}}")
} }
} }
@ -703,7 +728,7 @@ impl<'a> ::Encoder<io::IoError> for PrettyEncoder<'a> {
} else { } else {
try!(write!(self.writer, ",\n")); try!(write!(self.writer, ",\n"));
} }
try!(write!(self.writer, "{}", spaces(self.indent))); try!(spaces(self.writer, self.indent));
// ref #12967, make sure to wrap a key in double quotes, // ref #12967, make sure to wrap a key in double quotes,
// in the event that its of a type that omits them (eg numbers) // in the event that its of a type that omits them (eg numbers)
let mut buf = MemWriter::new(); let mut buf = MemWriter::new();