Merge pull request #2729 from dtolnay/saturating

Integrate Saturating<T> deserialization into impl_deserialize_num macro
This commit is contained in:
David Tolnay 2024-04-16 14:17:19 -07:00 committed by GitHub
commit 65b7eea775
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -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)*);)*) => {
@ -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 {
@ -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 {
@ -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 {
@ -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 {
@ -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! {
@ -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>
@ -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! {