Skip to content

Commit

Permalink
Implement Serialize and Deserialize for RangeInclusive
Browse files Browse the repository at this point in the history
  • Loading branch information
c410-f3r committed Aug 5, 2018
1 parent 4e54aaf commit 8b2e6ba
Show file tree
Hide file tree
Showing 6 changed files with 187 additions and 0 deletions.
138 changes: 138 additions & 0 deletions serde/src/de/impls.rs
Expand Up @@ -2196,6 +2196,144 @@ where

////////////////////////////////////////////////////////////////////////////////

#[cfg(feature = "std")]
impl<'de, Idx> Deserialize<'de> for ops::RangeInclusive<Idx>
where
Idx: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
enum Field {
Start,
End,
};

impl<'de> Deserialize<'de> for Field {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct FieldVisitor;

impl<'de> Visitor<'de> 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<Self::Value, 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<Self::Value, 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_identifier(FieldVisitor)
}
}

struct RangeInclusiveVisitor<Idx> {
phantom: PhantomData<Idx>,
}

impl<'de, Idx> Visitor<'de> for RangeInclusiveVisitor<Idx>
where
Idx: Deserialize<'de>,
{
type Value = ops::RangeInclusive<Idx>;

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct RangeInclusive")
}

fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let start: Idx = match try!(seq.next_element()) {
Some(value) => value,
None => {
return Err(Error::invalid_length(0, &self));
}
};
let end: Idx = match try!(seq.next_element()) {
Some(value) => value,
None => {
return Err(Error::invalid_length(1, &self));
}
};
Ok(start..=end)
}

fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: MapAccess<'de>,
{
let mut start: Option<Idx> = None;
let mut end: Option<Idx> = None;
while let Some(key) = try!(map.next_key()) {
match key {
Field::Start => {
if start.is_some() {
return Err(<A::Error as Error>::duplicate_field("start"));
}
start = Some(try!(map.next_value()));
}
Field::End => {
if end.is_some() {
return Err(<A::Error as Error>::duplicate_field("end"));
}
end = Some(try!(map.next_value()));
}
}
}
let start = match start {
Some(start) => start,
None => return Err(<A::Error as Error>::missing_field("start")),
};
let end = match end {
Some(end) => end,
None => return Err(<A::Error as Error>::missing_field("end")),
};
Ok(start..=end)
}
}

const FIELDS: &'static [&'static str] = &["start", "end"];
deserializer.deserialize_struct(
"RangeInclusive",
FIELDS,
RangeInclusiveVisitor {
phantom: PhantomData,
},
)
}
}

////////////////////////////////////////////////////////////////////////////////

macro_rules! nonzero_integers {
( $( $T: ident, )+ ) => {
$(
Expand Down
1 change: 1 addition & 0 deletions serde/src/de/mod.rs
Expand Up @@ -97,6 +97,7 @@
//! - Path
//! - PathBuf
//! - Range\<T\>
//! - RangeInclusive\<T\>
//! - num::NonZero*
//! - `!` *(unstable)*
//! - **Net types**:
Expand Down
19 changes: 19 additions & 0 deletions serde/src/ser/impls.rs
Expand Up @@ -246,6 +246,25 @@ where

////////////////////////////////////////////////////////////////////////////////

#[cfg(feature = "std")]
impl<Idx> Serialize for ops::RangeInclusive<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("RangeInclusive", 2));
try!(state.serialize_field("start", &self.start()));
try!(state.serialize_field("end", &self.end()));
state.end()
}
}

////////////////////////////////////////////////////////////////////////////////

impl Serialize for () {
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
Expand Down
1 change: 1 addition & 0 deletions serde/src/ser/mod.rs
Expand Up @@ -92,6 +92,7 @@
//! - Path
//! - PathBuf
//! - Range\<T\>
//! - RangeInclusive\<T\>
//! - num::NonZero*
//! - `!` *(unstable)*
//! - **Net types**:
Expand Down
17 changes: 17 additions & 0 deletions test_suite/tests/test_de.rs
Expand Up @@ -811,6 +811,23 @@ declare_tests! {
Token::SeqEnd,
],
}
test_range_inclusive {
1u32..=2u32 => &[
Token::Struct { name: "RangeInclusive", len: 2 },
Token::Str("start"),
Token::U32(1),

Token::Str("end"),
Token::U32(2),
Token::StructEnd,
],
1u32..=2u32 => &[
Token::Seq { len: Some(2) },
Token::U64(1),
Token::U64(2),
Token::SeqEnd,
],
}
test_path {
Path::new("/usr/local/lib") => &[
Token::BorrowedStr("/usr/local/lib"),
Expand Down
11 changes: 11 additions & 0 deletions test_suite/tests/test_ser.rs
Expand Up @@ -377,6 +377,17 @@ declare_tests! {
Token::StructEnd,
],
}
test_range_inclusive {
1u32..=2u32 => &[
Token::Struct { name: "RangeInclusive", len: 2 },
Token::Str("start"),
Token::U32(1),

Token::Str("end"),
Token::U32(2),
Token::StructEnd,
],
}
test_path {
Path::new("/usr/local/lib") => &[
Token::Str("/usr/local/lib"),
Expand Down

0 comments on commit 8b2e6ba

Please sign in to comment.