]> git.lizzy.rs Git - rust.git/commitdiff
serialize: Remove allocations from escaping strs and indenting spaces
authorErick Tryzelaar <erick.tryzelaar@gmail.com>
Fri, 4 Jul 2014 18:08:38 +0000 (11:08 -0700)
committerErick Tryzelaar <erick.tryzelaar@gmail.com>
Fri, 4 Jul 2014 18:08:38 +0000 (11:08 -0700)
src/libserialize/json.rs

index 832bc9c4e10cbb2c8f6085a2303aaaa92900e8d2..49f929d4658a0c446ea5631e401422780111d2db 100644 (file)
@@ -256,22 +256,38 @@ fn io_error_to_error(io: io::IoError) -> ParserError {
 pub type EncodeResult = io::IoResult<()>;
 pub type DecodeResult<T> = Result<T, DecoderError>;
 
-fn escape_str(s: &str) -> String {
-    let mut escaped = String::from_str("\"");
-    for c in s.chars() {
-        match c {
-            '"' => escaped.push_str("\\\""),
-            '\\' => escaped.push_str("\\\\"),
-            '\x08' => escaped.push_str("\\b"),
-            '\x0c' => escaped.push_str("\\f"),
-            '\n' => escaped.push_str("\\n"),
-            '\r' => escaped.push_str("\\r"),
-            '\t' => escaped.push_str("\\t"),
-            _ => escaped.push_char(c),
-        }
-    };
-    escaped.push_char('"');
-    escaped
+fn escape_bytes(writer: &mut io::Writer, s: &[u8]) -> Result<(), io::IoError> {
+    try!(writer.write_str("\""));
+    for byte in s.iter() {
+        match *byte {
+            b'"' => try!(writer.write_str("\\\"")),
+            b'\\' => try!(writer.write_str("\\\\")),
+            b'\x08' => try!(writer.write_str("\\b")),
+            b'\x0c' => try!(writer.write_str("\\f")),
+            b'\n' => try!(writer.write_str("\\n")),
+            b'\r' => try!(writer.write_str("\\r")),
+            b'\t' => try!(writer.write_str("\\t")),
+            _ => try!(writer.write_u8(*byte)),
+        }
+    }
+    writer.write_str("\"")
+}
+
+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 {
@@ -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.
 pub struct Encoder<'a> {
     writer: &'a mut io::Writer,
@@ -348,10 +360,10 @@ fn emit_f64(&mut self, v: f64) -> EncodeResult {
     fn emit_f32(&mut self, v: f32) -> EncodeResult { self.emit_f64(v as f64) }
 
     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 {
-        write!(self.writer, "{}", escape_str(v))
+        escape_str(self.writer, v)
     }
 
     fn emit_enum(&mut self, _name: &str, f: |&mut Encoder<'a>| -> EncodeResult) -> EncodeResult {
@@ -367,10 +379,10 @@ fn emit_enum_variant(&mut self,
         // Bunny => "Bunny"
         // Kangaroo(34,"William") => {"variant": "Kangaroo", "fields": [34,"William"]}
         if cnt == 0 {
-            write!(self.writer, "{}", escape_str(name))
+            escape_str(self.writer, name)
         } else {
             try!(write!(self.writer, "{{\"variant\":"));
-            try!(write!(self.writer, "{}", escape_str(name)));
+            try!(escape_str(self.writer, name));
             try!(write!(self.writer, ",\"fields\":["));
             try!(f(self));
             write!(self.writer, "]}}")
@@ -415,7 +427,8 @@ fn emit_struct_field(&mut self,
                          idx: uint,
                          f: |&mut Encoder<'a>| -> EncodeResult) -> EncodeResult {
         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)
     }
 
@@ -541,10 +554,10 @@ fn emit_f32(&mut self, v: f32) -> 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 {
-        write!(self.writer, "{}", escape_str(v))
+        escape_str(self.writer, v)
     }
 
     fn emit_enum(&mut self,
@@ -559,14 +572,18 @@ fn emit_enum_variant(&mut self,
                          cnt: uint,
                          f: |&mut PrettyEncoder<'a>| -> EncodeResult) -> EncodeResult {
         if cnt == 0 {
-            write!(self.writer, "{}", escape_str(name))
+            escape_str(self.writer, name)
         } else {
             self.indent += 2;
-            try!(write!(self.writer, "[\n{}{},\n", spaces(self.indent),
-                          escape_str(name)));
+            try!(write!(self.writer, "[\n"));
+            try!(spaces(self.writer, self.indent));
+            try!(escape_str(self.writer, name));
+            try!(write!(self.writer, ",\n"));
             try!(f(self));
             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 @@ fn emit_enum_variant_arg(&mut self,
         if idx != 0 {
             try!(write!(self.writer, ",\n"));
         }
-        try!(write!(self.writer, "{}", spaces(self.indent)));
+        try!(spaces(self.writer, self.indent));
         f(self)
     }
 
@@ -607,7 +624,9 @@ fn emit_struct(&mut self,
             self.indent += 2;
             try!(f(self));
             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 @@ fn emit_struct_field(&mut self,
         } else {
             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)
     }
 
@@ -665,7 +686,9 @@ fn emit_seq(&mut self,
             self.indent += 2;
             try!(f(self));
             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 @@ fn emit_seq_elt(&mut self,
         } else {
             try!(write!(self.writer, ",\n"));
         }
-        try!(write!(self.writer, "{}", spaces(self.indent)));
+        try!(spaces(self.writer, self.indent));
         f(self)
     }
 
@@ -691,7 +714,9 @@ fn emit_map(&mut self,
             self.indent += 2;
             try!(f(self));
             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 @@ fn emit_map_elt_key(&mut self,
         } else {
             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,
         // in the event that its of a type that omits them (eg numbers)
         let mut buf = MemWriter::new();