Add Deserialize impl for std::ops::Range

Resolves #796
This commit is contained in:
Robert O'Callahan 2017-03-10 08:39:27 +13:00
parent aebe1fddab
commit cc0d045f5c
2 changed files with 156 additions and 0 deletions

View File

@ -46,6 +46,9 @@ use alloc::boxed::Box;
#[cfg(feature = "std")]
use std::time::Duration;
#[cfg(feature = "std")]
use std;
#[cfg(feature = "unstable")]
use core::nonzero::{NonZero, Zeroable};
@ -1108,6 +1111,137 @@ impl Deserialize for Duration {
}
}
///////////////////////////////////////////////////////////////////////////////
// Similar to:
//
// #[derive(Deserialize)]
// #[serde(deny_unknown_fields)]
// struct Range {
// start: u64,
// end: u32,
// }
#[cfg(feature = "std")]
impl<Idx: Deserialize> Deserialize for std::ops::Range<Idx> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer
{
enum Field {
Start,
End,
};
impl Deserialize for Field {
fn deserialize<D>(deserializer: D) -> Result<Field, D::Error>
where D: Deserializer
{
struct FieldVisitor;
impl Visitor for FieldVisitor {
type Value = Field;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("`start` or `end`")
}
fn visit_str<E>(self, value: &str) -> Result<Field, E>
where E: Error
{
match value {
"start" => Ok(Field::Start),
"end" => Ok(Field::End),
_ => Err(Error::unknown_field(value, FIELDS)),
}
}
fn visit_bytes<E>(self, value: &[u8]) -> Result<Field, E>
where E: Error
{
match value {
b"start" => Ok(Field::Start),
b"end" => Ok(Field::End),
_ => {
let value = String::from_utf8_lossy(value);
Err(Error::unknown_field(&value, FIELDS))
}
}
}
}
deserializer.deserialize_struct_field(FieldVisitor)
}
}
struct RangeVisitor<Idx> {
phantom: PhantomData<Idx>,
}
impl<Idx: Deserialize> Visitor for RangeVisitor<Idx> {
type Value = std::ops::Range<Idx>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct Range")
}
fn visit_seq<V>(self, mut visitor: V) -> Result<std::ops::Range<Idx>, V::Error>
where V: SeqVisitor
{
let start: Idx = match try!(visitor.visit()) {
Some(value) => value,
None => {
return Err(Error::invalid_length(0, &self));
}
};
let end: Idx = match try!(visitor.visit()) {
Some(value) => value,
None => {
return Err(Error::invalid_length(1, &self));
}
};
Ok(start..end)
}
fn visit_map<V>(self, mut visitor: V) -> Result<std::ops::Range<Idx>, V::Error>
where V: MapVisitor
{
let mut start: Option<Idx> = None;
let mut end: Option<Idx> = None;
while let Some(key) = try!(visitor.visit_key::<Field>()) {
match key {
Field::Start => {
if start.is_some() {
return Err(<V::Error as Error>::duplicate_field("start"));
}
start = Some(try!(visitor.visit_value()));
}
Field::End => {
if end.is_some() {
return Err(<V::Error as Error>::duplicate_field("end"));
}
end = Some(try!(visitor.visit_value()));
}
}
}
let start = match start {
Some(start) => start,
None => return Err(<V::Error as Error>::missing_field("start")),
};
let end = match end {
Some(end) => end,
None => return Err(<V::Error as Error>::missing_field("end")),
};
Ok(start..end)
}
}
const FIELDS: &'static [&'static str] = &["start", "end"];
deserializer.deserialize_struct("Range", FIELDS, RangeVisitor { phantom: PhantomData })
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "unstable")]

View File

@ -868,6 +868,28 @@ declare_tests! {
Token::SeqEnd,
],
}
test_range {
1u32..2u32 => &[
Token::StructStart("Range", 2),
Token::StructSep,
Token::Str("start"),
Token::U32(1),
Token::StructSep,
Token::Str("end"),
Token::U32(2),
Token::StructEnd,
],
1u32..2u32 => &[
Token::SeqStart(Some(2)),
Token::SeqSep,
Token::U64(1),
Token::SeqSep,
Token::U64(2),
Token::SeqEnd,
],
}
test_net_ipv4addr {
"1.2.3.4".parse::<net::Ipv4Addr>().unwrap() => &[Token::Str("1.2.3.4")],
}