diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/de/impls.rs | 21 | ||||
-rw-r--r-- | src/lib.rs | 6 | ||||
-rw-r--r-- | src/private/de.rs | 37 | ||||
-rw-r--r-- | src/ser/impls.rs | 55 |
4 files changed, 100 insertions, 19 deletions
diff --git a/src/de/impls.rs b/src/de/impls.rs index 409f6cb..59d90d2 100644 --- a/src/de/impls.rs +++ b/src/de/impls.rs @@ -2046,6 +2046,17 @@ impl<'de> Deserialize<'de> for SystemTime { } } + fn check_overflow<E>(secs: u64, nanos: u32) -> Result<(), E> + where + E: Error, + { + static NANOS_PER_SEC: u32 = 1_000_000_000; + match secs.checked_add((nanos / NANOS_PER_SEC) as u64) { + Some(_) => Ok(()), + None => Err(E::custom("overflow deserializing SystemTime epoch offset")), + } + } + struct DurationVisitor; impl<'de> Visitor<'de> for DurationVisitor { @@ -2071,6 +2082,7 @@ impl<'de> Deserialize<'de> for SystemTime { return Err(Error::invalid_length(1, &self)); } }; + try!(check_overflow(secs, nanos)); Ok(Duration::new(secs, nanos)) } @@ -2108,13 +2120,20 @@ impl<'de> Deserialize<'de> for SystemTime { Some(nanos) => nanos, None => return Err(<A::Error as Error>::missing_field("nanos_since_epoch")), }; + try!(check_overflow(secs, nanos)); Ok(Duration::new(secs, nanos)) } } const FIELDS: &'static [&'static str] = &["secs_since_epoch", "nanos_since_epoch"]; let duration = try!(deserializer.deserialize_struct("SystemTime", FIELDS, DurationVisitor)); - Ok(UNIX_EPOCH + duration) + #[cfg(systemtime_checked_add)] + let ret = UNIX_EPOCH + .checked_add(duration) + .ok_or_else(|| D::Error::custom("overflow deserializing SystemTime")); + #[cfg(not(systemtime_checked_add))] + let ret = Ok(UNIX_EPOCH + duration); + ret } } @@ -44,7 +44,7 @@ //! - [BSON], the data storage and network transfer format used by MongoDB. //! - [Avro], a binary format used within Apache Hadoop, with support for schema //! definition. -//! - [JSON5], A superset of JSON including some productions from ES5. +//! - [JSON5], a superset of JSON including some productions from ES5. //! - [Postcard], a no\_std and embedded-systems friendly compact binary format. //! - [URL] query strings, in the x-www-form-urlencoded format. //! - [Envy], a way to deserialize environment variables into Rust structs. @@ -84,7 +84,7 @@ //////////////////////////////////////////////////////////////////////////////// // Serde types in rustdoc of other crates get linked to here. -#![doc(html_root_url = "https://docs.rs/serde/1.0.123")] +#![doc(html_root_url = "https://docs.rs/serde/1.0.125")] // Support using Serde without the standard library! #![cfg_attr(not(feature = "std"), no_std)] // Unstable functionality only if the user asks for it. For tracking and @@ -120,6 +120,7 @@ zero_prefixed_literal, // correctly used enum_glob_use, + let_underscore_drop, map_err_ignore, result_unit_err, wildcard_imports, @@ -138,7 +139,6 @@ ) )] // Rustc lints. -#![forbid(unsafe_code)] #![deny(missing_docs, unused_imports)] //////////////////////////////////////////////////////////////////////////////// diff --git a/src/private/de.rs b/src/private/de.rs index 0c2f3b8..9199816 100644 --- a/src/private/de.rs +++ b/src/private/de.rs @@ -1287,8 +1287,9 @@ mod content { // } // // We want {"topic":"Info"} to deserialize even though - // ordinarily unit structs do not deserialize from empty map. + // ordinarily unit structs do not deserialize from empty map/seq. Content::Map(ref v) if v.is_empty() => visitor.visit_unit(), + Content::Seq(ref v) if v.is_empty() => visitor.visit_unit(), _ => self.deserialize_any(visitor), } } @@ -1741,6 +1742,25 @@ mod content { _ => Err(self.invalid_type(&visitor)), } } + + fn deserialize_float<V>(self, visitor: V) -> Result<V::Value, E> + where + V: Visitor<'de>, + { + match *self.content { + Content::F32(v) => visitor.visit_f32(v), + Content::F64(v) => visitor.visit_f64(v), + Content::U8(v) => visitor.visit_u8(v), + Content::U16(v) => visitor.visit_u16(v), + Content::U32(v) => visitor.visit_u32(v), + Content::U64(v) => visitor.visit_u64(v), + Content::I8(v) => visitor.visit_i8(v), + Content::I16(v) => visitor.visit_i16(v), + Content::I32(v) => visitor.visit_i32(v), + Content::I64(v) => visitor.visit_i64(v), + _ => Err(self.invalid_type(&visitor)), + } + } } fn visit_content_seq_ref<'a, 'de, V, E>( @@ -1888,25 +1908,14 @@ mod content { where V: Visitor<'de>, { - match *self.content { - Content::F32(v) => visitor.visit_f32(v), - Content::F64(v) => visitor.visit_f64(v), - Content::U64(v) => visitor.visit_u64(v), - Content::I64(v) => visitor.visit_i64(v), - _ => Err(self.invalid_type(&visitor)), - } + self.deserialize_float(visitor) } fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error> where V: Visitor<'de>, { - match *self.content { - Content::F64(v) => visitor.visit_f64(v), - Content::U64(v) => visitor.visit_u64(v), - Content::I64(v) => visitor.visit_i64(v), - _ => Err(self.invalid_type(&visitor)), - } + self.deserialize_float(visitor) } fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error> diff --git a/src/ser/impls.rs b/src/ser/impls.rs index 431a478..c254ac6 100644 --- a/src/ser/impls.rs +++ b/src/ser/impls.rs @@ -675,6 +675,52 @@ impl Serialize for net::IpAddr { } #[cfg(feature = "std")] +const DEC_DIGITS_LUT: &'static [u8] = b"\ + 0001020304050607080910111213141516171819\ + 2021222324252627282930313233343536373839\ + 4041424344454647484950515253545556575859\ + 6061626364656667686970717273747576777879\ + 8081828384858687888990919293949596979899"; + +#[cfg(feature = "std")] +#[inline] +fn format_u8(mut n: u8, out: &mut [u8]) -> usize { + if n >= 100 { + let d1 = ((n % 100) << 1) as usize; + n /= 100; + out[0] = b'0' + n; + out[1] = DEC_DIGITS_LUT[d1]; + out[2] = DEC_DIGITS_LUT[d1 + 1]; + 3 + } else if n >= 10 { + let d1 = (n << 1) as usize; + out[0] = DEC_DIGITS_LUT[d1]; + out[1] = DEC_DIGITS_LUT[d1 + 1]; + 2 + } else { + out[0] = b'0' + n; + 1 + } +} + +#[cfg(feature = "std")] +#[test] +fn test_format_u8() { + let mut i = 0u8; + + loop { + let mut buf = [0u8; 3]; + let written = format_u8(i, &mut buf); + assert_eq!(i.to_string().as_bytes(), &buf[..written]); + + match i.checked_add(1) { + Some(next) => i = next, + None => break, + } + } +} + +#[cfg(feature = "std")] impl Serialize for net::Ipv4Addr { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where @@ -683,7 +729,14 @@ impl Serialize for net::Ipv4Addr { if serializer.is_human_readable() { const MAX_LEN: usize = 15; debug_assert_eq!(MAX_LEN, "101.102.103.104".len()); - serialize_display_bounded_length!(self, MAX_LEN, serializer) + let mut buf = [b'.'; MAX_LEN]; + let mut written = format_u8(self.octets()[0], &mut buf); + for oct in &self.octets()[1..] { + // Skip over delimiters that we initialized buf with + written += format_u8(*oct, &mut buf[written + 1..]) + 1; + } + // We've only written ASCII bytes to the buffer, so it is valid UTF-8 + serializer.serialize_str(unsafe { str::from_utf8_unchecked(&buf[..written]) }) } else { self.octets().serialize(serializer) } |