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::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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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);
|
||||||
|
@ -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"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user