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 62acef2ca1cc7..11339beda5832 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 { @@ -313,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 @@ -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 { @@ -428,268 +443,105 @@ 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), -} - -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 } - } -} - -impl<'a> ::Encoder for Encoder<'a> { - type Error = fmt::Error; - - fn emit_nil(&mut self) -> EncodeResult { write!(self.writer, "null") } - - 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_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_bool(&mut self, v: bool) -> EncodeResult { - if v { - write!(self.writer, "true") +macro_rules! emit_enquoted_if_mapkey { + ($enc:ident,$e:expr) => { + if $enc.is_emitting_map_key { + try!(write!($enc.writer, "\"{}\"", $e)); + Ok(()) } else { - write!(self.writer, "false") + try!(write!($enc.writer, "{}", $e)); + Ok(()) } } +} - fn emit_f64(&mut self, v: f64) -> EncodeResult { - write!(self.writer, "{}", 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, - { - f(self) +enum EncodingFormat { + Compact, + Pretty { + curr_indent: uint, + indent: uint } +} - 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 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)); - write!(self.writer, "]}}") - } - } +/// A structure for implementing serialization to JSON. +pub struct Encoder<'a> { + writer: &'a mut (fmt::Writer+'a), + format : EncodingFormat, + is_emitting_map_key: bool, +} - fn emit_enum_variant_arg(&mut self, idx: uint, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if idx != 0 { - try!(write!(self.writer, ",")); +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, + format: EncodingFormat::Pretty { + curr_indent: 0, + indent: 2, + }, + is_emitting_map_key: false, } - 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, - { - 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, - { - self.emit_enum_variant_arg(idx, f) - } - - fn emit_struct(&mut self, _: &str, _: uint, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - try!(write!(self.writer, "{{")); - try!(f(self)); - write!(self.writer, "}}") - } - - fn emit_struct_field(&mut self, name: &str, idx: uint, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - 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, - { - self.emit_seq(len, f) - } - fn emit_tuple_arg(&mut self, idx: uint, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - 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, - { - self.emit_seq(len, f) - } - fn emit_tuple_struct_arg(&mut self, idx: uint, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - self.emit_seq_elt(idx, f) } - fn emit_option(&mut self, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - f(self) - } - fn emit_option_none(&mut self) -> EncodeResult { self.emit_nil() } - fn emit_option_some(&mut self, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - f(self) - } - - fn emit_seq(&mut self, _len: uint, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - try!(write!(self.writer, "[")); - try!(f(self)); - write!(self.writer, "]") - } - - fn emit_seq_elt(&mut self, idx: uint, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if idx != 0 { - try!(write!(self.writer, ",")); + /// 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, } - f(self) - } - - fn emit_map(&mut self, _len: uint, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - try!(write!(self.writer, "{{")); - try!(f(self)); - write!(self.writer, "}}") - } - - fn emit_map_elt_key(&mut self, idx: uint, mut f: F) -> EncodeResult where - F: FnMut(&mut Encoder<'a>) -> EncodeResult, - { - 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, "\"")); } - try!(f(self)); - if needs_wrapping { try!(write!(self.writer, "\"")); } - Ok(()) - } - - fn emit_map_elt_val(&mut self, _idx: uint, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - try!(write!(self.writer, ":")); - f(self) - } -} - -/// Another encoder for JSON, but prints out human-readable JSON instead of -/// compact data -pub struct PrettyEncoder<'a> { - writer: &'a mut (fmt::Writer+'a), - curr_indent: uint, - indent: uint, -} - -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, } } /// 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> { - type Error = fmt::Error; +impl<'a> ::Encoder for Encoder<'a> { + 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) @@ -703,8 +555,9 @@ 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) } @@ -714,38 +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)); - 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) } @@ -754,8 +626,9 @@ 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) } @@ -763,149 +636,182 @@ 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) } 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 { - write!(self.writer, "{{}}") + 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)); - 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)); + } + 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 idx == 0 { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } + 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) } - 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, + 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 { - write!(self.writer, "[]") + 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)); - 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)); + } + 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 idx == 0 { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } + 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 { - write!(self.writer, "{{}}") + 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)); - 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)); + } + 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, + fn emit_map_elt_key(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { - if idx == 0 { + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } + 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, 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, "\"")); } + try!(spaces(self.writer, curr_indent)); + } + 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, + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { - try!(write!(self.writer, ": ")); + if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } + if let EncodingFormat::Pretty{..} = self.format { + try!(write!(self.writer, ": ")); + } else { + try!(write!(self.writer, ":")); + } f(self) } } @@ -2436,7 +2342,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) + } } } @@ -2444,8 +2353,11 @@ 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); - self.encode(&mut encoder) + let mut encoder = Encoder::new_compact(&mut shim); + match self.encode(&mut encoder) { + Ok(_) => Ok(()), + Err(_) => Err(fmt::Error) + } } } @@ -2453,8 +2365,11 @@ 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); - self.inner.encode(&mut encoder) + let mut encoder = Encoder::new_pretty(&mut shim); + match self.inner.encode(&mut encoder) { + Ok(_) => Ok(()), + Err(_) => Err(fmt::Error) + } } } @@ -2462,8 +2377,11 @@ 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); - self.inner.encode(&mut encoder) + let mut encoder = Encoder::new_compact(&mut shim); + match self.inner.encode(&mut encoder) { + Ok(_) => Ok(()), + Err(_) => Err(fmt::Error) + } } } @@ -2479,12 +2397,14 @@ 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(()), + Err(_) => Err(fmt::Error) } - self.inner.encode(&mut encoder) } } @@ -2507,7 +2427,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; @@ -3816,6 +3736,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_compact(&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( || { 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>; }