From f015a3b871a7eade289842a868f6de580740d89c Mon Sep 17 00:00:00 2001 From: Oliver 'ker' Schneider Date: Sat, 10 Jan 2015 10:14:19 +0100 Subject: [PATCH 1/4] 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 41499b5ae0efe..bfc0143c6891b 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[..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[..n]) - } else { - Ok(()) + try!(wr.write_str(&BUF[..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 d727f9910729625039defffd4058b907ca984bb9 Mon Sep 17 00:00:00 2001 From: Oliver 'ker' Schneider Date: Sat, 10 Jan 2015 10:14:32 +0100 Subject: [PATCH 2/4] 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 f28600e5e6973..25279796c03c0 100644 --- a/src/librbml/lib.rs +++ b/src/librbml/lib.rs @@ -1059,8 +1059,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 bfc0143c6891b..8412da3b4c557 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 0478a8c1d73ab936bcfb762ce8f31ab9f642f462 Mon Sep 17 00:00:00 2001 From: Oliver 'ker' Schneider Date: Sat, 10 Jan 2015 10:14:38 +0100 Subject: [PATCH 3/4] 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 8412da3b4c557..0364d9544b1aa 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 a320149dcce2eb27d3014113cbf87aacc04d24eb Mon Sep 17 00:00:00 2001 From: Oliver 'ker' Schneider Date: Sat, 10 Jan 2015 10:13:11 +0100 Subject: [PATCH 4/4] 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 0364d9544b1aa..77e1ebc5ef342 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) + } } }