Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integrate Saturating<T> deserialization into impl_deserialize_num macro #2729

Merged
merged 1 commit into from Apr 16, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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