From fe20852b2cd7f4185475f937c36d7fab85015224 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Thu, 13 Aug 2015 22:29:13 -0700 Subject: [PATCH] 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. --- serde_json/src/error.rs | 36 ++--- serde_json/src/ser.rs | 267 ++++++++++++++++++++----------- serde_tests/benches/bench_log.rs | 14 +- serde_tests/tests/test_json.rs | 13 ++ 4 files changed, 205 insertions(+), 125 deletions(-) diff --git a/serde_json/src/error.rs b/serde_json/src/error.rs index 6621188b..6c3a494c 100644 --- a/serde_json/src/error.rs +++ b/serde_json/src/error.rs @@ -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 for Error { } } +impl From for Error { + fn from(error: FromUtf8Error) -> Error { + Error::FromUtf8Error(error) + } +} + impl From for Error { fn from(error: de::value::Error) -> Error { match error { diff --git a/serde_json/src/ser.rs b/serde_json/src/ser.rs index b03ce38b..094022f5 100644 --- a/serde_json/src/ser.rs +++ b/serde_json/src/ser.rs @@ -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 { @@ -60,109 +60,109 @@ impl ser::Serializer for Serializer 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(&mut self, value: V) -> io::Result<()> + fn visit_some(&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(&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 ser::Serializer for Serializer 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 ser::Serializer for Serializer _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 ser::Serializer for Serializer } #[inline] - fn visit_seq(&mut self, mut visitor: V) -> io::Result<()> + fn visit_seq(&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 ser::Serializer for Serializer 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 ser::Serializer for Serializer _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 ser::Serializer for Serializer } #[inline] - fn visit_seq_elt(&mut self, value: T) -> io::Result<()> + fn visit_seq_elt(&mut self, value: T) -> Result<()> where T: ser::Serialize, { try!(self.formatter.comma(&mut self.writer, self.first)); @@ -247,12 +247,12 @@ impl ser::Serializer for Serializer } #[inline] - fn visit_map(&mut self, mut visitor: V) -> io::Result<()> + fn visit_map(&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 ser::Serializer for Serializer _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 ser::Serializer for Serializer } #[inline] - fn visit_map_elt(&mut self, key: K, value: V) -> io::Result<()> + fn visit_map_elt(&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 ser::Serializer for Serializer } } +struct MapKeySerializer<'a, W: 'a, F: 'a> { + ser: &'a mut Serializer, +} + +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(&mut self, _value: V) -> Result<()> + where V: ser::Serialize + { + Err(Error::SyntaxError(ErrorCode::KeyMustBeAString, 0, 0)) + } + + fn visit_seq(&mut self, _visitor: V) -> Result<()> + where V: ser::SeqVisitor, + { + Err(Error::SyntaxError(ErrorCode::KeyMustBeAString, 0, 0)) + } + + fn visit_seq_elt(&mut self, _value: T) -> Result<()> + where T: ser::Serialize, + { + Err(Error::SyntaxError(ErrorCode::KeyMustBeAString, 0, 0)) + } + + fn visit_map(&mut self, _visitor: V) -> Result<()> + where V: ser::MapVisitor, + { + Err(Error::SyntaxError(ErrorCode::KeyMustBeAString, 0, 0)) + } + + fn visit_map_elt(&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(&mut self, writer: &mut W, ch: u8) -> io::Result<()> + fn open(&mut self, writer: &mut W, ch: u8) -> Result<()> where W: io::Write; - fn comma(&mut self, writer: &mut W, first: bool) -> io::Result<()> + fn comma(&mut self, writer: &mut W, first: bool) -> Result<()> where W: io::Write; - fn colon(&mut self, writer: &mut W) -> io::Result<()> + fn colon(&mut self, writer: &mut W) -> Result<()> where W: io::Write; - fn close(&mut self, writer: &mut W, ch: u8) -> io::Result<()> + fn close(&mut self, writer: &mut W, ch: u8) -> Result<()> where W: io::Write; } pub struct CompactFormatter; impl Formatter for CompactFormatter { - fn open(&mut self, writer: &mut W, ch: u8) -> io::Result<()> + fn open(&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(&mut self, writer: &mut W, first: bool) -> io::Result<()> + fn comma(&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(&mut self, writer: &mut W) -> io::Result<()> + fn colon(&mut self, writer: &mut W) -> Result<()> where W: io::Write, { - writer.write_all(b":") + writer.write_all(b":").map_err(From::from) } - fn close(&mut self, writer: &mut W, ch: u8) -> io::Result<()> + fn close(&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(&mut self, writer: &mut W, ch: u8) -> io::Result<()> + fn open(&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(&mut self, writer: &mut W, first: bool) -> io::Result<()> + fn comma(&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(&mut self, writer: &mut W) -> io::Result<()> + fn colon(&mut self, writer: &mut W) -> Result<()> where W: io::Write, { - writer.write_all(b": ") + writer.write_all(b": ").map_err(From::from) } - fn close(&mut self, writer: &mut W, ch: u8) -> io::Result<()> + fn close(&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(wr: &mut W, bytes: &[u8]) -> io::Result<()> +pub fn escape_bytes(wr: &mut W, bytes: &[u8]) -> Result<()> where W: io::Write { try!(wr.write_all(b"\"")); @@ -444,14 +515,14 @@ pub fn escape_bytes(wr: &mut W, bytes: &[u8]) -> io::Result<()> } #[inline] -pub fn escape_str(wr: &mut W, value: &str) -> io::Result<()> +pub fn escape_str(wr: &mut W, value: &str) -> Result<()> where W: io::Write { escape_bytes(wr, value.as_bytes()) } #[inline] -fn escape_char(wr: &mut W, value: char) -> io::Result<()> +fn escape_char(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(wr: &mut W, value: char) -> io::Result<()> escape_bytes(wr, value.to_string().as_bytes()) } -fn fmt_f32_or_null(wr: &mut W, value: f32) -> io::Result<()> +fn fmt_f32_or_null(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(wr: &mut W, value: f64) -> io::Result<()> +fn fmt_f64_or_null(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(writer: &mut W, value: &T) -> io::Result<()> +pub fn to_writer(writer: &mut W, value: &T) -> Result<()> where W: io::Write, T: ser::Serialize, { @@ -494,7 +573,7 @@ pub fn to_writer(writer: &mut W, value: &T) -> io::Result<()> /// Encode the specified struct into a json `[u8]` writer. #[inline] -pub fn to_writer_pretty(writer: &mut W, value: &T) -> io::Result<()> +pub fn to_writer_pretty(writer: &mut W, value: &T) -> Result<()> where W: io::Write, T: ser::Serialize, { @@ -505,47 +584,49 @@ pub fn to_writer_pretty(writer: &mut W, value: &T) -> io::Result<()> /// Encode the specified struct into a json `[u8]` buffer. #[inline] -pub fn to_vec(value: &T) -> Vec +pub fn to_vec(value: &T) -> Result> 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(value: &T) -> Vec +pub fn to_vec_pretty(value: &T) -> Result> 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(value: &T) -> Result +pub fn to_string(value: &T) -> Result 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(value: &T) -> Result +pub fn to_string_pretty(value: &T) -> Result 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(wr: &mut W, n: usize, s: &[u8]) -> io::Result<()> +fn indent(wr: &mut W, n: usize, s: &[u8]) -> Result<()> where W: io::Write, { for _ in 0 .. n { diff --git a/serde_tests/benches/bench_log.rs b/serde_tests/benches/bench_log.rs index 4fa108da..9a4ccd17 100644 --- a/serde_tests/benches/bench_log.rs +++ b/serde_tests/benches/bench_log.rs @@ -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); diff --git a/serde_tests/tests/test_json.rs b/serde_tests/tests/test_json.rs index 934cbcc4..1c092a97 100644 --- a/serde_tests/tests/test_json.rs +++ b/serde_tests/tests/test_json.rs @@ -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"), + } +}