Impl Serialize for Bound<T>

This commit is contained in:
Dmitry Shlagoff 2019-01-29 15:20:27 +07:00
parent bb99b31eb0
commit 4bb45c8252
5 changed files with 148 additions and 1 deletions

View File

@ -2269,6 +2269,116 @@ mod range {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
impl<'de, T> Deserialize<'de> for Bound<T>
where
T: Deserialize<'de>
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
enum Field {
Unbounded,
Included,
Excluded,
}
impl<'de> Deserialize<'de> for Field {
#[inline]
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("`Unbounded`, `Included` or `Excluded`")
}
fn visit_u32<E>(self, value: u32) -> Result<Self::Value, E>
where
E: Error,
{
match value {
0 => Ok(Field::Unbounded),
1 => Ok(Field::Included),
2 => Ok(Field::Excluded),
_ => Err(Error::invalid_value(
Unexpected::Unsigned(value as u64),
&self,
)),
}
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: Error,
{
match value {
"Unbounded" => Ok(Field::Unbounded),
"Included" => Ok(Field::Included),
"Excluded" => Ok(Field::Excluded),
_ => Err(Error::unknown_variant(value, VARIANTS)),
}
}
fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
where
E: Error,
{
match value {
b"Unbounded" => Ok(Field::Unbounded),
b"Included" => Ok(Field::Included),
b"Excluded" => Ok(Field::Excluded),
_ => match str::from_utf8(value) {
Ok(value) => Err(Error::unknown_variant(value, VARIANTS)),
Err(_) => {
Err(Error::invalid_value(Unexpected::Bytes(value), &self))
}
},
}
}
}
deserializer.deserialize_identifier(FieldVisitor)
}
}
struct BoundVisitor<T>(PhantomData<Bound<T>>);
impl<'de, T> Visitor<'de> for BoundVisitor<T>
where
T: Deserialize<'de>,
{
type Value = Bound<T>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("enum Bound")
}
fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
where
A: EnumAccess<'de>,
{
match try!(data.variant()) {
(Field::Unbounded, v) => v.newtype_variant().map(|_: T| Bound::Unbounded),
(Field::Included, v) => v.newtype_variant().map(Bound::Included),
(Field::Excluded, v) => v.newtype_variant().map(Bound::Excluded),
}
}
}
const VARIANTS: &'static [&'static str] = &["Unbounded", "Included", "Excluded"];
deserializer.deserialize_enum("Bound", VARIANTS, BoundVisitor(PhantomData))
}
}
////////////////////////////////////////////////////////////////////////////////
macro_rules! nonzero_integers { macro_rules! nonzero_integers {
( $( $T: ident, )+ ) => { ( $( $T: ident, )+ ) => {
$( $(

View File

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

View File

@ -256,6 +256,24 @@ where
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
impl<T> Serialize for Bound<T>
where
T: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
Bound::Unbounded => serializer.serialize_unit_variant("Bound", 0, "Unbounded"),
Bound::Included(ref value) => serializer.serialize_newtype_variant("Bound", 1, "Included", value),
Bound::Excluded(ref value) => serializer.serialize_newtype_variant("Bound", 2, "Excluded", value),
}
}
}
////////////////////////////////////////////////////////////////////////////////
impl Serialize for () { impl Serialize for () {
#[inline] #[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>

View File

@ -10,6 +10,7 @@ use std::path::{Path, PathBuf};
use std::rc::{Rc, Weak as RcWeak}; use std::rc::{Rc, Weak as RcWeak};
use std::sync::{Arc, Weak as ArcWeak}; use std::sync::{Arc, Weak as ArcWeak};
use std::time::{Duration, UNIX_EPOCH}; use std::time::{Duration, UNIX_EPOCH};
use std::ops::Bound;
use fnv::FnvHasher; use fnv::FnvHasher;
use serde::{Deserialize, Deserializer}; use serde::{Deserialize, Deserializer};
@ -836,6 +837,23 @@ declare_tests! {
Token::SeqEnd, Token::SeqEnd,
], ],
} }
test_bound {
Bound::Unbounded::<()> => &[
Token::Enum { name: "Bound" },
Token::Str("Unbounded"),
Token::Unit,
],
Bound::Included(0) => &[
Token::Enum { name: "Bound" },
Token::Str("Included"),
Token::U8(0),
],
Bound::Excluded(0) => &[
Token::Enum { name: "Bound" },
Token::Str("Excluded"),
Token::U8(0),
],
}
test_path { test_path {
Path::new("/usr/local/lib") => &[ Path::new("/usr/local/lib") => &[
Token::BorrowedStr("/usr/local/lib"), Token::BorrowedStr("/usr/local/lib"),

View File

@ -10,6 +10,7 @@ use std::path::{Path, PathBuf};
use std::rc::{Rc, Weak as RcWeak}; use std::rc::{Rc, Weak as RcWeak};
use std::sync::{Arc, Weak as ArcWeak}; use std::sync::{Arc, Weak as ArcWeak};
use std::time::{Duration, UNIX_EPOCH}; use std::time::{Duration, UNIX_EPOCH};
use std::ops::Bound;
#[cfg(unix)] #[cfg(unix)]
use std::str; use std::str;