diff --git a/serde_json/src/de.rs b/serde_json/src/de.rs index 31f406af..04491899 100644 --- a/serde_json/src/de.rs +++ b/serde_json/src/de.rs @@ -6,7 +6,7 @@ use std::str; use serde::de; use serde::iter::LineColIterator; -use super::error::{Error, ErrorCode}; +use super::error::{Error, ErrorCode, Result}; pub struct Deserializer>> { rdr: LineColIterator, @@ -28,7 +28,7 @@ impl Deserializer { /// Creates the JSON parser from an `std::iter::Iterator`. #[inline] - pub fn new(rdr: Iter) -> Result, Error> { + pub fn new(rdr: Iter) -> Result> { let mut deserializer = Deserializer { rdr: LineColIterator::new(rdr), ch: None, @@ -41,7 +41,7 @@ impl Deserializer } #[inline] - pub fn end(&mut self) -> Result<(), Error> { + pub fn end(&mut self) -> Result<()> { try!(self.parse_whitespace()); if self.eof() { Ok(()) @@ -54,7 +54,7 @@ impl Deserializer fn ch_or_null(&self) -> u8 { self.ch.unwrap_or(b'\x00') } - fn bump(&mut self) -> Result<(), Error> { + fn bump(&mut self) -> Result<()> { self.ch = match self.rdr.next() { Some(Err(err)) => { return Err(Error::IoError(err)); } Some(Ok(ch)) => Some(ch), @@ -64,7 +64,7 @@ impl Deserializer Ok(()) } - fn next_char(&mut self) -> Result, Error> { + fn next_char(&mut self) -> Result> { try!(self.bump()); Ok(self.ch) } @@ -77,7 +77,7 @@ impl Deserializer Error::SyntaxError(reason, self.rdr.line(), self.rdr.col()) } - fn parse_whitespace(&mut self) -> Result<(), Error> { + fn parse_whitespace(&mut self) -> Result<()> { while self.ch_is(b' ') || self.ch_is(b'\n') || self.ch_is(b'\t') || @@ -86,7 +86,7 @@ impl Deserializer Ok(()) } - fn parse_value(&mut self, mut visitor: V) -> Result + fn parse_value(&mut self, mut visitor: V) -> Result where V: de::Visitor, { try!(self.parse_whitespace()); @@ -108,7 +108,13 @@ impl Deserializer try!(self.parse_ident(b"alse")); visitor.visit_bool(false) } - b'0' ... b'9' | b'-' => self.parse_number(visitor), + b'-' => { + try!(self.bump()); + self.parse_integer(false, visitor) + } + b'0' ... b'9' => { + self.parse_integer(true, visitor) + } b'"' => { try!(self.parse_string()); let s = str::from_utf8(&self.str_buf).unwrap(); @@ -134,7 +140,7 @@ impl Deserializer } } - fn parse_ident(&mut self, ident: &[u8]) -> Result<(), Error> { + fn parse_ident(&mut self, ident: &[u8]) -> Result<()> { for c in ident { if Some(*c) != try!(self.next_char()) { return Err(self.error(ErrorCode::ExpectedSomeIdent)); @@ -145,53 +151,9 @@ impl Deserializer Ok(()) } - fn parse_number(&mut self, mut visitor: V) -> Result + fn parse_integer(&mut self, pos: bool, visitor: V) -> Result where V: de::Visitor, { - let mut neg = false; - - if self.ch_is(b'-') { - try!(self.bump()); - neg = true; - } - - let res = try!(self.parse_integer()); - - if self.ch_is(b'.') || self.ch_is(b'e') || self.ch_is(b'E') { - let mut res = res as f64; - - if self.ch_is(b'.') { - res = try!(self.parse_decimal(res)); - } - - if self.ch_is(b'e') || self.ch_is(b'E') { - res = try!(self.parse_exponent(res)); - } - - if neg { - visitor.visit_f64(-res) - } else { - visitor.visit_f64(res) - } - } else { - if neg { - let res = -(res as i64); - - // Make sure we didn't underflow. - if res > 0 { - Err(self.error(ErrorCode::InvalidNumber)) - } else { - visitor.visit_i64(res) - } - } else { - visitor.visit_u64(res) - } - } - } - - fn parse_integer(&mut self) -> Result { - let mut accum: u64 = 0; - match self.ch_or_null() { b'0' => { try!(self.bump()); @@ -199,41 +161,138 @@ impl Deserializer // There can be only one leading '0'. match self.ch_or_null() { b'0' ... b'9' => { - return Err(self.error(ErrorCode::InvalidNumber)); + Err(self.error(ErrorCode::InvalidNumber)) + } + _ => { + self.parse_number(pos, 0, visitor) } - _ => () } }, - b'1' ... b'9' => { - while !self.eof() { + c @ b'1' ... b'9' => { + try!(self.bump()); + + let mut res: u64 = (c as u64) - ('0' as u64); + + loop { match self.ch_or_null() { c @ b'0' ... b'9' => { - accum = try_or_invalid!(self, accum.checked_mul(10)); - accum = try_or_invalid!(self, accum.checked_add((c as u64) - ('0' as u64))); - try!(self.bump()); + + let digit = (c as u64) - ('0' as u64); + + // We need to be careful with overflow. If we can, try to keep the + // number as a `u64` until we grow too large. At that point, switch to + // parsing the value as a `f64`. + match res.checked_mul(10).and_then(|val| val.checked_add(digit)) { + Some(res_) => { res = res_; } + None => { + return self.parse_float( + pos, + (res as f64) * 10.0 + (digit as f64), + visitor); + } + } + } + _ => { + return self.parse_number(pos, res, visitor); } - _ => break, } } } - _ => { return Err(self.error(ErrorCode::InvalidNumber)); } + _ => { + Err(self.error(ErrorCode::InvalidNumber)) + } } - - Ok(accum) } - fn parse_decimal(&mut self, res: f64) -> Result { + fn parse_float(&mut self, + pos: bool, + mut res: f64, + mut visitor: V) -> Result + where V: de::Visitor, + { + loop { + match self.ch_or_null() { + c @ b'0' ... b'9' => { + try!(self.bump()); + + let digit = (c as u64) - ('0' as u64); + + res *= 10.0; + res += digit as f64; + } + _ => { + match self.ch_or_null() { + b'.' => { + return self.parse_decimal(pos, res, visitor); + } + b'e' | b'E' => { + return self.parse_exponent(pos, res, visitor); + } + _ => { + if !pos { + res = -res; + } + + return visitor.visit_f64(res); + } + } + } + } + } + } + + fn parse_number(&mut self, + pos: bool, + res: u64, + mut visitor: V) -> Result + where V: de::Visitor, + { + match self.ch_or_null() { + b'.' => { + self.parse_decimal(pos, res as f64, visitor) + } + b'e' | b'E' => { + self.parse_exponent(pos, res as f64, visitor) + } + _ => { + if pos { + visitor.visit_u64(res) + } else { + // FIXME: `wrapping_neg` will be stable in Rust 1.2 + //let res_i64 = (res as i64).wrapping_neg(); + let res_i64 = (!res + 1) as i64; + + // Convert into a float if we underflow. + if res_i64 > 0 { + visitor.visit_f64(-(res as f64)) + } else { + visitor.visit_i64(res_i64) + } + } + } + } + } + + fn parse_decimal(&mut self, + pos: bool, + mut res: f64, + mut visitor: V) -> Result + where V: de::Visitor, + { try!(self.bump()); + let mut dec = 0.1; + // Make sure a digit follows the decimal place. match self.ch_or_null() { - b'0' ... b'9' => (), + c @ b'0' ... b'9' => { + try!(self.bump()); + res += (((c as u64) - (b'0' as u64)) as f64) * dec; + } _ => { return Err(self.error(ErrorCode::InvalidNumber)); } } - let mut res = res; - let mut dec = 1.0; while !self.eof() { match self.ch_or_null() { c @ b'0' ... b'9' => { @@ -245,36 +304,53 @@ impl Deserializer } } - Ok(res) + match self.ch_or_null() { + b'e' | b'E' => { + self.parse_exponent(pos, res, visitor) + } + _ => { + if pos { + visitor.visit_f64(res) + } else { + visitor.visit_f64(-res) + } + } + } + } - fn parse_exponent(&mut self, mut res: f64) -> Result { + fn parse_exponent(&mut self, + pos: bool, + mut res: f64, + mut visitor: V) -> Result + where V: de::Visitor, + { try!(self.bump()); - let mut exp: u64 = 0; - let mut neg_exp = false; - - if self.ch_is(b'+') { - try!(self.bump()); - } else if self.ch_is(b'-') { - try!(self.bump()); - neg_exp = true; - } + let pos_exp = match self.ch_or_null() { + b'+' => { try!(self.bump()); true } + b'-' => { try!(self.bump()); false } + _ => { true } + }; // Make sure a digit follows the exponent place. - match self.ch_or_null() { - b'0' ... b'9' => (), + let mut exp = match self.ch_or_null() { + c @ b'0' ... b'9' => { + try!(self.bump()); + (c as u64) - (b'0' as u64) + } _ => { return Err(self.error(ErrorCode::InvalidNumber)); } - } - while !self.eof() { + }; + + loop { match self.ch_or_null() { c @ b'0' ... b'9' => { + try!(self.bump()); + exp = try_or_invalid!(self, exp.checked_mul(10)); exp = try_or_invalid!(self, exp.checked_add((c as u64) - (b'0' as u64))); - - try!(self.bump()); } - _ => break + _ => { break; } } } @@ -284,16 +360,20 @@ impl Deserializer return Err(self.error(ErrorCode::InvalidNumber)); }; - if neg_exp { - res /= exp; - } else { + if pos_exp { res *= exp; + } else { + res /= exp; } - Ok(res) + if pos { + visitor.visit_f64(res) + } else { + visitor.visit_f64(-res) + } } - fn decode_hex_escape(&mut self) -> Result { + fn decode_hex_escape(&mut self) -> Result { let mut i = 0; let mut n = 0u16; while i < 4 && !self.eof() { @@ -320,7 +400,7 @@ impl Deserializer Ok(n) } - fn parse_string(&mut self) -> Result<(), Error> { + fn parse_string(&mut self) -> Result<()> { self.str_buf.clear(); loop { @@ -409,7 +489,7 @@ impl Deserializer } } - fn parse_object_colon(&mut self) -> Result<(), Error> { + fn parse_object_colon(&mut self) -> Result<()> { try!(self.parse_whitespace()); if self.ch_is(b':') { @@ -429,14 +509,14 @@ impl de::Deserializer for Deserializer type Error = Error; #[inline] - fn visit(&mut self, visitor: V) -> Result + fn visit(&mut self, visitor: V) -> Result where V: de::Visitor, { self.parse_value(visitor) } #[inline] - fn visit_option(&mut self, mut visitor: V) -> Result + fn visit_option(&mut self, mut visitor: V) -> Result where V: de::Visitor, { try!(self.parse_whitespace()); @@ -456,7 +536,7 @@ impl de::Deserializer for Deserializer #[inline] fn visit_newtype_struct(&mut self, _name: &str, - mut visitor: V) -> Result + mut visitor: V) -> Result where V: de::Visitor, { visitor.visit_newtype_struct(self) @@ -466,7 +546,7 @@ impl de::Deserializer for Deserializer fn visit_enum(&mut self, _name: &str, _variants: &'static [&'static str], - mut visitor: V) -> Result + mut visitor: V) -> Result where V: de::EnumVisitor, { try!(self.parse_whitespace()); @@ -517,7 +597,7 @@ impl<'a, Iter> de::SeqVisitor for SeqVisitor<'a, Iter> { type Error = Error; - fn visit(&mut self) -> Result, Error> + fn visit(&mut self) -> Result> where T: de::Deserialize, { try!(self.de.parse_whitespace()); @@ -542,7 +622,7 @@ impl<'a, Iter> de::SeqVisitor for SeqVisitor<'a, Iter> Ok(Some(value)) } - fn end(&mut self) -> Result<(), Error> { + fn end(&mut self) -> Result<()> { try!(self.de.parse_whitespace()); if self.de.ch_is(b']') { @@ -574,7 +654,7 @@ impl<'a, Iter> de::MapVisitor for MapVisitor<'a, Iter> { type Error = Error; - fn visit_key(&mut self) -> Result, Error> + fn visit_key(&mut self) -> Result> where K: de::Deserialize, { try!(self.de.parse_whitespace()); @@ -607,7 +687,7 @@ impl<'a, Iter> de::MapVisitor for MapVisitor<'a, Iter> Ok(Some(try!(de::Deserialize::deserialize(self.de)))) } - fn visit_value(&mut self) -> Result + fn visit_value(&mut self) -> Result where V: de::Deserialize, { try!(self.de.parse_object_colon()); @@ -615,7 +695,7 @@ impl<'a, Iter> de::MapVisitor for MapVisitor<'a, Iter> Ok(try!(de::Deserialize::deserialize(self.de))) } - fn end(&mut self) -> Result<(), Error> { + fn end(&mut self) -> Result<()> { try!(self.de.parse_whitespace()); if self.de.ch_is(b'}') { @@ -628,7 +708,7 @@ impl<'a, Iter> de::MapVisitor for MapVisitor<'a, Iter> } } - fn missing_field(&mut self, _field: &'static str) -> Result + fn missing_field(&mut self, _field: &'static str) -> Result where V: de::Deserialize, { let mut de = de::value::ValueDeserializer::into_deserializer(()); @@ -641,7 +721,7 @@ impl de::VariantVisitor for Deserializer { type Error = Error; - fn visit_variant(&mut self) -> Result + fn visit_variant(&mut self) -> Result where V: de::Deserialize { let val = try!(de::Deserialize::deserialize(self)); @@ -649,11 +729,11 @@ impl de::VariantVisitor for Deserializer Ok(val) } - fn visit_unit(&mut self) -> Result<(), Error> { + fn visit_unit(&mut self) -> Result<()> { de::Deserialize::deserialize(self) } - fn visit_newtype(&mut self) -> Result + fn visit_newtype(&mut self) -> Result where T: de::Deserialize, { de::Deserialize::deserialize(self) @@ -661,7 +741,7 @@ impl de::VariantVisitor for Deserializer fn visit_tuple(&mut self, _len: usize, - visitor: V) -> Result + visitor: V) -> Result where V: de::Visitor, { de::Deserializer::visit(self, visitor) @@ -669,7 +749,7 @@ impl de::VariantVisitor for Deserializer fn visit_struct(&mut self, _fields: &'static [&'static str], - visitor: V) -> Result + visitor: V) -> Result where V: de::Visitor, { de::Deserializer::visit(self, visitor) @@ -677,7 +757,7 @@ impl de::VariantVisitor for Deserializer } /// Decodes a json value from a `std::io::Read`. -pub fn from_iter(iter: I) -> Result +pub fn from_iter(iter: I) -> Result where I: Iterator>, T: de::Deserialize, { @@ -690,7 +770,7 @@ pub fn from_iter(iter: I) -> Result } /// Decodes a json value from a `std::io::Read`. -pub fn from_reader(rdr: R) -> Result +pub fn from_reader(rdr: R) -> Result where R: io::Read, T: de::Deserialize, { @@ -698,14 +778,14 @@ pub fn from_reader(rdr: R) -> Result } /// Decodes a json value from a `&str`. -pub fn from_slice(v: &[u8]) -> Result +pub fn from_slice(v: &[u8]) -> Result where T: de::Deserialize { from_iter(v.iter().map(|byte| Ok(*byte))) } /// Decodes a json value from a `&str`. -pub fn from_str(s: &str) -> Result +pub fn from_str(s: &str) -> Result where T: de::Deserialize { from_slice(s.as_bytes()) diff --git a/serde_json/src/error.rs b/serde_json/src/error.rs index 171e2459..beaa8a72 100644 --- a/serde_json/src/error.rs +++ b/serde_json/src/error.rs @@ -1,6 +1,7 @@ use std::error; use std::fmt; use std::io; +use std::result; use serde::de; @@ -183,3 +184,6 @@ impl de::Error for Error { Error::MissingFieldError(field) } } + +/// Helper alias for `Result` objects that return a JSON `Error`. +pub type Result = result::Result; diff --git a/serde_json/src/lib.rs b/serde_json/src/lib.rs index 3032db9c..e113127a 100644 --- a/serde_json/src/lib.rs +++ b/serde_json/src/lib.rs @@ -96,7 +96,7 @@ extern crate num; extern crate serde; pub use self::de::{Deserializer, from_str}; -pub use self::error::{Error, ErrorCode}; +pub use self::error::{Error, ErrorCode, Result}; pub use self::ser::{ Serializer, to_writer, diff --git a/serde_json/src/ser.rs b/serde_json/src/ser.rs index 67674aa5..b03ce38b 100644 --- a/serde_json/src/ser.rs +++ b/serde_json/src/ser.rs @@ -465,12 +465,7 @@ fn fmt_f32_or_null(wr: &mut W, value: f32) -> io::Result<()> match value.classify() { FpCategory::Nan | FpCategory::Infinite => wr.write_all(b"null"), _ => { - let s = format!("{:?}", value); - try!(wr.write_all(s.as_bytes())); - if !s.contains('.') { - try!(wr.write_all(b".0")) - } - Ok(()) + write!(wr, "{:?}", value) } } } @@ -481,12 +476,7 @@ fn fmt_f64_or_null(wr: &mut W, value: f64) -> io::Result<()> match value.classify() { FpCategory::Nan | FpCategory::Infinite => wr.write_all(b"null"), _ => { - let s = format!("{:?}", value); - try!(wr.write_all(s.as_bytes())); - if !s.contains('.') { - try!(wr.write_all(b".0")) - } - Ok(()) + write!(wr, "{:?}", value) } } } diff --git a/serde_tests/tests/test_json.rs b/serde_tests/tests/test_json.rs index 14345a28..d8e177b7 100644 --- a/serde_tests/tests/test_json.rs +++ b/serde_tests/tests/test_json.rs @@ -1,6 +1,9 @@ use std::collections::BTreeMap; +use std::f64; use std::fmt::Debug; +use std::i64; use std::marker::PhantomData; +use std::u64; use serde::de; use serde::ser; @@ -82,12 +85,23 @@ fn test_write_null() { test_pretty_encode_ok(tests); } +#[test] +fn test_write_u64() { + let tests = &[ + (3u64, "3"), + (u64::MAX, &u64::MAX.to_string()), + ]; + test_encode_ok(tests); + test_pretty_encode_ok(tests); +} + #[test] fn test_write_i64() { let tests = &[ (3i64, "3"), (-2i64, "-2"), (-1234i64, "-1234"), + (i64::MIN, &i64::MIN.to_string()), ]; test_encode_ok(tests); test_pretty_encode_ok(tests); @@ -95,11 +109,18 @@ fn test_write_i64() { #[test] fn test_write_f64() { + let min_string = format!("{:?}", f64::MIN); + let max_string = format!("{:?}", f64::MAX); + let epsilon_string = format!("{:?}", f64::EPSILON); + let tests = &[ - (3.0, "3.0"), + (3.0, "3"), (3.1, "3.1"), (-1.5, "-1.5"), (0.5, "0.5"), + (f64::MIN, &min_string), + (f64::MAX, &max_string), + (f64::EPSILON, &epsilon_string), ]; test_encode_ok(tests); test_pretty_encode_ok(tests); @@ -621,7 +642,7 @@ fn test_write_option() { ]); } -fn test_parse_ok(errors: Vec<(&'static str, T)>) +fn test_parse_ok(errors: Vec<(&str, T)>) where T: Clone + Debug + PartialEq + ser::Serialize + de::Deserialize, { for (s, value) in errors { @@ -707,8 +728,7 @@ fn test_parse_number_errors() { ("1e", Error::SyntaxError(ErrorCode::InvalidNumber, 1, 2)), ("1e+", Error::SyntaxError(ErrorCode::InvalidNumber, 1, 3)), ("1a", Error::SyntaxError(ErrorCode::TrailingCharacters, 1, 2)), - ("777777777777777777777777777", Error::SyntaxError(ErrorCode::InvalidNumber, 1, 20)), - ("1e777777777777777777777777777", Error::SyntaxError(ErrorCode::InvalidNumber, 1, 22)), + ("1e777777777777777777777777777", Error::SyntaxError(ErrorCode::InvalidNumber, 1, 23)), ]); } @@ -718,28 +738,44 @@ fn test_parse_i64() { ("-2", -2), ("-1234", -1234), (" -1234 ", -1234), + (&i64::MIN.to_string(), i64::MIN), + (&i64::MAX.to_string(), i64::MAX), ]); } #[test] fn test_parse_u64() { test_parse_ok(vec![ + ("0", 0u64), ("3", 3u64), ("1234", 1234), + (&u64::MAX.to_string(), u64::MAX), ]); } #[test] fn test_parse_f64() { test_parse_ok(vec![ + ("0.0", 0.0f64), ("3.0", 3.0f64), + ("3.00", 3.0f64), ("3.1", 3.1), ("-1.2", -1.2), ("0.4", 0.4), ("0.4e5", 0.4e5), + ("0.4e+5", 0.4e5), ("0.4e15", 0.4e15), - ("0.4e-01", 0.4e-01), - (" 0.4e-01 ", 0.4e-01), + ("0.4e+15", 0.4e15), + ("0.4e-01", 0.4e-1), + (" 0.4e-01 ", 0.4e-1), + ("0.4e-001", 0.4e-1), + ("0.4e-0", 0.4e0), + ("0.00e00", 0.0), + ("0.00e+00", 0.0), + ("0.00e-00", 0.0), + (&format!("{:?}", (i64::MIN as f64) - 1.0), (i64::MIN as f64) - 1.0), + (&format!("{:?}", (u64::MAX as f64) + 1.0), (u64::MAX as f64) + 1.0), + (&format!("{:?}", f64::EPSILON), f64::EPSILON), ]); }