Skip to content

Commit

Permalink
Merge pull request #2729 from dtolnay/saturating
Browse files Browse the repository at this point in the history
Integrate Saturating<T> deserialization into impl_deserialize_num macro
  • Loading branch information
dtolnay committed Apr 16, 2024
2 parents c13b3f7 + 01cd696 commit 65b7eea
Showing 1 changed file with 98 additions and 67 deletions.
165 changes: 98 additions & 67 deletions serde/src/de/impls.rs
Expand Up @@ -104,6 +104,28 @@ macro_rules! impl_deserialize_num {
deserializer.$deserialize(NonZeroVisitor)
}
}

#[cfg(not(no_core_num_saturating))]
impl<'de> Deserialize<'de> for Saturating<$primitive> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct SaturatingVisitor;

impl<'de> Visitor<'de> for SaturatingVisitor {
type Value = Saturating<$primitive>;

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("integer with support for saturating semantics")
}

$($($method!(saturating $primitive $val : $visit);)*)*
}

deserializer.$deserialize(SaturatingVisitor)
}
}
};

($primitive:ident, $deserialize:ident $($method:ident!($($val:ident : $visit:ident)*);)*) => {
Expand Down Expand Up @@ -154,6 +176,15 @@ macro_rules! num_self {
}
}
};

(saturating $primitive:ident $ty:ident : $visit:ident) => {
fn $visit<E>(self, v: $ty) -> Result<Self::Value, E>
where
E: Error,
{
Ok(Saturating(v))
}
};
}

macro_rules! num_as_self {
Expand All @@ -179,6 +210,15 @@ macro_rules! num_as_self {
}
}
};

(saturating $primitive:ident $ty:ident : $visit:ident) => {
fn $visit<E>(self, v: $ty) -> Result<Self::Value, E>
where
E: Error,
{
Ok(Saturating(v as $primitive))
}
};
}

macro_rules! num_as_copysign_self {
Expand Down Expand Up @@ -235,6 +275,21 @@ macro_rules! int_to_int {
Err(Error::invalid_value(Unexpected::Signed(v as i64), &self))
}
};

(saturating $primitive:ident $ty:ident : $visit:ident) => {
fn $visit<E>(self, v: $ty) -> Result<Self::Value, E>
where
E: Error,
{
if (v as i64) < $primitive::MIN as i64 {
Ok(Saturating($primitive::MIN))
} else if ($primitive::MAX as i64) < v as i64 {
Ok(Saturating($primitive::MAX))
} else {
Ok(Saturating(v as $primitive))
}
}
};
}

macro_rules! int_to_uint {
Expand Down Expand Up @@ -265,6 +320,21 @@ macro_rules! int_to_uint {
Err(Error::invalid_value(Unexpected::Signed(v as i64), &self))
}
};

(saturating $primitive:ident $ty:ident : $visit:ident) => {
fn $visit<E>(self, v: $ty) -> Result<Self::Value, E>
where
E: Error,
{
if v < 0 {
Ok(Saturating(0))
} else if ($primitive::MAX as u64) < v as u64 {
Ok(Saturating($primitive::MAX))
} else {
Ok(Saturating(v as $primitive))
}
}
};
}

macro_rules! uint_to_self {
Expand Down Expand Up @@ -295,6 +365,19 @@ macro_rules! uint_to_self {
Err(Error::invalid_value(Unexpected::Unsigned(v as u64), &self))
}
};

(saturating $primitive:ident $ty:ident : $visit:ident) => {
fn $visit<E>(self, v: $ty) -> Result<Self::Value, E>
where
E: Error,
{
if v as u64 <= $primitive::MAX as u64 {
Ok(Saturating(v as $primitive))
} else {
Ok(Saturating($primitive::MAX))
}
}
};
}

impl_deserialize_num! {
Expand Down Expand Up @@ -387,73 +470,6 @@ impl_deserialize_num! {
num_as_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32 u64:visit_u64);
}

#[cfg(not(no_core_num_saturating))]
macro_rules! visit_saturating {
($primitive:ident, $ty:ident : $visit:ident) => {
#[inline]
fn $visit<E>(self, v: $ty) -> Result<Saturating<$primitive>, E>
where
E: Error,
{
let out: $primitive = core::convert::TryFrom::<$ty>::try_from(v).unwrap_or_else(|_| {
#[allow(unused_comparisons)]
if v < 0 {
// never true for unsigned values
$primitive::MIN
} else {
$primitive::MAX
}
});
Ok(Saturating(out))
}
};
}

macro_rules! impl_deserialize_saturating_num {
($primitive:ident, $deserialize:ident) => {
#[cfg(not(no_core_num_saturating))]
impl<'de> Deserialize<'de> for Saturating<$primitive> {
#[inline]
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct SaturatingVisitor;

impl<'de> Visitor<'de> for SaturatingVisitor {
type Value = Saturating<$primitive>;

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("integer with support for saturating semantics")
}

visit_saturating!($primitive, u8:visit_u8);
visit_saturating!($primitive, u16:visit_u16);
visit_saturating!($primitive, u32:visit_u32);
visit_saturating!($primitive, u64:visit_u64);
visit_saturating!($primitive, i8:visit_i8);
visit_saturating!($primitive, i16:visit_i16);
visit_saturating!($primitive, i32:visit_i32);
visit_saturating!($primitive, i64:visit_i64);
}

deserializer.$deserialize(SaturatingVisitor)
}
}
};
}

impl_deserialize_saturating_num!(u8, deserialize_u8);
impl_deserialize_saturating_num!(u16, deserialize_u16);
impl_deserialize_saturating_num!(u32, deserialize_u32);
impl_deserialize_saturating_num!(u64, deserialize_u64);
impl_deserialize_saturating_num!(usize, deserialize_u64);
impl_deserialize_saturating_num!(i8, deserialize_i8);
impl_deserialize_saturating_num!(i16, deserialize_i16);
impl_deserialize_saturating_num!(i32, deserialize_i32);
impl_deserialize_saturating_num!(i64, deserialize_i64);
impl_deserialize_saturating_num!(isize, deserialize_i64);

macro_rules! num_128 {
($ty:ident : $visit:ident) => {
fn $visit<E>(self, v: $ty) -> Result<Self::Value, E>
Expand Down Expand Up @@ -494,6 +510,21 @@ macro_rules! num_128 {
}
}
};

(saturating $primitive:ident $ty:ident : $visit:ident) => {
fn $visit<E>(self, v: $ty) -> Result<Self::Value, E>
where
E: Error,
{
if (v as i128) < $primitive::MIN as i128 {
Ok(Saturating($primitive::MIN))
} else if ($primitive::MAX as u128) < v as u128 {
Ok(Saturating($primitive::MAX))
} else {
Ok(Saturating(v as $primitive))
}
}
};
}

impl_deserialize_num! {
Expand Down

0 comments on commit 65b7eea

Please sign in to comment.