Reject serializing maps to JSON with non-string keys

Closes #122. This is a breaking change since it modifies the
return type of serde_json::to_vec{,pretty}, so it'll require a major
version bump of serde_json.
This commit is contained in:
Erick Tryzelaar 2015-08-13 22:29:13 -07:00
parent fc58ea7487
commit fe20852b2c
4 changed files with 205 additions and 125 deletions

View File

@ -2,6 +2,7 @@ use std::error;
use std::fmt; use std::fmt;
use std::io; use std::io;
use std::result; use std::result;
use std::string::FromUtf8Error;
use serde::de; use serde::de;
@ -44,7 +45,6 @@ impl fmt::Debug for ErrorCode {
use std::fmt::Debug; use std::fmt::Debug;
match *self { match *self {
//ErrorCode::ConversionError(ref token) => write!(f, "failed to convert {}", token),
ErrorCode::EOFWhileParsingList => "EOF While parsing list".fmt(f), ErrorCode::EOFWhileParsingList => "EOF While parsing list".fmt(f),
ErrorCode::EOFWhileParsingObject => "EOF While parsing object".fmt(f), ErrorCode::EOFWhileParsingObject => "EOF While parsing object".fmt(f),
ErrorCode::EOFWhileParsingString => "EOF While parsing string".fmt(f), ErrorCode::EOFWhileParsingString => "EOF While parsing string".fmt(f),
@ -61,7 +61,6 @@ impl fmt::Debug for ErrorCode {
ErrorCode::ExpectedObjectCommaOrEnd => "expected `,` or `}`".fmt(f), ErrorCode::ExpectedObjectCommaOrEnd => "expected `,` or `}`".fmt(f),
ErrorCode::ExpectedSomeIdent => "expected ident".fmt(f), ErrorCode::ExpectedSomeIdent => "expected ident".fmt(f),
ErrorCode::ExpectedSomeValue => "expected value".fmt(f), ErrorCode::ExpectedSomeValue => "expected value".fmt(f),
//ErrorCode::ExpectedTokens(ref token, tokens) => write!(f, "expected {}, found {}", tokens, token),
ErrorCode::InvalidEscape => "invalid escape".fmt(f), ErrorCode::InvalidEscape => "invalid escape".fmt(f),
ErrorCode::InvalidNumber => "invalid number".fmt(f), ErrorCode::InvalidNumber => "invalid number".fmt(f),
ErrorCode::InvalidUnicodeCodePoint => "invalid unicode code point".fmt(f), ErrorCode::InvalidUnicodeCodePoint => "invalid unicode code point".fmt(f),
@ -73,7 +72,6 @@ impl fmt::Debug for ErrorCode {
ErrorCode::NotUtf8 => "contents not utf-8".fmt(f), ErrorCode::NotUtf8 => "contents not utf-8".fmt(f),
ErrorCode::TrailingCharacters => "trailing characters".fmt(f), ErrorCode::TrailingCharacters => "trailing characters".fmt(f),
ErrorCode::UnexpectedEndOfHexEscape => "unexpected end of hex escape".fmt(f), ErrorCode::UnexpectedEndOfHexEscape => "unexpected end of hex escape".fmt(f),
//ErrorCode::UnexpectedName(ref name) => write!(f, "unexpected name {}", name),
ErrorCode::UnknownVariant => "unknown variant".fmt(f), ErrorCode::UnknownVariant => "unknown variant".fmt(f),
ErrorCode::UnrecognizedHex => "invalid \\u escape (unrecognized hex)".fmt(f), ErrorCode::UnrecognizedHex => "invalid \\u escape (unrecognized hex)".fmt(f),
} }
@ -85,13 +83,8 @@ pub enum Error {
/// msg, line, col /// msg, line, col
SyntaxError(ErrorCode, usize, usize), SyntaxError(ErrorCode, usize, usize),
IoError(io::Error), IoError(io::Error),
/*
ExpectedError(String, String),
*/
MissingFieldError(&'static str), MissingFieldError(&'static str),
/* FromUtf8Error(FromUtf8Error),
UnknownVariantError(String),
*/
} }
impl error::Error for Error { impl error::Error for Error {
@ -99,19 +92,15 @@ impl error::Error for Error {
match *self { match *self {
Error::SyntaxError(..) => "syntax error", Error::SyntaxError(..) => "syntax error",
Error::IoError(ref error) => error::Error::description(error), Error::IoError(ref error) => error::Error::description(error),
/*
Error::ExpectedError(ref expected, _) => &expected,
*/
Error::MissingFieldError(_) => "missing field", Error::MissingFieldError(_) => "missing field",
/* Error::FromUtf8Error(ref error) => error.description(),
Error::UnknownVariantError(_) => "unknown variant",
*/
} }
} }
fn cause(&self) -> Option<&error::Error> { fn cause(&self) -> Option<&error::Error> {
match *self { match *self {
Error::IoError(ref error) => Some(error), Error::IoError(ref error) => Some(error),
Error::FromUtf8Error(ref error) => Some(error),
_ => None, _ => None,
} }
} }
@ -125,19 +114,10 @@ impl fmt::Display for Error {
write!(fmt, "{:?} at line {} column {}", code, line, col) write!(fmt, "{:?} at line {} column {}", code, line, col)
} }
Error::IoError(ref error) => fmt::Display::fmt(error, fmt), Error::IoError(ref error) => fmt::Display::fmt(error, fmt),
/* Error::FromUtf8Error(ref error) => fmt::Display::fmt(error, fmt),
Error::ExpectedError(ref expected, ref found) => {
Some(format!("expected {}, found {}", expected, found))
}
*/
Error::MissingFieldError(ref field) => { Error::MissingFieldError(ref field) => {
write!(fmt, "missing field {}", field) write!(fmt, "missing field {}", field)
} }
/*
Error::UnknownVariantError(ref variant) => {
Some(format!("unknown variant {}", variant))
}
*/
} }
} }
} }
@ -148,6 +128,12 @@ impl From<io::Error> for Error {
} }
} }
impl From<FromUtf8Error> for Error {
fn from(error: FromUtf8Error) -> Error {
Error::FromUtf8Error(error)
}
}
impl From<de::value::Error> for Error { impl From<de::value::Error> for Error {
fn from(error: de::value::Error) -> Error { fn from(error: de::value::Error) -> Error {
match error { match error {

View File

@ -1,8 +1,8 @@
use std::io; use std::io;
use std::num::FpCategory; use std::num::FpCategory;
use std::string::FromUtf8Error;
use serde::ser; use serde::ser;
use super::error::{Error, ErrorCode, Result};
/// A structure for implementing serialization to JSON. /// A structure for implementing serialization to JSON.
pub struct Serializer<W, F=CompactFormatter> { pub struct Serializer<W, F=CompactFormatter> {
@ -60,109 +60,109 @@ impl<W, F> ser::Serializer for Serializer<W, F>
where W: io::Write, where W: io::Write,
F: Formatter, F: Formatter,
{ {
type Error = io::Error; type Error = Error;
#[inline] #[inline]
fn visit_bool(&mut self, value: bool) -> io::Result<()> { fn visit_bool(&mut self, value: bool) -> Result<()> {
if value { if value {
self.writer.write_all(b"true") self.writer.write_all(b"true").map_err(From::from)
} else { } else {
self.writer.write_all(b"false") self.writer.write_all(b"false").map_err(From::from)
} }
} }
#[inline] #[inline]
fn visit_isize(&mut self, value: isize) -> io::Result<()> { fn visit_isize(&mut self, value: isize) -> Result<()> {
write!(&mut self.writer, "{}", value) write!(&mut self.writer, "{}", value).map_err(From::from)
} }
#[inline] #[inline]
fn visit_i8(&mut self, value: i8) -> io::Result<()> { fn visit_i8(&mut self, value: i8) -> Result<()> {
write!(&mut self.writer, "{}", value) write!(&mut self.writer, "{}", value).map_err(From::from)
} }
#[inline] #[inline]
fn visit_i16(&mut self, value: i16) -> io::Result<()> { fn visit_i16(&mut self, value: i16) -> Result<()> {
write!(&mut self.writer, "{}", value) write!(&mut self.writer, "{}", value).map_err(From::from)
} }
#[inline] #[inline]
fn visit_i32(&mut self, value: i32) -> io::Result<()> { fn visit_i32(&mut self, value: i32) -> Result<()> {
write!(&mut self.writer, "{}", value) write!(&mut self.writer, "{}", value).map_err(From::from)
} }
#[inline] #[inline]
fn visit_i64(&mut self, value: i64) -> io::Result<()> { fn visit_i64(&mut self, value: i64) -> Result<()> {
write!(&mut self.writer, "{}", value) write!(&mut self.writer, "{}", value).map_err(From::from)
} }
#[inline] #[inline]
fn visit_usize(&mut self, value: usize) -> io::Result<()> { fn visit_usize(&mut self, value: usize) -> Result<()> {
write!(&mut self.writer, "{}", value) write!(&mut self.writer, "{}", value).map_err(From::from)
} }
#[inline] #[inline]
fn visit_u8(&mut self, value: u8) -> io::Result<()> { fn visit_u8(&mut self, value: u8) -> Result<()> {
write!(&mut self.writer, "{}", value) write!(&mut self.writer, "{}", value).map_err(From::from)
} }
#[inline] #[inline]
fn visit_u16(&mut self, value: u16) -> io::Result<()> { fn visit_u16(&mut self, value: u16) -> Result<()> {
write!(&mut self.writer, "{}", value) write!(&mut self.writer, "{}", value).map_err(From::from)
} }
#[inline] #[inline]
fn visit_u32(&mut self, value: u32) -> io::Result<()> { fn visit_u32(&mut self, value: u32) -> Result<()> {
write!(&mut self.writer, "{}", value) write!(&mut self.writer, "{}", value).map_err(From::from)
} }
#[inline] #[inline]
fn visit_u64(&mut self, value: u64) -> io::Result<()> { fn visit_u64(&mut self, value: u64) -> Result<()> {
write!(&mut self.writer, "{}", value) write!(&mut self.writer, "{}", value).map_err(From::from)
} }
#[inline] #[inline]
fn visit_f32(&mut self, value: f32) -> io::Result<()> { fn visit_f32(&mut self, value: f32) -> Result<()> {
fmt_f32_or_null(&mut self.writer, value) fmt_f32_or_null(&mut self.writer, value).map_err(From::from)
} }
#[inline] #[inline]
fn visit_f64(&mut self, value: f64) -> io::Result<()> { fn visit_f64(&mut self, value: f64) -> Result<()> {
fmt_f64_or_null(&mut self.writer, value) fmt_f64_or_null(&mut self.writer, value).map_err(From::from)
} }
#[inline] #[inline]
fn visit_char(&mut self, value: char) -> io::Result<()> { fn visit_char(&mut self, value: char) -> Result<()> {
escape_char(&mut self.writer, value) escape_char(&mut self.writer, value).map_err(From::from)
} }
#[inline] #[inline]
fn visit_str(&mut self, value: &str) -> io::Result<()> { fn visit_str(&mut self, value: &str) -> Result<()> {
escape_str(&mut self.writer, value) escape_str(&mut self.writer, value).map_err(From::from)
} }
#[inline] #[inline]
fn visit_none(&mut self) -> io::Result<()> { fn visit_none(&mut self) -> Result<()> {
self.visit_unit() self.visit_unit()
} }
#[inline] #[inline]
fn visit_some<V>(&mut self, value: V) -> io::Result<()> fn visit_some<V>(&mut self, value: V) -> Result<()>
where V: ser::Serialize where V: ser::Serialize
{ {
value.serialize(self) value.serialize(self)
} }
#[inline] #[inline]
fn visit_unit(&mut self) -> io::Result<()> { fn visit_unit(&mut self) -> Result<()> {
self.writer.write_all(b"null") self.writer.write_all(b"null").map_err(From::from)
} }
/// Override `visit_newtype_struct` to serialize newtypes without an object wrapper. /// Override `visit_newtype_struct` to serialize newtypes without an object wrapper.
#[inline] #[inline]
fn visit_newtype_struct<T>(&mut self, fn visit_newtype_struct<T>(&mut self,
_name: &'static str, _name: &'static str,
value: T) -> Result<(), Self::Error> value: T) -> Result<()>
where T: ser::Serialize, where T: ser::Serialize,
{ {
value.serialize(self) value.serialize(self)
@ -172,7 +172,7 @@ impl<W, F> ser::Serializer for Serializer<W, F>
fn visit_unit_variant(&mut self, fn visit_unit_variant(&mut self,
_name: &str, _name: &str,
_variant_index: usize, _variant_index: usize,
variant: &str) -> io::Result<()> { variant: &str) -> Result<()> {
try!(self.formatter.open(&mut self.writer, b'{')); try!(self.formatter.open(&mut self.writer, b'{'));
try!(self.formatter.comma(&mut self.writer, true)); try!(self.formatter.comma(&mut self.writer, true));
try!(self.visit_str(variant)); try!(self.visit_str(variant));
@ -186,7 +186,7 @@ impl<W, F> ser::Serializer for Serializer<W, F>
_name: &str, _name: &str,
_variant_index: usize, _variant_index: usize,
variant: &str, variant: &str,
value: T) -> io::Result<()> value: T) -> Result<()>
where T: ser::Serialize, where T: ser::Serialize,
{ {
try!(self.formatter.open(&mut self.writer, b'{')); try!(self.formatter.open(&mut self.writer, b'{'));
@ -198,12 +198,12 @@ impl<W, F> ser::Serializer for Serializer<W, F>
} }
#[inline] #[inline]
fn visit_seq<V>(&mut self, mut visitor: V) -> io::Result<()> fn visit_seq<V>(&mut self, mut visitor: V) -> Result<()>
where V: ser::SeqVisitor, where V: ser::SeqVisitor,
{ {
match visitor.len() { match visitor.len() {
Some(len) if len == 0 => { Some(len) if len == 0 => {
self.writer.write_all(b"[]") self.writer.write_all(b"[]").map_err(From::from)
} }
_ => { _ => {
try!(self.formatter.open(&mut self.writer, b'[')); try!(self.formatter.open(&mut self.writer, b'['));
@ -212,7 +212,7 @@ impl<W, F> ser::Serializer for Serializer<W, F>
while let Some(()) = try!(visitor.visit(self)) { } while let Some(()) = try!(visitor.visit(self)) { }
self.formatter.close(&mut self.writer, b']') self.formatter.close(&mut self.writer, b']').map_err(From::from)
} }
} }
@ -223,7 +223,7 @@ impl<W, F> ser::Serializer for Serializer<W, F>
_name: &str, _name: &str,
_variant_index: usize, _variant_index: usize,
variant: &str, variant: &str,
visitor: V) -> io::Result<()> visitor: V) -> Result<()>
where V: ser::SeqVisitor, where V: ser::SeqVisitor,
{ {
try!(self.formatter.open(&mut self.writer, b'{')); try!(self.formatter.open(&mut self.writer, b'{'));
@ -235,7 +235,7 @@ impl<W, F> ser::Serializer for Serializer<W, F>
} }
#[inline] #[inline]
fn visit_seq_elt<T>(&mut self, value: T) -> io::Result<()> fn visit_seq_elt<T>(&mut self, value: T) -> Result<()>
where T: ser::Serialize, where T: ser::Serialize,
{ {
try!(self.formatter.comma(&mut self.writer, self.first)); try!(self.formatter.comma(&mut self.writer, self.first));
@ -247,12 +247,12 @@ impl<W, F> ser::Serializer for Serializer<W, F>
} }
#[inline] #[inline]
fn visit_map<V>(&mut self, mut visitor: V) -> io::Result<()> fn visit_map<V>(&mut self, mut visitor: V) -> Result<()>
where V: ser::MapVisitor, where V: ser::MapVisitor,
{ {
match visitor.len() { match visitor.len() {
Some(len) if len == 0 => { Some(len) if len == 0 => {
self.writer.write_all(b"{}") self.writer.write_all(b"{}").map_err(From::from)
} }
_ => { _ => {
try!(self.formatter.open(&mut self.writer, b'{')); try!(self.formatter.open(&mut self.writer, b'{'));
@ -271,7 +271,7 @@ impl<W, F> ser::Serializer for Serializer<W, F>
_name: &str, _name: &str,
_variant_index: usize, _variant_index: usize,
variant: &str, variant: &str,
visitor: V) -> io::Result<()> visitor: V) -> Result<()>
where V: ser::MapVisitor, where V: ser::MapVisitor,
{ {
try!(self.formatter.open(&mut self.writer, b'{')); try!(self.formatter.open(&mut self.writer, b'{'));
@ -284,13 +284,13 @@ impl<W, F> ser::Serializer for Serializer<W, F>
} }
#[inline] #[inline]
fn visit_map_elt<K, V>(&mut self, key: K, value: V) -> io::Result<()> fn visit_map_elt<K, V>(&mut self, key: K, value: V) -> Result<()>
where K: ser::Serialize, where K: ser::Serialize,
V: ser::Serialize, V: ser::Serialize,
{ {
try!(self.formatter.comma(&mut self.writer, self.first)); try!(self.formatter.comma(&mut self.writer, self.first));
try!(key.serialize(self)); try!(key.serialize(&mut MapKeySerializer { ser: self }));
try!(self.formatter.colon(&mut self.writer)); try!(self.formatter.colon(&mut self.writer));
try!(value.serialize(self)); try!(value.serialize(self));
@ -305,49 +305,120 @@ impl<W, F> ser::Serializer for Serializer<W, F>
} }
} }
struct MapKeySerializer<'a, W: 'a, F: 'a> {
ser: &'a mut Serializer<W, F>,
}
impl<'a, W, F> ser::Serializer for MapKeySerializer<'a, W, F>
where W: io::Write,
F: Formatter,
{
type Error = Error;
#[inline]
fn visit_str(&mut self, value: &str) -> Result<()> {
self.ser.visit_str(value)
}
fn visit_bool(&mut self, _value: bool) -> Result<()> {
Err(Error::SyntaxError(ErrorCode::KeyMustBeAString, 0, 0))
}
fn visit_i64(&mut self, _value: i64) -> Result<()> {
Err(Error::SyntaxError(ErrorCode::KeyMustBeAString, 0, 0))
}
fn visit_u64(&mut self, _value: u64) -> Result<()> {
Err(Error::SyntaxError(ErrorCode::KeyMustBeAString, 0, 0))
}
fn visit_f64(&mut self, _value: f64) -> Result<()> {
Err(Error::SyntaxError(ErrorCode::KeyMustBeAString, 0, 0))
}
fn visit_unit(&mut self) -> Result<()> {
Err(Error::SyntaxError(ErrorCode::KeyMustBeAString, 0, 0))
}
fn visit_none(&mut self) -> Result<()> {
Err(Error::SyntaxError(ErrorCode::KeyMustBeAString, 0, 0))
}
fn visit_some<V>(&mut self, _value: V) -> Result<()>
where V: ser::Serialize
{
Err(Error::SyntaxError(ErrorCode::KeyMustBeAString, 0, 0))
}
fn visit_seq<V>(&mut self, _visitor: V) -> Result<()>
where V: ser::SeqVisitor,
{
Err(Error::SyntaxError(ErrorCode::KeyMustBeAString, 0, 0))
}
fn visit_seq_elt<T>(&mut self, _value: T) -> Result<()>
where T: ser::Serialize,
{
Err(Error::SyntaxError(ErrorCode::KeyMustBeAString, 0, 0))
}
fn visit_map<V>(&mut self, _visitor: V) -> Result<()>
where V: ser::MapVisitor,
{
Err(Error::SyntaxError(ErrorCode::KeyMustBeAString, 0, 0))
}
fn visit_map_elt<K, V>(&mut self, _key: K, _value: V) -> Result<()>
where K: ser::Serialize,
V: ser::Serialize,
{
Err(Error::SyntaxError(ErrorCode::KeyMustBeAString, 0, 0))
}
}
pub trait Formatter { pub trait Formatter {
fn open<W>(&mut self, writer: &mut W, ch: u8) -> io::Result<()> fn open<W>(&mut self, writer: &mut W, ch: u8) -> Result<()>
where W: io::Write; where W: io::Write;
fn comma<W>(&mut self, writer: &mut W, first: bool) -> io::Result<()> fn comma<W>(&mut self, writer: &mut W, first: bool) -> Result<()>
where W: io::Write; where W: io::Write;
fn colon<W>(&mut self, writer: &mut W) -> io::Result<()> fn colon<W>(&mut self, writer: &mut W) -> Result<()>
where W: io::Write; where W: io::Write;
fn close<W>(&mut self, writer: &mut W, ch: u8) -> io::Result<()> fn close<W>(&mut self, writer: &mut W, ch: u8) -> Result<()>
where W: io::Write; where W: io::Write;
} }
pub struct CompactFormatter; pub struct CompactFormatter;
impl Formatter for CompactFormatter { impl Formatter for CompactFormatter {
fn open<W>(&mut self, writer: &mut W, ch: u8) -> io::Result<()> fn open<W>(&mut self, writer: &mut W, ch: u8) -> Result<()>
where W: io::Write, where W: io::Write,
{ {
writer.write_all(&[ch]) writer.write_all(&[ch]).map_err(From::from)
} }
fn comma<W>(&mut self, writer: &mut W, first: bool) -> io::Result<()> fn comma<W>(&mut self, writer: &mut W, first: bool) -> Result<()>
where W: io::Write, where W: io::Write,
{ {
if first { if first {
Ok(()) Ok(())
} else { } else {
writer.write_all(b",") writer.write_all(b",").map_err(From::from)
} }
} }
fn colon<W>(&mut self, writer: &mut W) -> io::Result<()> fn colon<W>(&mut self, writer: &mut W) -> Result<()>
where W: io::Write, where W: io::Write,
{ {
writer.write_all(b":") writer.write_all(b":").map_err(From::from)
} }
fn close<W>(&mut self, writer: &mut W, ch: u8) -> io::Result<()> fn close<W>(&mut self, writer: &mut W, ch: u8) -> Result<()>
where W: io::Write, where W: io::Write,
{ {
writer.write_all(&[ch]) writer.write_all(&[ch]).map_err(From::from)
} }
} }
@ -370,14 +441,14 @@ impl<'a> PrettyFormatter<'a> {
} }
impl<'a> Formatter for PrettyFormatter<'a> { impl<'a> Formatter for PrettyFormatter<'a> {
fn open<W>(&mut self, writer: &mut W, ch: u8) -> io::Result<()> fn open<W>(&mut self, writer: &mut W, ch: u8) -> Result<()>
where W: io::Write, where W: io::Write,
{ {
self.current_indent += 1; self.current_indent += 1;
writer.write_all(&[ch]) writer.write_all(&[ch]).map_err(From::from)
} }
fn comma<W>(&mut self, writer: &mut W, first: bool) -> io::Result<()> fn comma<W>(&mut self, writer: &mut W, first: bool) -> Result<()>
where W: io::Write, where W: io::Write,
{ {
if first { if first {
@ -389,25 +460,25 @@ impl<'a> Formatter for PrettyFormatter<'a> {
indent(writer, self.current_indent, self.indent) indent(writer, self.current_indent, self.indent)
} }
fn colon<W>(&mut self, writer: &mut W) -> io::Result<()> fn colon<W>(&mut self, writer: &mut W) -> Result<()>
where W: io::Write, where W: io::Write,
{ {
writer.write_all(b": ") writer.write_all(b": ").map_err(From::from)
} }
fn close<W>(&mut self, writer: &mut W, ch: u8) -> io::Result<()> fn close<W>(&mut self, writer: &mut W, ch: u8) -> Result<()>
where W: io::Write, where W: io::Write,
{ {
self.current_indent -= 1; self.current_indent -= 1;
try!(writer.write(b"\n")); try!(writer.write(b"\n"));
try!(indent(writer, self.current_indent, self.indent)); try!(indent(writer, self.current_indent, self.indent));
writer.write_all(&[ch]) writer.write_all(&[ch]).map_err(From::from)
} }
} }
#[inline] #[inline]
pub fn escape_bytes<W>(wr: &mut W, bytes: &[u8]) -> io::Result<()> pub fn escape_bytes<W>(wr: &mut W, bytes: &[u8]) -> Result<()>
where W: io::Write where W: io::Write
{ {
try!(wr.write_all(b"\"")); try!(wr.write_all(b"\""));
@ -444,14 +515,14 @@ pub fn escape_bytes<W>(wr: &mut W, bytes: &[u8]) -> io::Result<()>
} }
#[inline] #[inline]
pub fn escape_str<W>(wr: &mut W, value: &str) -> io::Result<()> pub fn escape_str<W>(wr: &mut W, value: &str) -> Result<()>
where W: io::Write where W: io::Write
{ {
escape_bytes(wr, value.as_bytes()) escape_bytes(wr, value.as_bytes())
} }
#[inline] #[inline]
fn escape_char<W>(wr: &mut W, value: char) -> io::Result<()> fn escape_char<W>(wr: &mut W, value: char) -> Result<()>
where W: io::Write where W: io::Write
{ {
// FIXME: this allocation is required in order to be compatible with stable // FIXME: this allocation is required in order to be compatible with stable
@ -459,31 +530,39 @@ fn escape_char<W>(wr: &mut W, value: char) -> io::Result<()>
escape_bytes(wr, value.to_string().as_bytes()) escape_bytes(wr, value.to_string().as_bytes())
} }
fn fmt_f32_or_null<W>(wr: &mut W, value: f32) -> io::Result<()> fn fmt_f32_or_null<W>(wr: &mut W, value: f32) -> Result<()>
where W: io::Write where W: io::Write
{ {
match value.classify() { match value.classify() {
FpCategory::Nan | FpCategory::Infinite => wr.write_all(b"null"), FpCategory::Nan | FpCategory::Infinite => {
try!(wr.write_all(b"null"))
}
_ => { _ => {
write!(wr, "{:?}", value) try!(write!(wr, "{:?}", value))
} }
} }
Ok(())
} }
fn fmt_f64_or_null<W>(wr: &mut W, value: f64) -> io::Result<()> fn fmt_f64_or_null<W>(wr: &mut W, value: f64) -> Result<()>
where W: io::Write where W: io::Write
{ {
match value.classify() { match value.classify() {
FpCategory::Nan | FpCategory::Infinite => wr.write_all(b"null"), FpCategory::Nan | FpCategory::Infinite => {
try!(wr.write_all(b"null"))
}
_ => { _ => {
write!(wr, "{:?}", value) try!(write!(wr, "{:?}", value))
} }
} }
Ok(())
} }
/// Encode the specified struct into a json `[u8]` writer. /// Encode the specified struct into a json `[u8]` writer.
#[inline] #[inline]
pub fn to_writer<W, T>(writer: &mut W, value: &T) -> io::Result<()> pub fn to_writer<W, T>(writer: &mut W, value: &T) -> Result<()>
where W: io::Write, where W: io::Write,
T: ser::Serialize, T: ser::Serialize,
{ {
@ -494,7 +573,7 @@ pub fn to_writer<W, T>(writer: &mut W, value: &T) -> io::Result<()>
/// Encode the specified struct into a json `[u8]` writer. /// Encode the specified struct into a json `[u8]` writer.
#[inline] #[inline]
pub fn to_writer_pretty<W, T>(writer: &mut W, value: &T) -> io::Result<()> pub fn to_writer_pretty<W, T>(writer: &mut W, value: &T) -> Result<()>
where W: io::Write, where W: io::Write,
T: ser::Serialize, T: ser::Serialize,
{ {
@ -505,47 +584,49 @@ pub fn to_writer_pretty<W, T>(writer: &mut W, value: &T) -> io::Result<()>
/// Encode the specified struct into a json `[u8]` buffer. /// Encode the specified struct into a json `[u8]` buffer.
#[inline] #[inline]
pub fn to_vec<T>(value: &T) -> Vec<u8> pub fn to_vec<T>(value: &T) -> Result<Vec<u8>>
where T: ser::Serialize, where T: ser::Serialize,
{ {
// We are writing to a Vec, which doesn't fail. So we can ignore // We are writing to a Vec, which doesn't fail. So we can ignore
// the error. // the error.
let mut writer = Vec::with_capacity(128); let mut writer = Vec::with_capacity(128);
to_writer(&mut writer, value).unwrap(); try!(to_writer(&mut writer, value));
writer Ok(writer)
} }
/// Encode the specified struct into a json `[u8]` buffer. /// Encode the specified struct into a json `[u8]` buffer.
#[inline] #[inline]
pub fn to_vec_pretty<T>(value: &T) -> Vec<u8> pub fn to_vec_pretty<T>(value: &T) -> Result<Vec<u8>>
where T: ser::Serialize, where T: ser::Serialize,
{ {
// We are writing to a Vec, which doesn't fail. So we can ignore // We are writing to a Vec, which doesn't fail. So we can ignore
// the error. // the error.
let mut writer = Vec::with_capacity(128); let mut writer = Vec::with_capacity(128);
to_writer_pretty(&mut writer, value).unwrap(); try!(to_writer_pretty(&mut writer, value));
writer Ok(writer)
} }
/// Encode the specified struct into a json `String` buffer. /// Encode the specified struct into a json `String` buffer.
#[inline] #[inline]
pub fn to_string<T>(value: &T) -> Result<String, FromUtf8Error> pub fn to_string<T>(value: &T) -> Result<String>
where T: ser::Serialize where T: ser::Serialize
{ {
let vec = to_vec(value); let vec = try!(to_vec(value));
String::from_utf8(vec) let string = try!(String::from_utf8(vec));
Ok(string)
} }
/// Encode the specified struct into a json `String` buffer. /// Encode the specified struct into a json `String` buffer.
#[inline] #[inline]
pub fn to_string_pretty<T>(value: &T) -> Result<String, FromUtf8Error> pub fn to_string_pretty<T>(value: &T) -> Result<String>
where T: ser::Serialize where T: ser::Serialize
{ {
let vec = to_vec_pretty(value); let vec = try!(to_vec_pretty(value));
String::from_utf8(vec) let string = try!(String::from_utf8(vec));
Ok(string)
} }
fn indent<W>(wr: &mut W, n: usize, s: &[u8]) -> io::Result<()> fn indent<W>(wr: &mut W, n: usize, s: &[u8]) -> Result<()>
where W: io::Write, where W: io::Write,
{ {
for _ in 0 .. n { for _ in 0 .. n {

View File

@ -1123,18 +1123,18 @@ fn bench_encoder(b: &mut Bencher) {
#[test] #[test]
fn test_serializer() { fn test_serializer() {
let log = Log::new(); let log = Log::new();
let json = serde_json::to_vec(&log); let json = serde_json::to_vec(&log).unwrap();
assert_eq!(json, JSON_STR.as_bytes()); assert_eq!(json, JSON_STR.as_bytes());
} }
#[bench] #[bench]
fn bench_serializer(b: &mut Bencher) { fn bench_serializer(b: &mut Bencher) {
let log = Log::new(); let log = Log::new();
let json = serde_json::to_vec(&log); let json = serde_json::to_vec(&log).unwrap();
b.bytes = json.len() as u64; b.bytes = json.len() as u64;
b.iter(|| { b.iter(|| {
let _ = serde_json::to_vec(&log); serde_json::to_vec(&log).unwrap();
}); });
} }
@ -1152,7 +1152,7 @@ fn test_serializer_vec() {
#[bench] #[bench]
fn bench_serializer_vec(b: &mut Bencher) { fn bench_serializer_vec(b: &mut Bencher) {
let log = Log::new(); let log = Log::new();
let json = serde_json::to_vec(&log); let json = serde_json::to_vec(&log).unwrap();
b.bytes = json.len() as u64; b.bytes = json.len() as u64;
let mut wr = Vec::with_capacity(1024); let mut wr = Vec::with_capacity(1024);
@ -1169,7 +1169,7 @@ fn bench_serializer_vec(b: &mut Bencher) {
#[bench] #[bench]
fn bench_serializer_slice(b: &mut Bencher) { fn bench_serializer_slice(b: &mut Bencher) {
let log = Log::new(); let log = Log::new();
let json = serde_json::to_vec(&log); let json = serde_json::to_vec(&log).unwrap();
b.bytes = json.len() as u64; b.bytes = json.len() as u64;
let mut buf = [0; 1024]; let mut buf = [0; 1024];
@ -1202,7 +1202,7 @@ fn test_serializer_my_mem_writer0() {
#[bench] #[bench]
fn bench_serializer_my_mem_writer0(b: &mut Bencher) { fn bench_serializer_my_mem_writer0(b: &mut Bencher) {
let log = Log::new(); let log = Log::new();
let json = serde_json::to_vec(&log); let json = serde_json::to_vec(&log).unwrap();
b.bytes = json.len() as u64; b.bytes = json.len() as u64;
let mut wr = MyMemWriter0::with_capacity(1024); let mut wr = MyMemWriter0::with_capacity(1024);
@ -1234,7 +1234,7 @@ fn test_serializer_my_mem_writer1() {
#[bench] #[bench]
fn bench_serializer_my_mem_writer1(b: &mut Bencher) { fn bench_serializer_my_mem_writer1(b: &mut Bencher) {
let log = Log::new(); let log = Log::new();
let json = serde_json::to_vec(&log); let json = serde_json::to_vec(&log).unwrap();
b.bytes = json.len() as u64; b.bytes = json.len() as u64;
let mut wr = MyMemWriter1::with_capacity(1024); let mut wr = MyMemWriter1::with_capacity(1024);

View File

@ -1348,3 +1348,16 @@ fn test_deserialize_from_stream() {
assert_eq!(request, response); assert_eq!(request, response);
} }
#[test]
fn test_serialize_rejects_non_key_maps() {
let map = treemap!(
1 => 2,
3 => 4
);
match serde_json::to_vec(&map).unwrap_err() {
serde_json::Error::SyntaxError(serde_json::ErrorCode::KeyMustBeAString, 0, 0) => {}
_ => panic!("integers used as keys"),
}
}