Skip to content

Commit

Permalink
Remove use of ops::Mul and ops::Neg since they can fail
Browse files Browse the repository at this point in the history
  • Loading branch information
jonasbb committed Dec 25, 2024
1 parent 4c273b2 commit 90d7312
Showing 1 changed file with 37 additions and 32 deletions.
69 changes: 37 additions & 32 deletions serde_with/src/utils/duration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,17 @@ impl Sign {
*self == Sign::Negative
}

pub(crate) fn apply<T>(&self, value: T) -> T
where
T: core::ops::Neg<Output = T>,
{
pub(crate) fn apply_f64(&self, value: f64) -> f64 {
match *self {
Sign::Positive => value,
Sign::Negative => value.neg(),
Sign::Negative => -value,
}
}

pub(crate) fn apply_i64(&self, value: i64) -> Option<i64> {
match *self {
Sign::Positive => Some(value),
Sign::Negative => value.checked_neg(),
}
}
}
Expand All @@ -53,6 +57,16 @@ impl DurationSigned {
}
}

pub(crate) fn checked_mul(mut self, rhs: u32) -> Option<Self> {
self.duration = self.duration.checked_mul(rhs)?;
Some(self)
}

pub(crate) fn checked_div(mut self, rhs: u32) -> Option<Self> {
self.duration = self.duration.checked_div(rhs)?;
Some(self)
}

#[cfg(any(feature = "chrono_0_4", feature = "time_0_3"))]
pub(crate) fn with_duration(sign: Sign, duration: Duration) -> Self {
Self { sign, duration }
Expand Down Expand Up @@ -107,24 +121,6 @@ impl From<&SystemTime> for DurationSigned {
}
}

impl core::ops::Mul<u32> for DurationSigned {
type Output = DurationSigned;

fn mul(mut self, rhs: u32) -> Self::Output {
self.duration *= rhs;
self
}
}

impl core::ops::Div<u32> for DurationSigned {
type Output = DurationSigned;

fn div(mut self, rhs: u32) -> Self::Output {
self.duration /= rhs;
self
}
}

impl<STRICTNESS> SerializeAs<DurationSigned> for DurationSeconds<u64, STRICTNESS>
where
STRICTNESS: Strictness,
Expand Down Expand Up @@ -163,11 +159,15 @@ where
{
let mut secs = source
.sign
.apply(i64::try_from(source.duration.as_secs()).map_err(|_| {
.apply_i64(i64::try_from(source.duration.as_secs()).map_err(|_| {
SerError::custom("The Duration of Timestamp is outside the supported range.")
})?);
})?)
.ok_or_else(|| {
S::Error::custom("The Duration of Timestamp is outside the supported range.")
})?;

// Properly round the value
// TODO check for overflows BUG771
if source.duration.subsec_millis() >= 500 {
if source.sign.is_positive() {
secs += 1;
Expand All @@ -189,7 +189,7 @@ where
{
// as conversions are necessary for floats
#[allow(clippy::as_conversions)]
let mut secs = source.sign.apply(source.duration.as_secs() as f64);
let mut secs = source.sign.apply_f64(source.duration.as_secs() as f64);

// Properly round the value
if source.duration.subsec_millis() >= 500 {
Expand All @@ -214,9 +214,12 @@ where
{
let mut secs = source
.sign
.apply(i64::try_from(source.duration.as_secs()).map_err(|_| {
.apply_i64(i64::try_from(source.duration.as_secs()).map_err(|_| {
SerError::custom("The Duration of Timestamp is outside the supported range.")
})?);
})?)
.ok_or_else(|| {
S::Error::custom("The Duration of Timestamp is outside the supported range.")
})?;

// Properly round the value
if source.duration.subsec_millis() >= 500 {
Expand All @@ -240,7 +243,7 @@ where
{
source
.sign
.apply(source.duration.as_secs_f64())
.apply_f64(source.duration.as_secs_f64())
.serialize(serializer)
}
}
Expand All @@ -256,7 +259,7 @@ where
{
source
.sign
.apply(source.duration.as_secs_f64())
.apply_f64(source.duration.as_secs_f64())
.to_string()
.serialize(serializer)
}
Expand All @@ -276,7 +279,8 @@ macro_rules! duration_impls {
where
S: Serializer,
{
$inner::<FORMAT, STRICTNESS>::serialize_as(&(*source * $factor), serializer)
let value = source.checked_mul($factor).ok_or_else(|| S::Error::custom("Failed to serialize value as the value cannot be represented."))?;
$inner::<FORMAT, STRICTNESS>::serialize_as(&value, serializer)
}
}

Expand All @@ -291,7 +295,8 @@ macro_rules! duration_impls {
D: Deserializer<'de>,
{
let dur = $inner::<FORMAT, STRICTNESS>::deserialize_as(deserializer)?;
Ok(dur / $factor)
let dur = dur.checked_div($factor).ok_or_else(|| D::Error::custom("Failed to deserialize value as the value cannot be represented."))?;
Ok(dur)
}
}

Expand Down

0 comments on commit 90d7312

Please sign in to comment.