From af9fe922f3ead4c25fee5911bb72d0136b77002f Mon Sep 17 00:00:00 2001 From: Oliver 'ker' Schneider Date: Sat, 10 Jan 2015 10:14:19 +0100 Subject: [PATCH 1/6] json-encoder: report error when hash map key is not string or numeric --- src/libserialize/json.rs | 232 ++++++++++++++++++++++++++------------- 1 file changed, 154 insertions(+), 78 deletions(-) diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 62acef2ca1cc7..7cfd15f4772e1 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -202,7 +202,7 @@ use self::InternalStackElement::*; use std; use std::collections::{HashMap, BTreeMap}; use std::{char, f64, fmt, io, num, str}; -use std::mem::{swap, transmute}; +use std::mem::{swap}; use std::num::{Float, Int}; use std::num::FpCategory as Fp; use std::str::FromStr; @@ -275,6 +275,12 @@ pub enum DecoderError { ApplicationError(string::String) } +#[derive(Copy, Show)] +pub enum EncoderError { + FmtError(fmt::Error), + BadHashmapKey, +} + /// Returns a readable error string for a given error code. pub fn error_str(error: ErrorCode) -> &'static str { match error { @@ -334,10 +340,19 @@ impl std::error::Error for DecoderError { fn detail(&self) -> Option { Some(format!("{:?}", self)) } } -pub type EncodeResult = fmt::Result; +impl std::error::Error for EncoderError { + fn description(&self) -> &str { "encoder error" } + fn detail(&self) -> Option { Some(format!("{:?}", self)) } +} + +impl std::error::FromError for EncoderError { + fn from_error(err: fmt::Error) -> EncoderError { EncoderError::FmtError(err) } +} + +pub type EncodeResult = Result<(), EncoderError>; pub type DecodeResult = Result; -fn escape_str(wr: &mut fmt::Writer, v: &str) -> fmt::Result { +fn escape_str(wr: &mut fmt::Writer, v: &str) -> EncodeResult { try!(wr.write_str("\"")); let mut start = 0; @@ -395,17 +410,18 @@ fn escape_str(wr: &mut fmt::Writer, v: &str) -> fmt::Result { try!(wr.write_str(&v[start..])); } - wr.write_str("\"") + try!(wr.write_str("\"")); + Ok(()) } -fn escape_char(writer: &mut fmt::Writer, v: char) -> fmt::Result { +fn escape_char(writer: &mut fmt::Writer, v: char) -> EncodeResult { let mut buf = [0; 4]; let n = v.encode_utf8(&mut buf).unwrap(); let buf = unsafe { str::from_utf8_unchecked(&buf[0..n]) }; escape_str(writer, buf) } -fn spaces(wr: &mut fmt::Writer, mut n: uint) -> fmt::Result { +fn spaces(wr: &mut fmt::Writer, mut n: uint) -> EncodeResult { const BUF: &'static str = " "; while n >= BUF.len() { @@ -414,10 +430,9 @@ fn spaces(wr: &mut fmt::Writer, mut n: uint) -> fmt::Result { } if n > 0 { - wr.write_str(&BUF[0..n]) - } else { - Ok(()) + try!(wr.write_str(&BUF[0..n])); } + Ok(()) } fn fmt_number_or_null(v: f64) -> string::String { @@ -431,43 +446,62 @@ fn fmt_number_or_null(v: f64) -> string::String { /// A structure for implementing serialization to JSON. pub struct Encoder<'a> { writer: &'a mut (fmt::Writer+'a), + is_emitting_map_key: bool, } impl<'a> Encoder<'a> { /// Creates a new JSON encoder whose output will be written to the writer /// specified. pub fn new(writer: &'a mut fmt::Writer) -> Encoder<'a> { - Encoder { writer: writer } + Encoder { writer: writer, is_emitting_map_key: false, } + } +} + +macro_rules! emit_enquoted_if_mapkey { + ($enc:ident,$e:expr) => { + if $enc.is_emitting_map_key { + try!(write!($enc.writer, "\"{}\"", $e)); + Ok(()) + } else { + try!(write!($enc.writer, "{}", $e)); + Ok(()) + } } } impl<'a> ::Encoder for Encoder<'a> { - type Error = fmt::Error; + type Error = EncoderError; - fn emit_nil(&mut self) -> EncodeResult { write!(self.writer, "null") } + fn emit_nil(&mut self) -> EncodeResult { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } + try!(write!(self.writer, "null")); + Ok(()) + } - fn emit_uint(&mut self, v: uint) -> EncodeResult { write!(self.writer, "{}", v) } - fn emit_u64(&mut self, v: u64) -> EncodeResult { write!(self.writer, "{}", v) } - fn emit_u32(&mut self, v: u32) -> EncodeResult { write!(self.writer, "{}", v) } - fn emit_u16(&mut self, v: u16) -> EncodeResult { write!(self.writer, "{}", v) } - fn emit_u8(&mut self, v: u8) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_uint(&mut self, v: uint) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } + fn emit_u64(&mut self, v: u64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } + fn emit_u32(&mut self, v: u32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } + fn emit_u16(&mut self, v: u16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } + fn emit_u8(&mut self, v: u8) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - fn emit_int(&mut self, v: int) -> EncodeResult { write!(self.writer, "{}", v) } - fn emit_i64(&mut self, v: i64) -> EncodeResult { write!(self.writer, "{}", v) } - fn emit_i32(&mut self, v: i32) -> EncodeResult { write!(self.writer, "{}", v) } - fn emit_i16(&mut self, v: i16) -> EncodeResult { write!(self.writer, "{}", v) } - fn emit_i8(&mut self, v: i8) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_int(&mut self, v: int) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } + fn emit_i64(&mut self, v: i64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } + fn emit_i32(&mut self, v: i32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } + fn emit_i16(&mut self, v: i16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } + fn emit_i8(&mut self, v: i8) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_bool(&mut self, v: bool) -> EncodeResult { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } if v { - write!(self.writer, "true") + try!(write!(self.writer, "true")); } else { - write!(self.writer, "false") + try!(write!(self.writer, "false")); } + Ok(()) } fn emit_f64(&mut self, v: f64) -> EncodeResult { - write!(self.writer, "{}", fmt_number_or_null(v)) + emit_enquoted_if_mapkey!(self, fmt_number_or_null(v)) } fn emit_f32(&mut self, v: f32) -> EncodeResult { self.emit_f64(v as f64) @@ -483,6 +517,7 @@ impl<'a> ::Encoder for Encoder<'a> { fn emit_enum(&mut self, _name: &str, f: F) -> EncodeResult where F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } f(self) } @@ -496,6 +531,7 @@ impl<'a> ::Encoder for Encoder<'a> { // enums are encoded as strings or objects // Bunny => "Bunny" // Kangaroo(34,"William") => {"variant": "Kangaroo", "fields": [34,"William"]} + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } if cnt == 0 { escape_str(self.writer, name) } else { @@ -503,13 +539,15 @@ impl<'a> ::Encoder for Encoder<'a> { try!(escape_str(self.writer, name)); try!(write!(self.writer, ",\"fields\":[")); try!(f(self)); - write!(self.writer, "]}}") + try!(write!(self.writer, "]}}")); + Ok(()) } } fn emit_enum_variant_arg(&mut self, idx: uint, f: F) -> EncodeResult where F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } if idx != 0 { try!(write!(self.writer, ",")); } @@ -523,6 +561,7 @@ impl<'a> ::Encoder for Encoder<'a> { f: F) -> EncodeResult where F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } self.emit_enum_variant(name, id, cnt, f) } @@ -532,20 +571,24 @@ impl<'a> ::Encoder for Encoder<'a> { f: F) -> EncodeResult where F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } self.emit_enum_variant_arg(idx, f) } fn emit_struct(&mut self, _: &str, _: uint, f: F) -> EncodeResult where F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } try!(write!(self.writer, "{{")); try!(f(self)); - write!(self.writer, "}}") + try!(write!(self.writer, "}}")); + Ok(()) } fn emit_struct_field(&mut self, name: &str, idx: uint, f: F) -> EncodeResult where F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } if idx != 0 { try!(write!(self.writer, ",")); } try!(escape_str(self.writer, name)); try!(write!(self.writer, ":")); @@ -555,48 +598,60 @@ impl<'a> ::Encoder for Encoder<'a> { fn emit_tuple(&mut self, len: uint, f: F) -> EncodeResult where F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } self.emit_seq(len, f) } fn emit_tuple_arg(&mut self, idx: uint, f: F) -> EncodeResult where F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } self.emit_seq_elt(idx, f) } fn emit_tuple_struct(&mut self, _name: &str, len: uint, f: F) -> EncodeResult where F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } self.emit_seq(len, f) } fn emit_tuple_struct_arg(&mut self, idx: uint, f: F) -> EncodeResult where F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } self.emit_seq_elt(idx, f) } fn emit_option(&mut self, f: F) -> EncodeResult where F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } f(self) } - fn emit_option_none(&mut self) -> EncodeResult { self.emit_nil() } + fn emit_option_none(&mut self) -> EncodeResult { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } + self.emit_nil() + } fn emit_option_some(&mut self, f: F) -> EncodeResult where F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } f(self) } fn emit_seq(&mut self, _len: uint, f: F) -> EncodeResult where F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } try!(write!(self.writer, "[")); try!(f(self)); - write!(self.writer, "]") + try!(write!(self.writer, "]")); + Ok(()) } fn emit_seq_elt(&mut self, idx: uint, f: F) -> EncodeResult where F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } if idx != 0 { try!(write!(self.writer, ",")); } @@ -606,34 +661,28 @@ impl<'a> ::Encoder for Encoder<'a> { fn emit_map(&mut self, _len: uint, f: F) -> EncodeResult where F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } try!(write!(self.writer, "{{")); try!(f(self)); - write!(self.writer, "}}") + try!(write!(self.writer, "}}")); + Ok(()) } fn emit_map_elt_key(&mut self, idx: uint, mut f: F) -> EncodeResult where F: FnMut(&mut Encoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } if idx != 0 { try!(write!(self.writer, ",")) } - // 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 = Vec::new(); - // FIXME(14302) remove the transmute and unsafe block. - unsafe { - let mut check_encoder = Encoder::new(&mut buf); - try!(f(transmute(&mut check_encoder))); - } - let out = str::from_utf8(&buf[]).unwrap(); - let needs_wrapping = out.char_at(0) != '"' && out.char_at_reverse(out.len()) != '"'; - if needs_wrapping { try!(write!(self.writer, "\"")); } + self.is_emitting_map_key = true; try!(f(self)); - if needs_wrapping { try!(write!(self.writer, "\"")); } + self.is_emitting_map_key = false; Ok(()) } fn emit_map_elt_val(&mut self, _idx: uint, f: F) -> EncodeResult where F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } try!(write!(self.writer, ":")); f(self) } @@ -645,12 +694,18 @@ pub struct PrettyEncoder<'a> { writer: &'a mut (fmt::Writer+'a), curr_indent: uint, indent: uint, + is_emitting_map_key: bool, } impl<'a> PrettyEncoder<'a> { /// Creates a new encoder whose output will be written to the specified writer pub fn new(writer: &'a mut fmt::Writer) -> PrettyEncoder<'a> { - PrettyEncoder { writer: writer, curr_indent: 0, indent: 2, } + PrettyEncoder { + writer: writer, + curr_indent: 0, + indent: 2, + is_emitting_map_key: false, + } } /// Set the number of spaces to indent for each level. @@ -664,32 +719,38 @@ impl<'a> PrettyEncoder<'a> { } impl<'a> ::Encoder for PrettyEncoder<'a> { - type Error = fmt::Error; + type Error = EncoderError; - fn emit_nil(&mut self) -> EncodeResult { write!(self.writer, "null") } + fn emit_nil(&mut self) -> EncodeResult { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } + try!(write!(self.writer, "null")); + Ok(()) + } - fn emit_uint(&mut self, v: uint) -> EncodeResult { write!(self.writer, "{}", v) } - fn emit_u64(&mut self, v: u64) -> EncodeResult { write!(self.writer, "{}", v) } - fn emit_u32(&mut self, v: u32) -> EncodeResult { write!(self.writer, "{}", v) } - fn emit_u16(&mut self, v: u16) -> EncodeResult { write!(self.writer, "{}", v) } - fn emit_u8(&mut self, v: u8) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_uint(&mut self, v: uint) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } + fn emit_u64(&mut self, v: u64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } + fn emit_u32(&mut self, v: u32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } + fn emit_u16(&mut self, v: u16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } + fn emit_u8(&mut self, v: u8) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - fn emit_int(&mut self, v: int) -> EncodeResult { write!(self.writer, "{}", v) } - fn emit_i64(&mut self, v: i64) -> EncodeResult { write!(self.writer, "{}", v) } - fn emit_i32(&mut self, v: i32) -> EncodeResult { write!(self.writer, "{}", v) } - fn emit_i16(&mut self, v: i16) -> EncodeResult { write!(self.writer, "{}", v) } - fn emit_i8(&mut self, v: i8) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_int(&mut self, v: int) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } + fn emit_i64(&mut self, v: i64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } + fn emit_i32(&mut self, v: i32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } + fn emit_i16(&mut self, v: i16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } + fn emit_i8(&mut self, v: i8) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_bool(&mut self, v: bool) -> EncodeResult { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } if v { - write!(self.writer, "true") + try!(write!(self.writer, "true")); } else { - write!(self.writer, "false") + try!(write!(self.writer, "false")); } + Ok(()) } fn emit_f64(&mut self, v: f64) -> EncodeResult { - write!(self.writer, "{}", fmt_number_or_null(v)) + emit_enquoted_if_mapkey!(self, fmt_number_or_null(v)) } fn emit_f32(&mut self, v: f32) -> EncodeResult { self.emit_f64(v as f64) @@ -705,6 +766,7 @@ impl<'a> ::Encoder for PrettyEncoder<'a> { fn emit_enum(&mut self, _name: &str, f: F) -> EncodeResult where F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } f(self) } @@ -716,6 +778,7 @@ impl<'a> ::Encoder for PrettyEncoder<'a> { -> EncodeResult where F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } if cnt == 0 { escape_str(self.writer, name) } else { @@ -735,13 +798,15 @@ impl<'a> ::Encoder for PrettyEncoder<'a> { self.curr_indent -= self.indent; try!(write!(self.writer, "]\n")); try!(spaces(self.writer, self.curr_indent)); - write!(self.writer, "}}") + try!(write!(self.writer, "}}")); + Ok(()) } } fn emit_enum_variant_arg(&mut self, idx: uint, f: F) -> EncodeResult where F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } if idx != 0 { try!(write!(self.writer, ",\n")); } @@ -756,6 +821,7 @@ impl<'a> ::Encoder for PrettyEncoder<'a> { f: F) -> EncodeResult where F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } self.emit_enum_variant(name, id, cnt, f) } @@ -765,6 +831,7 @@ impl<'a> ::Encoder for PrettyEncoder<'a> { f: F) -> EncodeResult where F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } self.emit_enum_variant_arg(idx, f) } @@ -772,8 +839,9 @@ impl<'a> ::Encoder for PrettyEncoder<'a> { fn emit_struct(&mut self, _: &str, len: uint, f: F) -> EncodeResult where F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } if len == 0 { - write!(self.writer, "{{}}") + try!(write!(self.writer, "{{}}")); } else { try!(write!(self.writer, "{{")); self.curr_indent += self.indent; @@ -781,13 +849,15 @@ impl<'a> ::Encoder for PrettyEncoder<'a> { self.curr_indent -= self.indent; try!(write!(self.writer, "\n")); try!(spaces(self.writer, self.curr_indent)); - write!(self.writer, "}}") + try!(write!(self.writer, "}}")); } + Ok(()) } fn emit_struct_field(&mut self, name: &str, idx: uint, f: F) -> EncodeResult where F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } if idx == 0 { try!(write!(self.writer, "\n")); } else { @@ -802,42 +872,52 @@ impl<'a> ::Encoder for PrettyEncoder<'a> { fn emit_tuple(&mut self, len: uint, f: F) -> EncodeResult where F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } self.emit_seq(len, f) } fn emit_tuple_arg(&mut self, idx: uint, f: F) -> EncodeResult where F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } self.emit_seq_elt(idx, f) } fn emit_tuple_struct(&mut self, _: &str, len: uint, f: F) -> EncodeResult where F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } self.emit_seq(len, f) } fn emit_tuple_struct_arg(&mut self, idx: uint, f: F) -> EncodeResult where F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } self.emit_seq_elt(idx, f) } fn emit_option(&mut self, f: F) -> EncodeResult where F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } f(self) } - fn emit_option_none(&mut self) -> EncodeResult { self.emit_nil() } + fn emit_option_none(&mut self) -> EncodeResult { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } + self.emit_nil() + } fn emit_option_some(&mut self, f: F) -> EncodeResult where F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } f(self) } fn emit_seq(&mut self, len: uint, f: F) -> EncodeResult where F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } if len == 0 { - write!(self.writer, "[]") + try!(write!(self.writer, "[]")); } else { try!(write!(self.writer, "[")); self.curr_indent += self.indent; @@ -845,13 +925,15 @@ impl<'a> ::Encoder for PrettyEncoder<'a> { self.curr_indent -= self.indent; try!(write!(self.writer, "\n")); try!(spaces(self.writer, self.curr_indent)); - write!(self.writer, "]") + try!(write!(self.writer, "]")); } + Ok(()) } fn emit_seq_elt(&mut self, idx: uint, f: F) -> EncodeResult where F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } if idx == 0 { try!(write!(self.writer, "\n")); } else { @@ -864,8 +946,9 @@ impl<'a> ::Encoder for PrettyEncoder<'a> { fn emit_map(&mut self, len: uint, f: F) -> EncodeResult where F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } if len == 0 { - write!(self.writer, "{{}}") + try!(write!(self.writer, "{{}}")); } else { try!(write!(self.writer, "{{")); self.curr_indent += self.indent; @@ -873,38 +956,31 @@ impl<'a> ::Encoder for PrettyEncoder<'a> { self.curr_indent -= self.indent; try!(write!(self.writer, "\n")); try!(spaces(self.writer, self.curr_indent)); - write!(self.writer, "}}") + try!(write!(self.writer, "}}")); } + Ok(()) } fn emit_map_elt_key(&mut self, idx: uint, mut f: F) -> EncodeResult where F: FnMut(&mut PrettyEncoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } if idx == 0 { try!(write!(self.writer, "\n")); } else { try!(write!(self.writer, ",\n")); } try!(spaces(self.writer, self.curr_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 = Vec::new(); - // FIXME(14302) remove the transmute and unsafe block. - unsafe { - let mut check_encoder = PrettyEncoder::new(&mut buf); - try!(f(transmute(&mut check_encoder))); - } - let out = str::from_utf8(&buf[]).unwrap(); - let needs_wrapping = out.char_at(0) != '"' && out.char_at_reverse(out.len()) != '"'; - if needs_wrapping { try!(write!(self.writer, "\"")); } + self.is_emitting_map_key = true; try!(f(self)); - if needs_wrapping { try!(write!(self.writer, "\"")); } + self.is_emitting_map_key = false; Ok(()) } fn emit_map_elt_val(&mut self, _idx: uint, f: F) -> EncodeResult where F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } try!(write!(self.writer, ": ")); f(self) } From 0392273bc54904d1bd6203587e4e1546cbbf1f6a Mon Sep 17 00:00:00 2001 From: Oliver 'ker' Schneider Date: Sat, 10 Jan 2015 10:14:32 +0100 Subject: [PATCH 2/6] lower FnMut to FnOnce since json-hack is no longer required Conflicts: src/libserialize/serialize.rs --- src/librbml/lib.rs | 4 ++-- src/libserialize/json.rs | 8 ++++---- src/libserialize/serialize.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs index 6a7062a419e59..20bc5acaa14e5 100644 --- a/src/librbml/lib.rs +++ b/src/librbml/lib.rs @@ -1058,8 +1058,8 @@ pub mod writer { self.end_tag() } - fn emit_map_elt_key(&mut self, _idx: uint, mut f: F) -> EncodeResult where - F: FnMut(&mut Encoder<'a, W>) -> EncodeResult, + fn emit_map_elt_key(&mut self, _idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, { try!(self.start_tag(EsMapKey as uint)); diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 7cfd15f4772e1..2c298a78f7a4d 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -668,8 +668,8 @@ impl<'a> ::Encoder for Encoder<'a> { Ok(()) } - fn emit_map_elt_key(&mut self, idx: uint, mut f: F) -> EncodeResult where - F: FnMut(&mut Encoder<'a>) -> EncodeResult, + fn emit_map_elt_key(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } if idx != 0 { try!(write!(self.writer, ",")) } @@ -961,8 +961,8 @@ impl<'a> ::Encoder for PrettyEncoder<'a> { Ok(()) } - fn emit_map_elt_key(&mut self, idx: uint, mut f: F) -> EncodeResult where - F: FnMut(&mut PrettyEncoder<'a>) -> EncodeResult, + fn emit_map_elt_key(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } if idx == 0 { diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index fe2d57486a88e..e93d71a9dff4a 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -98,7 +98,7 @@ pub trait Encoder { fn emit_map(&mut self, len: uint, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error>; fn emit_map_elt_key(&mut self, idx: uint, f: F) -> Result<(), Self::Error> - where F: FnMut(&mut Self) -> Result<(), Self::Error>; + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; fn emit_map_elt_val(&mut self, idx: uint, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error>; } From 3fb5c9443c5b5358d60854e135abe07b4a2ac7c4 Mon Sep 17 00:00:00 2001 From: Oliver 'ker' Schneider Date: Sat, 10 Jan 2015 10:14:38 +0100 Subject: [PATCH 3/6] add unit test for non string/numeric map keys --- src/libserialize/json.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 2c298a78f7a4d..c2cffc835eee6 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -2583,7 +2583,7 @@ mod tests { use super::DecoderError::*; use super::JsonEvent::*; use super::{Json, from_str, DecodeResult, DecoderError, JsonEvent, Parser, - StackElement, Stack, Decoder}; + StackElement, Stack, Decoder, Encoder, EncoderError}; use std::{i64, u64, f32, f64, io}; use std::collections::BTreeMap; use std::num::Float; @@ -3892,6 +3892,25 @@ mod tests { assert_eq!(None::.to_json(), Null); } + #[test] + fn test_encode_hashmap_with_arbitrary_key() { + use std::str::from_utf8; + use std::io::Writer; + use std::collections::HashMap; + use std::fmt; + #[derive(PartialEq, Eq, Hash, RustcEncodable)] + struct ArbitraryType(uint); + let mut hm: HashMap = HashMap::new(); + hm.insert(ArbitraryType(1), true); + let mut mem_buf = Vec::new(); + let mut encoder = Encoder::new(&mut mem_buf as &mut fmt::Writer); + let result = hm.encode(&mut encoder); + match result.unwrap_err() { + EncoderError::BadHashmapKey => (), + _ => panic!("expected bad hash map key") + } + } + #[bench] fn bench_streaming_small(b: &mut Bencher) { b.iter( || { From 0980eafc9e0d4d9b8843acc2f98e5e6bca25e710 Mon Sep 17 00:00:00 2001 From: Oliver 'ker' Schneider Date: Sat, 10 Jan 2015 10:13:11 +0100 Subject: [PATCH 4/6] ugly hack to convert BadHashMapKey error to general fmt::Error --- src/libserialize/json.rs | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index c2cffc835eee6..309edde3ec137 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -2512,7 +2512,10 @@ struct FormatShim<'a, 'b: 'a> { impl<'a, 'b> fmt::Writer for FormatShim<'a, 'b> { fn write_str(&mut self, s: &str) -> fmt::Result { - self.inner.write_str(s) + match self.inner.write_str(s) { + Ok(_) => Ok(()), + Err(_) => Err(fmt::Error) + } } } @@ -2521,7 +2524,10 @@ impl fmt::String for Json { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut shim = FormatShim { inner: f }; let mut encoder = Encoder::new(&mut shim); - self.encode(&mut encoder) + match self.encode(&mut encoder) { + Ok(_) => Ok(()), + Err(_) => Err(fmt::Error) + } } } @@ -2530,7 +2536,10 @@ impl<'a> fmt::String for PrettyJson<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut shim = FormatShim { inner: f }; let mut encoder = PrettyEncoder::new(&mut shim); - self.inner.encode(&mut encoder) + match self.inner.encode(&mut encoder) { + Ok(_) => Ok(()), + Err(_) => Err(fmt::Error) + } } } @@ -2539,7 +2548,10 @@ impl<'a, T: Encodable> fmt::String for AsJson<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut shim = FormatShim { inner: f }; let mut encoder = Encoder::new(&mut shim); - self.inner.encode(&mut encoder) + match self.inner.encode(&mut encoder) { + Ok(_) => Ok(()), + Err(_) => Err(fmt::Error) + } } } @@ -2560,7 +2572,10 @@ impl<'a, T: Encodable> fmt::String for AsPrettyJson<'a, T> { Some(n) => encoder.set_indent(n), None => {} } - self.inner.encode(&mut encoder) + match self.inner.encode(&mut encoder) { + Ok(_) => Ok(()), + Err(_) => Err(fmt::Error) + } } } From 58a90c4a04f2c59c561906e8a5ffbad16cff5a89 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 13 Jan 2015 13:20:09 +0100 Subject: [PATCH 5/6] make next commit more readable --- src/libserialize/json.rs | 233 --------------------------------------- 1 file changed, 233 deletions(-) diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 309edde3ec137..7de63823a5aba 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -443,20 +443,6 @@ fn fmt_number_or_null(v: f64) -> string::String { } } -/// A structure for implementing serialization to JSON. -pub struct Encoder<'a> { - writer: &'a mut (fmt::Writer+'a), - is_emitting_map_key: bool, -} - -impl<'a> Encoder<'a> { - /// Creates a new JSON encoder whose output will be written to the writer - /// specified. - pub fn new(writer: &'a mut fmt::Writer) -> Encoder<'a> { - Encoder { writer: writer, is_emitting_map_key: false, } - } -} - macro_rules! emit_enquoted_if_mapkey { ($enc:ident,$e:expr) => { if $enc.is_emitting_map_key { @@ -469,225 +455,6 @@ macro_rules! emit_enquoted_if_mapkey { } } -impl<'a> ::Encoder for Encoder<'a> { - type Error = EncoderError; - - fn emit_nil(&mut self) -> EncodeResult { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - try!(write!(self.writer, "null")); - Ok(()) - } - - fn emit_uint(&mut self, v: uint) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - fn emit_u64(&mut self, v: u64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - fn emit_u32(&mut self, v: u32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - fn emit_u16(&mut self, v: u16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - fn emit_u8(&mut self, v: u8) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - - fn emit_int(&mut self, v: int) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - fn emit_i64(&mut self, v: i64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - fn emit_i32(&mut self, v: i32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - fn emit_i16(&mut self, v: i16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - fn emit_i8(&mut self, v: i8) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - - fn emit_bool(&mut self, v: bool) -> EncodeResult { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - if v { - try!(write!(self.writer, "true")); - } else { - try!(write!(self.writer, "false")); - } - Ok(()) - } - - fn emit_f64(&mut self, v: f64) -> EncodeResult { - emit_enquoted_if_mapkey!(self, fmt_number_or_null(v)) - } - fn emit_f32(&mut self, v: f32) -> EncodeResult { - self.emit_f64(v as f64) - } - - fn emit_char(&mut self, v: char) -> EncodeResult { - escape_char(self.writer, v) - } - fn emit_str(&mut self, v: &str) -> EncodeResult { - escape_str(self.writer, v) - } - - fn emit_enum(&mut self, _name: &str, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - f(self) - } - - fn emit_enum_variant(&mut self, - name: &str, - _id: uint, - cnt: uint, - f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - // enums are encoded as strings or objects - // Bunny => "Bunny" - // Kangaroo(34,"William") => {"variant": "Kangaroo", "fields": [34,"William"]} - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - if cnt == 0 { - escape_str(self.writer, name) - } else { - try!(write!(self.writer, "{{\"variant\":")); - try!(escape_str(self.writer, name)); - try!(write!(self.writer, ",\"fields\":[")); - try!(f(self)); - try!(write!(self.writer, "]}}")); - Ok(()) - } - } - - fn emit_enum_variant_arg(&mut self, idx: uint, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - if idx != 0 { - try!(write!(self.writer, ",")); - } - f(self) - } - - fn emit_enum_struct_variant(&mut self, - name: &str, - id: uint, - cnt: uint, - f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - self.emit_enum_variant(name, id, cnt, f) - } - - fn emit_enum_struct_variant_field(&mut self, - _: &str, - idx: uint, - f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - self.emit_enum_variant_arg(idx, f) - } - - fn emit_struct(&mut self, _: &str, _: uint, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - try!(write!(self.writer, "{{")); - try!(f(self)); - try!(write!(self.writer, "}}")); - Ok(()) - } - - fn emit_struct_field(&mut self, name: &str, idx: uint, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - if idx != 0 { try!(write!(self.writer, ",")); } - try!(escape_str(self.writer, name)); - try!(write!(self.writer, ":")); - f(self) - } - - fn emit_tuple(&mut self, len: uint, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - self.emit_seq(len, f) - } - fn emit_tuple_arg(&mut self, idx: uint, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - self.emit_seq_elt(idx, f) - } - - fn emit_tuple_struct(&mut self, _name: &str, len: uint, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - self.emit_seq(len, f) - } - fn emit_tuple_struct_arg(&mut self, idx: uint, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - self.emit_seq_elt(idx, f) - } - - fn emit_option(&mut self, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - f(self) - } - fn emit_option_none(&mut self) -> EncodeResult { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - self.emit_nil() - } - fn emit_option_some(&mut self, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - f(self) - } - - fn emit_seq(&mut self, _len: uint, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - try!(write!(self.writer, "[")); - try!(f(self)); - try!(write!(self.writer, "]")); - Ok(()) - } - - fn emit_seq_elt(&mut self, idx: uint, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - if idx != 0 { - try!(write!(self.writer, ",")); - } - f(self) - } - - fn emit_map(&mut self, _len: uint, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - try!(write!(self.writer, "{{")); - try!(f(self)); - try!(write!(self.writer, "}}")); - Ok(()) - } - - fn emit_map_elt_key(&mut self, idx: uint, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - if idx != 0 { try!(write!(self.writer, ",")) } - self.is_emitting_map_key = true; - try!(f(self)); - self.is_emitting_map_key = false; - Ok(()) - } - - fn emit_map_elt_val(&mut self, _idx: uint, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - try!(write!(self.writer, ":")); - f(self) - } -} - /// Another encoder for JSON, but prints out human-readable JSON instead of /// compact data pub struct PrettyEncoder<'a> { From 3ff7667da45e6ba1a5718505d65ac912d00048e0 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 14 Jan 2015 17:35:11 +0100 Subject: [PATCH 6/6] merge json::PrettyEncoder and json::Encoder --- src/libserialize/json.rs | 238 ++++++++++++++++++++++++--------------- 1 file changed, 150 insertions(+), 88 deletions(-) diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 7de63823a5aba..11339beda5832 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -319,7 +319,7 @@ pub fn decode(s: &str) -> DecodeResult { pub fn encode(object: &T) -> string::String { let mut s = String::new(); { - let mut encoder = Encoder::new(&mut s); + let mut encoder = Encoder::new_compact(&mut s); let _ = object.encode(&mut encoder); } s @@ -455,37 +455,61 @@ macro_rules! emit_enquoted_if_mapkey { } } -/// Another encoder for JSON, but prints out human-readable JSON instead of -/// compact data -pub struct PrettyEncoder<'a> { +enum EncodingFormat { + Compact, + Pretty { + curr_indent: uint, + indent: uint + } +} + +/// A structure for implementing serialization to JSON. +pub struct Encoder<'a> { writer: &'a mut (fmt::Writer+'a), - curr_indent: uint, - indent: uint, + format : EncodingFormat, is_emitting_map_key: bool, } -impl<'a> PrettyEncoder<'a> { - /// Creates a new encoder whose output will be written to the specified writer - pub fn new(writer: &'a mut fmt::Writer) -> PrettyEncoder<'a> { - PrettyEncoder { +impl<'a> Encoder<'a> { + /// Creates a new encoder whose output will be written in human-readable + /// JSON to the specified writer + pub fn new_pretty(writer: &'a mut fmt::Writer) -> Encoder<'a> { + Encoder { writer: writer, - curr_indent: 0, - indent: 2, + format: EncodingFormat::Pretty { + curr_indent: 0, + indent: 2, + }, + is_emitting_map_key: false, + } + } + + /// Creates a new encoder whose output will be written in compact + /// JSON to the specified writer + pub fn new_compact(writer: &'a mut fmt::Writer) -> Encoder<'a> { + Encoder { + writer: writer, + format: EncodingFormat::Compact, is_emitting_map_key: false, } } /// Set the number of spaces to indent for each level. /// This is safe to set during encoding. - pub fn set_indent(&mut self, indent: uint) { - // self.indent very well could be 0 so we need to use checked division. - let level = self.curr_indent.checked_div(self.indent).unwrap_or(0); - self.indent = indent; - self.curr_indent = level * self.indent; + pub fn set_indent(&mut self, new_indent: uint) -> Result<(), ()> { + if let EncodingFormat::Pretty{ref mut curr_indent, ref mut indent} = self.format { + // self.indent very well could be 0 so we need to use checked division. + let level = curr_indent.checked_div(*indent).unwrap_or(0); + *indent = new_indent; + *curr_indent = level * *indent; + Ok(()) + } else { + Err(()) + } } } -impl<'a> ::Encoder for PrettyEncoder<'a> { +impl<'a> ::Encoder for Encoder<'a> { type Error = EncoderError; fn emit_nil(&mut self) -> EncodeResult { @@ -531,7 +555,7 @@ impl<'a> ::Encoder for PrettyEncoder<'a> { } fn emit_enum(&mut self, _name: &str, f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } f(self) @@ -543,41 +567,57 @@ impl<'a> ::Encoder for PrettyEncoder<'a> { cnt: uint, f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { + // enums are encoded as strings or objects + // Bunny => "Bunny" + // Kangaroo(34,"William") => {"variant": "Kangaroo", "fields": [34,"William"]} if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } if cnt == 0 { escape_str(self.writer, name) } else { - try!(write!(self.writer, "{{\n")); - self.curr_indent += self.indent; - try!(spaces(self.writer, self.curr_indent)); - try!(write!(self.writer, "\"variant\": ")); - try!(escape_str(self.writer, name)); - try!(write!(self.writer, ",\n")); - try!(spaces(self.writer, self.curr_indent)); - try!(write!(self.writer, "\"fields\": [\n")); - self.curr_indent += self.indent; + if let EncodingFormat::Pretty{ref mut curr_indent, indent} = self.format { + try!(write!(self.writer, "{{\n")); + *curr_indent += indent; + try!(spaces(self.writer, *curr_indent)); + try!(write!(self.writer, "\"variant\": ")); + try!(escape_str(self.writer, name)); + try!(write!(self.writer, ",\n")); + try!(spaces(self.writer, *curr_indent)); + try!(write!(self.writer, "\"fields\": [\n")); + *curr_indent += indent; + } else { + try!(write!(self.writer, "{{\"variant\":")); + try!(escape_str(self.writer, name)); + try!(write!(self.writer, ",\"fields\":[")); + } try!(f(self)); - self.curr_indent -= self.indent; - try!(write!(self.writer, "\n")); - try!(spaces(self.writer, self.curr_indent)); - self.curr_indent -= self.indent; - try!(write!(self.writer, "]\n")); - try!(spaces(self.writer, self.curr_indent)); - try!(write!(self.writer, "}}")); + if let EncodingFormat::Pretty{ref mut curr_indent, indent} = self.format { + *curr_indent -= indent; + try!(write!(self.writer, "\n")); + try!(spaces(self.writer, *curr_indent)); + *curr_indent -= indent; + try!(write!(self.writer, "]\n")); + try!(spaces(self.writer, *curr_indent)); + try!(write!(self.writer, "}}")); + } else { + try!(write!(self.writer, "]}}")); + } Ok(()) } } fn emit_enum_variant_arg(&mut self, idx: uint, f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } if idx != 0 { - try!(write!(self.writer, ",\n")); + try!(write!(self.writer, ",")); + } + if let EncodingFormat::Pretty{curr_indent, ..} = self.format { + try!(write!(self.writer, "\n")); + try!(spaces(self.writer, curr_indent)); } - try!(spaces(self.writer, self.curr_indent)); f(self) } @@ -586,7 +626,7 @@ impl<'a> ::Encoder for PrettyEncoder<'a> { id: uint, cnt: uint, f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } self.emit_enum_variant(name, id, cnt, f) @@ -596,7 +636,7 @@ impl<'a> ::Encoder for PrettyEncoder<'a> { _: &str, idx: uint, f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } self.emit_enum_variant_arg(idx, f) @@ -604,66 +644,75 @@ impl<'a> ::Encoder for PrettyEncoder<'a> { fn emit_struct(&mut self, _: &str, len: uint, f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } if len == 0 { try!(write!(self.writer, "{{}}")); } else { try!(write!(self.writer, "{{")); - self.curr_indent += self.indent; + if let EncodingFormat::Pretty{ref mut curr_indent, indent} = self.format { + *curr_indent += indent; + } try!(f(self)); - self.curr_indent -= self.indent; - try!(write!(self.writer, "\n")); - try!(spaces(self.writer, self.curr_indent)); + if let EncodingFormat::Pretty{ref mut curr_indent, indent} = self.format { + *curr_indent -= indent; + try!(write!(self.writer, "\n")); + try!(spaces(self.writer, *curr_indent)); + } try!(write!(self.writer, "}}")); } Ok(()) } fn emit_struct_field(&mut self, name: &str, idx: uint, f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - if idx == 0 { + if idx != 0 { + try!(write!(self.writer, ",")); + } + if let EncodingFormat::Pretty{curr_indent, ..} = self.format { try!(write!(self.writer, "\n")); - } else { - try!(write!(self.writer, ",\n")); + try!(spaces(self.writer, curr_indent)); } - try!(spaces(self.writer, self.curr_indent)); try!(escape_str(self.writer, name)); - try!(write!(self.writer, ": ")); + if let EncodingFormat::Pretty{..} = self.format { + try!(write!(self.writer, ": ")); + } else { + try!(write!(self.writer, ":")); + } f(self) } fn emit_tuple(&mut self, len: uint, f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } self.emit_seq(len, f) } fn emit_tuple_arg(&mut self, idx: uint, f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } self.emit_seq_elt(idx, f) } fn emit_tuple_struct(&mut self, _: &str, len: uint, f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } self.emit_seq(len, f) } fn emit_tuple_struct_arg(&mut self, idx: uint, f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } self.emit_seq_elt(idx, f) } fn emit_option(&mut self, f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } f(self) @@ -673,71 +722,81 @@ impl<'a> ::Encoder for PrettyEncoder<'a> { self.emit_nil() } fn emit_option_some(&mut self, f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } f(self) } fn emit_seq(&mut self, len: uint, f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } if len == 0 { try!(write!(self.writer, "[]")); } else { try!(write!(self.writer, "[")); - self.curr_indent += self.indent; + if let EncodingFormat::Pretty{ref mut curr_indent, indent} = self.format { + *curr_indent += indent; + } try!(f(self)); - self.curr_indent -= self.indent; - try!(write!(self.writer, "\n")); - try!(spaces(self.writer, self.curr_indent)); + if let EncodingFormat::Pretty{ref mut curr_indent, indent} = self.format { + *curr_indent -= indent; + try!(write!(self.writer, "\n")); + try!(spaces(self.writer, *curr_indent)); + } try!(write!(self.writer, "]")); } Ok(()) } fn emit_seq_elt(&mut self, idx: uint, f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - if idx == 0 { + if idx != 0 { + try!(write!(self.writer, ",")); + } + if let EncodingFormat::Pretty{ref mut curr_indent, ..} = self.format { try!(write!(self.writer, "\n")); - } else { - try!(write!(self.writer, ",\n")); + try!(spaces(self.writer, *curr_indent)); } - try!(spaces(self.writer, self.curr_indent)); f(self) } fn emit_map(&mut self, len: uint, f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } if len == 0 { try!(write!(self.writer, "{{}}")); } else { try!(write!(self.writer, "{{")); - self.curr_indent += self.indent; + if let EncodingFormat::Pretty{ref mut curr_indent, indent} = self.format { + *curr_indent += indent; + } try!(f(self)); - self.curr_indent -= self.indent; - try!(write!(self.writer, "\n")); - try!(spaces(self.writer, self.curr_indent)); + if let EncodingFormat::Pretty{ref mut curr_indent, indent} = self.format { + *curr_indent -= indent; + try!(write!(self.writer, "\n")); + try!(spaces(self.writer, *curr_indent)); + } try!(write!(self.writer, "}}")); } Ok(()) } fn emit_map_elt_key(&mut self, idx: uint, f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - if idx == 0 { + if idx != 0 { + try!(write!(self.writer, ",")); + } + if let EncodingFormat::Pretty{curr_indent, ..} = self.format { try!(write!(self.writer, "\n")); - } else { - try!(write!(self.writer, ",\n")); + try!(spaces(self.writer, curr_indent)); } - try!(spaces(self.writer, self.curr_indent)); self.is_emitting_map_key = true; try!(f(self)); self.is_emitting_map_key = false; @@ -745,10 +804,14 @@ impl<'a> ::Encoder for PrettyEncoder<'a> { } fn emit_map_elt_val(&mut self, _idx: uint, f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - try!(write!(self.writer, ": ")); + if let EncodingFormat::Pretty{..} = self.format { + try!(write!(self.writer, ": ")); + } else { + try!(write!(self.writer, ":")); + } f(self) } } @@ -2290,7 +2353,7 @@ impl fmt::String for Json { /// Encodes a json value into a string fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut shim = FormatShim { inner: f }; - let mut encoder = Encoder::new(&mut shim); + let mut encoder = Encoder::new_compact(&mut shim); match self.encode(&mut encoder) { Ok(_) => Ok(()), Err(_) => Err(fmt::Error) @@ -2302,7 +2365,7 @@ impl<'a> fmt::String for PrettyJson<'a> { /// Encodes a json value into a string fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut shim = FormatShim { inner: f }; - let mut encoder = PrettyEncoder::new(&mut shim); + let mut encoder = Encoder::new_pretty(&mut shim); match self.inner.encode(&mut encoder) { Ok(_) => Ok(()), Err(_) => Err(fmt::Error) @@ -2314,7 +2377,7 @@ impl<'a, T: Encodable> fmt::String for AsJson<'a, T> { /// Encodes a json value into a string fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut shim = FormatShim { inner: f }; - let mut encoder = Encoder::new(&mut shim); + let mut encoder = Encoder::new_compact(&mut shim); match self.inner.encode(&mut encoder) { Ok(_) => Ok(()), Err(_) => Err(fmt::Error) @@ -2334,10 +2397,9 @@ impl<'a, T: Encodable> fmt::String for AsPrettyJson<'a, T> { /// Encodes a json value into a string fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut shim = FormatShim { inner: f }; - let mut encoder = PrettyEncoder::new(&mut shim); - match self.indent { - Some(n) => encoder.set_indent(n), - None => {} + let mut encoder = Encoder::new_pretty(&mut shim); + if let Some(n) = self.indent { + encoder.set_indent(n).unwrap(); } match self.inner.encode(&mut encoder) { Ok(_) => Ok(()), @@ -3685,7 +3747,7 @@ mod tests { let mut hm: HashMap = HashMap::new(); hm.insert(ArbitraryType(1), true); let mut mem_buf = Vec::new(); - let mut encoder = Encoder::new(&mut mem_buf as &mut fmt::Writer); + let mut encoder = Encoder::new_compact(&mut mem_buf as &mut fmt::Writer); let result = hm.encode(&mut encoder); match result.unwrap_err() { EncoderError::BadHashmapKey => (),