aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/de/impls.rs21
-rw-r--r--src/lib.rs6
-rw-r--r--src/private/de.rs37
-rw-r--r--src/ser/impls.rs55
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
}
}
diff --git a/src/lib.rs b/src/lib.rs
index 7de2ff6..5c07ece 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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)
}