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:
parent
fc58ea7487
commit
fe20852b2c
@ -2,6 +2,7 @@ use std::error;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::result;
|
||||
use std::string::FromUtf8Error;
|
||||
|
||||
use serde::de;
|
||||
|
||||
@ -44,7 +45,6 @@ impl fmt::Debug for ErrorCode {
|
||||
use std::fmt::Debug;
|
||||
|
||||
match *self {
|
||||
//ErrorCode::ConversionError(ref token) => write!(f, "failed to convert {}", token),
|
||||
ErrorCode::EOFWhileParsingList => "EOF While parsing list".fmt(f),
|
||||
ErrorCode::EOFWhileParsingObject => "EOF While parsing object".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::ExpectedSomeIdent => "expected ident".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::InvalidNumber => "invalid number".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::TrailingCharacters => "trailing characters".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::UnrecognizedHex => "invalid \\u escape (unrecognized hex)".fmt(f),
|
||||
}
|
||||
@ -85,13 +83,8 @@ pub enum Error {
|
||||
/// msg, line, col
|
||||
SyntaxError(ErrorCode, usize, usize),
|
||||
IoError(io::Error),
|
||||
/*
|
||||
ExpectedError(String, String),
|
||||
*/
|
||||
MissingFieldError(&'static str),
|
||||
/*
|
||||
UnknownVariantError(String),
|
||||
*/
|
||||
FromUtf8Error(FromUtf8Error),
|
||||
}
|
||||
|
||||
impl error::Error for Error {
|
||||
@ -99,19 +92,15 @@ impl error::Error for Error {
|
||||
match *self {
|
||||
Error::SyntaxError(..) => "syntax error",
|
||||
Error::IoError(ref error) => error::Error::description(error),
|
||||
/*
|
||||
Error::ExpectedError(ref expected, _) => &expected,
|
||||
*/
|
||||
Error::MissingFieldError(_) => "missing field",
|
||||
/*
|
||||
Error::UnknownVariantError(_) => "unknown variant",
|
||||
*/
|
||||
Error::FromUtf8Error(ref error) => error.description(),
|
||||
}
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&error::Error> {
|
||||
match *self {
|
||||
Error::IoError(ref error) => Some(error),
|
||||
Error::FromUtf8Error(ref error) => Some(error),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@ -125,19 +114,10 @@ impl fmt::Display for Error {
|
||||
write!(fmt, "{:?} at line {} column {}", code, line, col)
|
||||
}
|
||||
Error::IoError(ref error) => fmt::Display::fmt(error, fmt),
|
||||
/*
|
||||
Error::ExpectedError(ref expected, ref found) => {
|
||||
Some(format!("expected {}, found {}", expected, found))
|
||||
}
|
||||
*/
|
||||
Error::FromUtf8Error(ref error) => fmt::Display::fmt(error, fmt),
|
||||
Error::MissingFieldError(ref 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 {
|
||||
fn from(error: de::value::Error) -> Error {
|
||||
match error {
|
||||
|
@ -1,8 +1,8 @@
|
||||
use std::io;
|
||||
use std::num::FpCategory;
|
||||
use std::string::FromUtf8Error;
|
||||
|
||||
use serde::ser;
|
||||
use super::error::{Error, ErrorCode, Result};
|
||||
|
||||
/// A structure for implementing serialization to JSON.
|
||||
pub struct Serializer<W, F=CompactFormatter> {
|
||||
@ -60,109 +60,109 @@ impl<W, F> ser::Serializer for Serializer<W, F>
|
||||
where W: io::Write,
|
||||
F: Formatter,
|
||||
{
|
||||
type Error = io::Error;
|
||||
type Error = Error;
|
||||
|
||||
#[inline]
|
||||
fn visit_bool(&mut self, value: bool) -> io::Result<()> {
|
||||
fn visit_bool(&mut self, value: bool) -> Result<()> {
|
||||
if value {
|
||||
self.writer.write_all(b"true")
|
||||
self.writer.write_all(b"true").map_err(From::from)
|
||||
} else {
|
||||
self.writer.write_all(b"false")
|
||||
self.writer.write_all(b"false").map_err(From::from)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_isize(&mut self, value: isize) -> io::Result<()> {
|
||||
write!(&mut self.writer, "{}", value)
|
||||
fn visit_isize(&mut self, value: isize) -> Result<()> {
|
||||
write!(&mut self.writer, "{}", value).map_err(From::from)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_i8(&mut self, value: i8) -> io::Result<()> {
|
||||
write!(&mut self.writer, "{}", value)
|
||||
fn visit_i8(&mut self, value: i8) -> Result<()> {
|
||||
write!(&mut self.writer, "{}", value).map_err(From::from)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_i16(&mut self, value: i16) -> io::Result<()> {
|
||||
write!(&mut self.writer, "{}", value)
|
||||
fn visit_i16(&mut self, value: i16) -> Result<()> {
|
||||
write!(&mut self.writer, "{}", value).map_err(From::from)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_i32(&mut self, value: i32) -> io::Result<()> {
|
||||
write!(&mut self.writer, "{}", value)
|
||||
fn visit_i32(&mut self, value: i32) -> Result<()> {
|
||||
write!(&mut self.writer, "{}", value).map_err(From::from)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_i64(&mut self, value: i64) -> io::Result<()> {
|
||||
write!(&mut self.writer, "{}", value)
|
||||
fn visit_i64(&mut self, value: i64) -> Result<()> {
|
||||
write!(&mut self.writer, "{}", value).map_err(From::from)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_usize(&mut self, value: usize) -> io::Result<()> {
|
||||
write!(&mut self.writer, "{}", value)
|
||||
fn visit_usize(&mut self, value: usize) -> Result<()> {
|
||||
write!(&mut self.writer, "{}", value).map_err(From::from)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_u8(&mut self, value: u8) -> io::Result<()> {
|
||||
write!(&mut self.writer, "{}", value)
|
||||
fn visit_u8(&mut self, value: u8) -> Result<()> {
|
||||
write!(&mut self.writer, "{}", value).map_err(From::from)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_u16(&mut self, value: u16) -> io::Result<()> {
|
||||
write!(&mut self.writer, "{}", value)
|
||||
fn visit_u16(&mut self, value: u16) -> Result<()> {
|
||||
write!(&mut self.writer, "{}", value).map_err(From::from)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_u32(&mut self, value: u32) -> io::Result<()> {
|
||||
write!(&mut self.writer, "{}", value)
|
||||
fn visit_u32(&mut self, value: u32) -> Result<()> {
|
||||
write!(&mut self.writer, "{}", value).map_err(From::from)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_u64(&mut self, value: u64) -> io::Result<()> {
|
||||
write!(&mut self.writer, "{}", value)
|
||||
fn visit_u64(&mut self, value: u64) -> Result<()> {
|
||||
write!(&mut self.writer, "{}", value).map_err(From::from)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_f32(&mut self, value: f32) -> io::Result<()> {
|
||||
fmt_f32_or_null(&mut self.writer, value)
|
||||
fn visit_f32(&mut self, value: f32) -> Result<()> {
|
||||
fmt_f32_or_null(&mut self.writer, value).map_err(From::from)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_f64(&mut self, value: f64) -> io::Result<()> {
|
||||
fmt_f64_or_null(&mut self.writer, value)
|
||||
fn visit_f64(&mut self, value: f64) -> Result<()> {
|
||||
fmt_f64_or_null(&mut self.writer, value).map_err(From::from)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_char(&mut self, value: char) -> io::Result<()> {
|
||||
escape_char(&mut self.writer, value)
|
||||
fn visit_char(&mut self, value: char) -> Result<()> {
|
||||
escape_char(&mut self.writer, value).map_err(From::from)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_str(&mut self, value: &str) -> io::Result<()> {
|
||||
escape_str(&mut self.writer, value)
|
||||
fn visit_str(&mut self, value: &str) -> Result<()> {
|
||||
escape_str(&mut self.writer, value).map_err(From::from)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_none(&mut self) -> io::Result<()> {
|
||||
fn visit_none(&mut self) -> Result<()> {
|
||||
self.visit_unit()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_some<V>(&mut self, value: V) -> io::Result<()>
|
||||
fn visit_some<V>(&mut self, value: V) -> Result<()>
|
||||
where V: ser::Serialize
|
||||
{
|
||||
value.serialize(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_unit(&mut self) -> io::Result<()> {
|
||||
self.writer.write_all(b"null")
|
||||
fn visit_unit(&mut self) -> Result<()> {
|
||||
self.writer.write_all(b"null").map_err(From::from)
|
||||
}
|
||||
|
||||
/// Override `visit_newtype_struct` to serialize newtypes without an object wrapper.
|
||||
#[inline]
|
||||
fn visit_newtype_struct<T>(&mut self,
|
||||
_name: &'static str,
|
||||
value: T) -> Result<(), Self::Error>
|
||||
value: T) -> Result<()>
|
||||
where T: ser::Serialize,
|
||||
{
|
||||
value.serialize(self)
|
||||
@ -172,7 +172,7 @@ impl<W, F> ser::Serializer for Serializer<W, F>
|
||||
fn visit_unit_variant(&mut self,
|
||||
_name: &str,
|
||||
_variant_index: usize,
|
||||
variant: &str) -> io::Result<()> {
|
||||
variant: &str) -> Result<()> {
|
||||
try!(self.formatter.open(&mut self.writer, b'{'));
|
||||
try!(self.formatter.comma(&mut self.writer, true));
|
||||
try!(self.visit_str(variant));
|
||||
@ -186,7 +186,7 @@ impl<W, F> ser::Serializer for Serializer<W, F>
|
||||
_name: &str,
|
||||
_variant_index: usize,
|
||||
variant: &str,
|
||||
value: T) -> io::Result<()>
|
||||
value: T) -> Result<()>
|
||||
where T: ser::Serialize,
|
||||
{
|
||||
try!(self.formatter.open(&mut self.writer, b'{'));
|
||||
@ -198,12 +198,12 @@ impl<W, F> ser::Serializer for Serializer<W, F>
|
||||
}
|
||||
|
||||
#[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,
|
||||
{
|
||||
match visitor.len() {
|
||||
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'['));
|
||||
@ -212,7 +212,7 @@ impl<W, F> ser::Serializer for Serializer<W, F>
|
||||
|
||||
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,
|
||||
_variant_index: usize,
|
||||
variant: &str,
|
||||
visitor: V) -> io::Result<()>
|
||||
visitor: V) -> Result<()>
|
||||
where V: ser::SeqVisitor,
|
||||
{
|
||||
try!(self.formatter.open(&mut self.writer, b'{'));
|
||||
@ -235,7 +235,7 @@ impl<W, F> ser::Serializer for Serializer<W, F>
|
||||
}
|
||||
|
||||
#[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,
|
||||
{
|
||||
try!(self.formatter.comma(&mut self.writer, self.first));
|
||||
@ -247,12 +247,12 @@ impl<W, F> ser::Serializer for Serializer<W, F>
|
||||
}
|
||||
|
||||
#[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,
|
||||
{
|
||||
match visitor.len() {
|
||||
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'{'));
|
||||
@ -271,7 +271,7 @@ impl<W, F> ser::Serializer for Serializer<W, F>
|
||||
_name: &str,
|
||||
_variant_index: usize,
|
||||
variant: &str,
|
||||
visitor: V) -> io::Result<()>
|
||||
visitor: V) -> Result<()>
|
||||
where V: ser::MapVisitor,
|
||||
{
|
||||
try!(self.formatter.open(&mut self.writer, b'{'));
|
||||
@ -284,13 +284,13 @@ impl<W, F> ser::Serializer for Serializer<W, F>
|
||||
}
|
||||
|
||||
#[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,
|
||||
V: ser::Serialize,
|
||||
{
|
||||
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!(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 {
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
fn colon<W>(&mut self, writer: &mut W) -> io::Result<()>
|
||||
fn colon<W>(&mut self, writer: &mut W) -> Result<()>
|
||||
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;
|
||||
}
|
||||
|
||||
pub struct 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,
|
||||
{
|
||||
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,
|
||||
{
|
||||
if first {
|
||||
Ok(())
|
||||
} 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,
|
||||
{
|
||||
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,
|
||||
{
|
||||
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> {
|
||||
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,
|
||||
{
|
||||
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,
|
||||
{
|
||||
if first {
|
||||
@ -389,25 +460,25 @@ impl<'a> Formatter for PrettyFormatter<'a> {
|
||||
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,
|
||||
{
|
||||
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,
|
||||
{
|
||||
self.current_indent -= 1;
|
||||
try!(writer.write(b"\n"));
|
||||
try!(indent(writer, self.current_indent, self.indent));
|
||||
|
||||
writer.write_all(&[ch])
|
||||
writer.write_all(&[ch]).map_err(From::from)
|
||||
}
|
||||
}
|
||||
|
||||
#[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
|
||||
{
|
||||
try!(wr.write_all(b"\""));
|
||||
@ -444,14 +515,14 @@ pub fn escape_bytes<W>(wr: &mut W, bytes: &[u8]) -> io::Result<()>
|
||||
}
|
||||
|
||||
#[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
|
||||
{
|
||||
escape_bytes(wr, value.as_bytes())
|
||||
}
|
||||
|
||||
#[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
|
||||
{
|
||||
// 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())
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
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.
|
||||
#[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,
|
||||
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.
|
||||
#[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,
|
||||
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.
|
||||
#[inline]
|
||||
pub fn to_vec<T>(value: &T) -> Vec<u8>
|
||||
pub fn to_vec<T>(value: &T) -> Result<Vec<u8>>
|
||||
where T: ser::Serialize,
|
||||
{
|
||||
// We are writing to a Vec, which doesn't fail. So we can ignore
|
||||
// the error.
|
||||
let mut writer = Vec::with_capacity(128);
|
||||
to_writer(&mut writer, value).unwrap();
|
||||
writer
|
||||
try!(to_writer(&mut writer, value));
|
||||
Ok(writer)
|
||||
}
|
||||
|
||||
/// Encode the specified struct into a json `[u8]` buffer.
|
||||
#[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,
|
||||
{
|
||||
// We are writing to a Vec, which doesn't fail. So we can ignore
|
||||
// the error.
|
||||
let mut writer = Vec::with_capacity(128);
|
||||
to_writer_pretty(&mut writer, value).unwrap();
|
||||
writer
|
||||
try!(to_writer_pretty(&mut writer, value));
|
||||
Ok(writer)
|
||||
}
|
||||
|
||||
/// Encode the specified struct into a json `String` buffer.
|
||||
#[inline]
|
||||
pub fn to_string<T>(value: &T) -> Result<String, FromUtf8Error>
|
||||
pub fn to_string<T>(value: &T) -> Result<String>
|
||||
where T: ser::Serialize
|
||||
{
|
||||
let vec = to_vec(value);
|
||||
String::from_utf8(vec)
|
||||
let vec = try!(to_vec(value));
|
||||
let string = try!(String::from_utf8(vec));
|
||||
Ok(string)
|
||||
}
|
||||
|
||||
/// Encode the specified struct into a json `String` buffer.
|
||||
#[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
|
||||
{
|
||||
let vec = to_vec_pretty(value);
|
||||
String::from_utf8(vec)
|
||||
let vec = try!(to_vec_pretty(value));
|
||||
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,
|
||||
{
|
||||
for _ in 0 .. n {
|
||||
|
@ -1123,18 +1123,18 @@ fn bench_encoder(b: &mut Bencher) {
|
||||
#[test]
|
||||
fn test_serializer() {
|
||||
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());
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_serializer(b: &mut Bencher) {
|
||||
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.iter(|| {
|
||||
let _ = serde_json::to_vec(&log);
|
||||
serde_json::to_vec(&log).unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
@ -1152,7 +1152,7 @@ fn test_serializer_vec() {
|
||||
#[bench]
|
||||
fn bench_serializer_vec(b: &mut Bencher) {
|
||||
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;
|
||||
|
||||
let mut wr = Vec::with_capacity(1024);
|
||||
@ -1169,7 +1169,7 @@ fn bench_serializer_vec(b: &mut Bencher) {
|
||||
#[bench]
|
||||
fn bench_serializer_slice(b: &mut Bencher) {
|
||||
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;
|
||||
|
||||
let mut buf = [0; 1024];
|
||||
@ -1202,7 +1202,7 @@ fn test_serializer_my_mem_writer0() {
|
||||
#[bench]
|
||||
fn bench_serializer_my_mem_writer0(b: &mut Bencher) {
|
||||
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;
|
||||
|
||||
let mut wr = MyMemWriter0::with_capacity(1024);
|
||||
@ -1234,7 +1234,7 @@ fn test_serializer_my_mem_writer1() {
|
||||
#[bench]
|
||||
fn bench_serializer_my_mem_writer1(b: &mut Bencher) {
|
||||
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;
|
||||
|
||||
let mut wr = MyMemWriter1::with_capacity(1024);
|
||||
|
@ -1348,3 +1348,16 @@ fn test_deserialize_from_stream() {
|
||||
|
||||
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"),
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user