Serialize and Deserialize for std::time::Duration

This commit is contained in:
David Tolnay 2016-08-03 17:15:14 -07:00
parent b289edd4a4
commit c4b5a42615
No known key found for this signature in database
GPG Key ID: F9BA143B95FF6D82
4 changed files with 185 additions and 0 deletions

View File

@ -53,6 +53,9 @@ use alloc::arc::Arc;
#[cfg(all(feature = "unstable", feature = "alloc", not(feature = "std")))]
use alloc::boxed::Box;
#[cfg(feature = "std")]
use std::time::Duration;
#[cfg(feature = "unstable")]
use core::nonzero::{NonZero, Zeroable};
@ -982,6 +985,135 @@ impl<'a, T: ?Sized> Deserialize for Cow<'a, T> where T: ToOwned, T::Owned: Deser
///////////////////////////////////////////////////////////////////////////////
// This is a cleaned-up version of the impl generated by:
//
// #[derive(Deserialize)]
// #[serde(deny_unknown_fields)]
// struct Duration {
// secs: u64,
// nanos: u32,
// }
#[cfg(feature = "std")]
impl Deserialize for Duration {
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
where D: Deserializer,
{
enum Field { Secs, Nanos };
impl Deserialize for Field {
fn deserialize<D>(deserializer: &mut D) -> Result<Field, D::Error>
where D: Deserializer,
{
struct FieldVisitor;
impl Visitor for FieldVisitor {
type Value = Field;
fn visit_usize<E>(&mut self, value: usize) -> Result<Field, E>
where E: Error,
{
match value {
0usize => Ok(Field::Secs),
1usize => Ok(Field::Nanos),
_ => Err(Error::invalid_value("expected a field")),
}
}
fn visit_str<E>(&mut self, value: &str) -> Result<Field, E>
where E: Error,
{
match value {
"secs" => Ok(Field::Secs),
"nanos" => Ok(Field::Nanos),
_ => Err(Error::unknown_field(value)),
}
}
fn visit_bytes<E>(&mut self, value: &[u8]) -> Result<Field, E>
where E: Error,
{
match value {
b"secs" => Ok(Field::Secs),
b"nanos" => Ok(Field::Nanos),
_ => {
let value = String::from_utf8_lossy(value);
Err(Error::unknown_field(&value))
}
}
}
}
deserializer.deserialize_struct_field(FieldVisitor)
}
}
struct DurationVisitor;
impl Visitor for DurationVisitor {
type Value = Duration;
fn visit_seq<V>(&mut self, mut visitor: V) -> Result<Duration, V::Error>
where V: SeqVisitor,
{
let secs: u64 = match try!(visitor.visit()) {
Some(value) => value,
None => {
try!(visitor.end());
return Err(Error::invalid_length(0));
}
};
let nanos: u32 = match try!(visitor.visit()) {
Some(value) => value,
None => {
try!(visitor.end());
return Err(Error::invalid_length(1));
}
};
try!(visitor.end());
Ok(Duration::new(secs, nanos))
}
fn visit_map<V>(&mut self, mut visitor: V) -> Result<Duration, V::Error>
where V: MapVisitor,
{
let mut secs: Option<u64> = None;
let mut nanos: Option<u32> = None;
while let Some(key) = try!(visitor.visit_key::<Field>()) {
match key {
Field::Secs => {
if secs.is_some() {
return Err(<V::Error as Error>::duplicate_field("secs"));
}
secs = Some(try!(visitor.visit_value()));
}
Field::Nanos => {
if nanos.is_some() {
return Err(<V::Error as Error>::duplicate_field("nanos"));
}
nanos = Some(try!(visitor.visit_value()));
}
}
}
try!(visitor.end());
let secs = match secs {
Some(secs) => secs,
None => try!(visitor.missing_field("secs")),
};
let nanos = match nanos {
Some(nanos) => nanos,
None => try!(visitor.missing_field("nanos")),
};
Ok(Duration::new(secs, nanos))
}
}
const FIELDS: &'static [&'static str] = &["secs", "nanos"];
deserializer.deserialize_struct("Duration", FIELDS, DurationVisitor)
}
}
///////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "unstable")]
impl<T> Deserialize for NonZero<T> where T: Deserialize + PartialEq + Zeroable + Zero {
fn deserialize<D>(deserializer: &mut D) -> Result<NonZero<T>, D::Error> where D: Deserializer {

View File

@ -50,6 +50,8 @@ use std::path;
use std::rc::Rc;
#[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::rc::Rc;
#[cfg(feature = "std")]
use std::time::Duration;
#[cfg(feature = "std")]
use std::sync::Arc;
@ -624,6 +626,20 @@ impl<T, E> Serialize for Result<T, E> where T: Serialize, E: Serialize {
///////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "std")]
impl Serialize for Duration {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer,
{
let mut state = try!(serializer.serialize_struct("Duration", 2));
try!(serializer.serialize_struct_elt(&mut state, "secs", self.as_secs()));
try!(serializer.serialize_struct_elt(&mut state, "nanos", self.subsec_nanos()));
serializer.serialize_struct_end(state)
}
}
///////////////////////////////////////////////////////////////////////////////
#[cfg(all(feature = "std", feature = "unstable"))]
impl Serialize for net::IpAddr {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>

View File

@ -1,6 +1,7 @@
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::net;
use std::path::PathBuf;
use std::time::Duration;
use serde::Deserialize;
@ -745,6 +746,28 @@ declare_tests! {
Token::SeqEnd,
],
}
test_duration {
Duration::new(1, 2) => &[
Token::StructStart("Duration", 2),
Token::StructSep,
Token::Str("secs"),
Token::U64(1),
Token::StructSep,
Token::Str("nanos"),
Token::U32(2),
Token::StructEnd,
],
Duration::new(1, 2) => &[
Token::SeqStart(Some(2)),
Token::SeqSep,
Token::I64(1),
Token::SeqSep,
Token::I64(2),
Token::SeqEnd,
],
}
test_net_ipv4addr {
"1.2.3.4".parse::<net::Ipv4Addr>().unwrap() => &[Token::Str("1.2.3.4")],
}

View File

@ -2,6 +2,7 @@ use std::collections::{BTreeMap, HashMap, HashSet};
use std::net;
use std::path::{Path, PathBuf};
use std::str;
use std::time::Duration;
extern crate serde_test;
use self::serde_test::{
@ -324,6 +325,19 @@ declare_ser_tests! {
Token::SeqEnd,
],
}
test_duration {
Duration::new(1, 2) => &[
Token::StructStart("Duration", 2),
Token::StructSep,
Token::Str("secs"),
Token::U64(1),
Token::StructSep,
Token::Str("nanos"),
Token::U32(2),
Token::StructEnd,
],
}
test_net_ipv4addr {
"1.2.3.4".parse::<net::Ipv4Addr>().unwrap() => &[Token::Str("1.2.3.4")],
}