Impl Ser/De for RangeFrom, RangeTo, RangeToInclusive

This commit is contained in:
Dmitry Shlagoff 2019-01-29 20:29:14 +07:00
parent 4bb45c8252
commit 0def7da5a8
5 changed files with 260 additions and 2 deletions

View File

@ -2138,6 +2138,72 @@ where
}
}
impl<'de, Idx> Deserialize<'de> for RangeFrom<Idx>
where
Idx: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let field = range::Field::Start;
let start = deserializer.deserialize_struct(
"RangeFrom",
field.name_slice(),
range::UnboundedRangeVisitor {
expecting: "struct RangeFrom",
phantom: PhantomData,
field,
},
)?;
Ok(start..)
}
}
impl<'de, Idx> Deserialize<'de> for RangeTo<Idx>
where
Idx: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let field = range::Field::End;
let end = deserializer.deserialize_struct(
"RangeTo",
field.name_slice(),
range::UnboundedRangeVisitor {
expecting: "struct RangeTo",
phantom: PhantomData,
field,
},
)?;
Ok(..end)
}
}
impl<'de, Idx> Deserialize<'de> for RangeToInclusive<Idx>
where
Idx: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let field = range::Field::End;
let end = deserializer.deserialize_struct(
"RangeToInclusive",
field.name_slice(),
range::UnboundedRangeVisitor {
expecting: "struct RangeToInclusive",
phantom: PhantomData,
field,
},
)?;
Ok(..=end)
}
}
mod range {
use lib::*;
@ -2149,11 +2215,31 @@ mod range {
//
// #[derive(Deserialize)]
// #[serde(field_identifier, rename_all = "lowercase")]
enum Field {
#[derive(PartialEq)]
pub enum Field {
Start,
End,
}
const FIELDS_START_ONLY: &'static [&'static str] = &["start"];
const FIELD_END_ONLY: &'static [&'static str] = &["end"];
impl Field {
fn name(&self) -> &'static str {
match self {
Field::Start => "start",
Field::End => "end",
}
}
pub fn name_slice(&self) -> &'static [&'static str] {
match self {
Field::Start => FIELDS_START_ONLY,
Field::End => FIELD_END_ONLY,
}
}
}
impl<'de> Deserialize<'de> for Field {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
@ -2265,6 +2351,62 @@ mod range {
Ok((start, end))
}
}
pub struct UnboundedRangeVisitor<Idx> {
pub expecting: &'static str,
pub phantom: PhantomData<Idx>,
pub field: Field,
}
impl<'de, Idx> Visitor<'de> for UnboundedRangeVisitor<Idx>
where
Idx: Deserialize<'de>,
{
type Value = Idx;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(self.expecting)
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let value: Idx = match try!(seq.next_element()) {
Some(value) => value,
None => {
return Err(Error::invalid_length(0, &self));
}
};
Ok(value)
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: MapAccess<'de>,
{
let mut value: Option<Idx> = None;
while let Some(key) = try!(map.next_key()) {
let key: Field = key;
match key {
ref key if *key == self.field => {
if value.is_some() {
return Err(<A::Error as Error>::duplicate_field(key.name()));
}
value = Some(try!(map.next_value()));
}
key => {
return Err(<A::Error as Error>::unknown_field(key.name(), self.field.name_slice()));
}
}
}
let value = match value {
Some(value) => value,
None => return Err(<A::Error as Error>::missing_field(self.field.name())),
};
Ok(value)
}
}
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -160,7 +160,7 @@ mod lib {
pub use self::core::default::{self, Default};
pub use self::core::fmt::{self, Debug, Display};
pub use self::core::marker::{self, PhantomData};
pub use self::core::ops::{Range, Bound};
pub use self::core::ops::{Range, Bound, RangeFrom, RangeTo, RangeToInclusive};
pub use self::core::option::{self, Option};
pub use self::core::result::{self, Result};

View File

@ -256,6 +256,57 @@ where
////////////////////////////////////////////////////////////////////////////////
impl<Idx> Serialize for RangeFrom<Idx>
where
Idx: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
use super::SerializeStruct;
let mut state = try!(serializer.serialize_struct("RangeFrom", 1));
try!(state.serialize_field("start", &self.start));
state.end()
}
}
////////////////////////////////////////////////////////////////////////////////
impl<Idx> Serialize for RangeTo<Idx>
where
Idx: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
use super::SerializeStruct;
let mut state = try!(serializer.serialize_struct("RangeTo", 1));
try!(state.serialize_field("end", &self.end));
state.end()
}
}
////////////////////////////////////////////////////////////////////////////////
impl<Idx> Serialize for RangeToInclusive<Idx>
where
Idx: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
use super::SerializeStruct;
let mut state = try!(serializer.serialize_struct("RangeToInclusive", 1));
try!(state.serialize_field("end", &self.end));
state.end()
}
}
////////////////////////////////////////////////////////////////////////////////
impl<T> Serialize for Bound<T>
where
T: Serialize,

View File

@ -837,6 +837,30 @@ declare_tests! {
Token::SeqEnd,
],
}
test_range_from {
0u8.. => &[
Token::Struct { name: "RangeFrom", len: 1 },
Token::Str("start"),
Token::U8(0),
Token::StructEnd,
],
}
test_range_to {
..2u8 => &[
Token::Struct { name: "RangeTo", len: 1 },
Token::Str("end"),
Token::U8(2),
Token::StructEnd,
],
}
test_range_to_inclusive {
..=2u8 => &[
Token::Struct { name: "RangeToInclusive", len: 1 },
Token::Str("end"),
Token::U8(2),
Token::StructEnd,
],
}
test_bound {
Bound::Unbounded::<()> => &[
Token::Enum { name: "Bound" },

View File

@ -376,6 +376,47 @@ declare_tests! {
Token::StructEnd,
],
}
test_range_from {
0u8.. => &[
Token::Struct { name: "RangeFrom", len: 1 },
Token::Str("start"),
Token::U8(0),
Token::StructEnd,
],
}
test_range_to {
..2u8 => &[
Token::Struct { name: "RangeTo", len: 1 },
Token::Str("end"),
Token::U8(2),
Token::StructEnd,
],
}
test_range_to_inclusive {
..=2u8 => &[
Token::Struct { name: "RangeToInclusive", len: 1 },
Token::Str("end"),
Token::U8(2),
Token::StructEnd,
],
}
test_bound {
Bound::Unbounded::<()> => &[
Token::Enum { name: "Bound" },
Token::Str("Unbounded"),
Token::Unit,
],
Bound::Included(0u8) => &[
Token::Enum { name: "Bound" },
Token::Str("Included"),
Token::U8(0),
],
Bound::Excluded(0u8) => &[
Token::Enum { name: "Bound" },
Token::Str("Excluded"),
Token::U8(0),
],
}
test_path {
Path::new("/usr/local/lib") => &[
Token::Str("/usr/local/lib"),