Skip to content

Commit 9f2a43c

Browse files
committed
auto merge of rust-lang#15419 : erickt/rust/json, r=pcwalton
This speeds up json serialization by removing most of the allocations.
2 parents 459f155 + 67c8a8d commit 9f2a43c

File tree

1 file changed

+87
-37
lines changed

1 file changed

+87
-37
lines changed

src/libserialize/json.rs

+87-37
Original file line numberDiff line numberDiff line change
@@ -256,22 +256,63 @@ fn io_error_to_error(io: io::IoError) -> ParserError {
256256
pub type EncodeResult = io::IoResult<()>;
257257
pub type DecodeResult<T> = Result<T, DecoderError>;
258258

259-
fn escape_str(s: &str) -> String {
260-
let mut escaped = String::from_str("\"");
261-
for c in s.chars() {
262-
match c {
263-
'"' => escaped.push_str("\\\""),
264-
'\\' => escaped.push_str("\\\\"),
265-
'\x08' => escaped.push_str("\\b"),
266-
'\x0c' => escaped.push_str("\\f"),
267-
'\n' => escaped.push_str("\\n"),
268-
'\r' => escaped.push_str("\\r"),
269-
'\t' => escaped.push_str("\\t"),
270-
_ => escaped.push_char(c),
259+
pub fn escape_bytes(wr: &mut io::Writer, bytes: &[u8]) -> Result<(), io::IoError> {
260+
try!(wr.write_str("\""));
261+
262+
let mut start = 0;
263+
264+
for (i, byte) in bytes.iter().enumerate() {
265+
let escaped = match *byte {
266+
b'"' => "\\\"",
267+
b'\\' => "\\\\",
268+
b'\x08' => "\\b",
269+
b'\x0c' => "\\f",
270+
b'\n' => "\\n",
271+
b'\r' => "\\r",
272+
b'\t' => "\\t",
273+
_ => { continue; }
274+
};
275+
276+
if start < i {
277+
try!(wr.write(bytes.slice(start, i)));
271278
}
272-
};
273-
escaped.push_char('"');
274-
escaped
279+
280+
try!(wr.write_str(escaped));
281+
282+
start = i + 1;
283+
}
284+
285+
if start != bytes.len() {
286+
try!(wr.write(bytes.slice_from(start)));
287+
}
288+
289+
wr.write_str("\"")
290+
}
291+
292+
fn escape_str(writer: &mut io::Writer, v: &str) -> Result<(), io::IoError> {
293+
escape_bytes(writer, v.as_bytes())
294+
}
295+
296+
fn escape_char(writer: &mut io::Writer, v: char) -> Result<(), io::IoError> {
297+
let mut buf = [0, .. 4];
298+
v.encode_utf8(buf);
299+
escape_bytes(writer, buf)
300+
}
301+
302+
fn spaces(wr: &mut io::Writer, mut n: uint) -> Result<(), io::IoError> {
303+
static len: uint = 16;
304+
static buf: [u8, ..len] = [b' ', ..len];
305+
306+
while n >= len {
307+
try!(wr.write(buf));
308+
n -= len;
309+
}
310+
311+
if n > 0 {
312+
wr.write(buf.slice_to(n))
313+
} else {
314+
Ok(())
315+
}
275316
}
276317

277318
fn fmt_number_or_null(v: f64) -> String {
@@ -281,10 +322,6 @@ fn fmt_number_or_null(v: f64) -> String {
281322
}
282323
}
283324

284-
fn spaces(n: uint) -> String {
285-
String::from_char(n, ' ')
286-
}
287-
288325
/// A structure for implementing serialization to JSON.
289326
pub struct Encoder<'a> {
290327
writer: &'a mut io::Writer,
@@ -348,10 +385,10 @@ impl<'a> ::Encoder<io::IoError> for Encoder<'a> {
348385
fn emit_f32(&mut self, v: f32) -> EncodeResult { self.emit_f64(v as f64) }
349386

350387
fn emit_char(&mut self, v: char) -> EncodeResult {
351-
self.emit_str(str::from_char(v).as_slice())
388+
escape_char(self.writer, v)
352389
}
353390
fn emit_str(&mut self, v: &str) -> EncodeResult {
354-
write!(self.writer, "{}", escape_str(v))
391+
escape_str(self.writer, v)
355392
}
356393

357394
fn emit_enum(&mut self, _name: &str, f: |&mut Encoder<'a>| -> EncodeResult) -> EncodeResult {
@@ -367,10 +404,10 @@ impl<'a> ::Encoder<io::IoError> for Encoder<'a> {
367404
// Bunny => "Bunny"
368405
// Kangaroo(34,"William") => {"variant": "Kangaroo", "fields": [34,"William"]}
369406
if cnt == 0 {
370-
write!(self.writer, "{}", escape_str(name))
407+
escape_str(self.writer, name)
371408
} else {
372409
try!(write!(self.writer, "{{\"variant\":"));
373-
try!(write!(self.writer, "{}", escape_str(name)));
410+
try!(escape_str(self.writer, name));
374411
try!(write!(self.writer, ",\"fields\":["));
375412
try!(f(self));
376413
write!(self.writer, "]}}")
@@ -415,7 +452,8 @@ impl<'a> ::Encoder<io::IoError> for Encoder<'a> {
415452
idx: uint,
416453
f: |&mut Encoder<'a>| -> EncodeResult) -> EncodeResult {
417454
if idx != 0 { try!(write!(self.writer, ",")); }
418-
try!(write!(self.writer, "{}:", escape_str(name)));
455+
try!(escape_str(self.writer, name));
456+
try!(write!(self.writer, ":"));
419457
f(self)
420458
}
421459

@@ -541,10 +579,10 @@ impl<'a> ::Encoder<io::IoError> for PrettyEncoder<'a> {
541579
}
542580

543581
fn emit_char(&mut self, v: char) -> EncodeResult {
544-
self.emit_str(str::from_char(v).as_slice())
582+
escape_char(self.writer, v)
545583
}
546584
fn emit_str(&mut self, v: &str) -> EncodeResult {
547-
write!(self.writer, "{}", escape_str(v))
585+
escape_str(self.writer, v)
548586
}
549587

550588
fn emit_enum(&mut self,
@@ -559,14 +597,18 @@ impl<'a> ::Encoder<io::IoError> for PrettyEncoder<'a> {
559597
cnt: uint,
560598
f: |&mut PrettyEncoder<'a>| -> EncodeResult) -> EncodeResult {
561599
if cnt == 0 {
562-
write!(self.writer, "{}", escape_str(name))
600+
escape_str(self.writer, name)
563601
} else {
564602
self.indent += 2;
565-
try!(write!(self.writer, "[\n{}{},\n", spaces(self.indent),
566-
escape_str(name)));
603+
try!(write!(self.writer, "[\n"));
604+
try!(spaces(self.writer, self.indent));
605+
try!(escape_str(self.writer, name));
606+
try!(write!(self.writer, ",\n"));
567607
try!(f(self));
568608
self.indent -= 2;
569-
write!(self.writer, "\n{}]", spaces(self.indent))
609+
try!(write!(self.writer, "\n"));
610+
try!(spaces(self.writer, self.indent));
611+
write!(self.writer, "]")
570612
}
571613
}
572614

@@ -576,7 +618,7 @@ impl<'a> ::Encoder<io::IoError> for PrettyEncoder<'a> {
576618
if idx != 0 {
577619
try!(write!(self.writer, ",\n"));
578620
}
579-
try!(write!(self.writer, "{}", spaces(self.indent)));
621+
try!(spaces(self.writer, self.indent));
580622
f(self)
581623
}
582624

@@ -607,7 +649,9 @@ impl<'a> ::Encoder<io::IoError> for PrettyEncoder<'a> {
607649
self.indent += 2;
608650
try!(f(self));
609651
self.indent -= 2;
610-
write!(self.writer, "\n{}}}", spaces(self.indent))
652+
try!(write!(self.writer, "\n"));
653+
try!(spaces(self.writer, self.indent));
654+
write!(self.writer, "}}")
611655
}
612656
}
613657

@@ -620,7 +664,9 @@ impl<'a> ::Encoder<io::IoError> for PrettyEncoder<'a> {
620664
} else {
621665
try!(write!(self.writer, ",\n"));
622666
}
623-
try!(write!(self.writer, "{}{}: ", spaces(self.indent), escape_str(name)));
667+
try!(spaces(self.writer, self.indent));
668+
try!(escape_str(self.writer, name));
669+
try!(write!(self.writer, ": "));
624670
f(self)
625671
}
626672

@@ -665,7 +711,9 @@ impl<'a> ::Encoder<io::IoError> for PrettyEncoder<'a> {
665711
self.indent += 2;
666712
try!(f(self));
667713
self.indent -= 2;
668-
write!(self.writer, "\n{}]", spaces(self.indent))
714+
try!(write!(self.writer, "\n"));
715+
try!(spaces(self.writer, self.indent));
716+
write!(self.writer, "]")
669717
}
670718
}
671719

@@ -677,7 +725,7 @@ impl<'a> ::Encoder<io::IoError> for PrettyEncoder<'a> {
677725
} else {
678726
try!(write!(self.writer, ",\n"));
679727
}
680-
try!(write!(self.writer, "{}", spaces(self.indent)));
728+
try!(spaces(self.writer, self.indent));
681729
f(self)
682730
}
683731

@@ -691,7 +739,9 @@ impl<'a> ::Encoder<io::IoError> for PrettyEncoder<'a> {
691739
self.indent += 2;
692740
try!(f(self));
693741
self.indent -= 2;
694-
write!(self.writer, "\n{}}}", spaces(self.indent))
742+
try!(write!(self.writer, "\n"));
743+
try!(spaces(self.writer, self.indent));
744+
write!(self.writer, "}}")
695745
}
696746
}
697747

@@ -703,7 +753,7 @@ impl<'a> ::Encoder<io::IoError> for PrettyEncoder<'a> {
703753
} else {
704754
try!(write!(self.writer, ",\n"));
705755
}
706-
try!(write!(self.writer, "{}", spaces(self.indent)));
756+
try!(spaces(self.writer, self.indent));
707757
// ref #12967, make sure to wrap a key in double quotes,
708758
// in the event that its of a type that omits them (eg numbers)
709759
let mut buf = MemWriter::new();

0 commit comments

Comments
 (0)