Skip to content

Commit

Permalink
Merge pull request #1678 from CosmWasm/chipshort/issue1609
Browse files Browse the repository at this point in the history
Add #[must_use] to applicable math operations
  • Loading branch information
chipshort authored May 2, 2023
2 parents 3651064 + fbba7f6 commit 1915d0e
Show file tree
Hide file tree
Showing 9 changed files with 137 additions and 33 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ and this project adheres to

- cosmwasm-std: Implement `PartialEq` for `Addr == &Addr` and `&Addr == Addr` as
well as `Event == &Event` and `&Event == Event` ([#1672]).
- cosmwasm-std: Add `#[must_use]` annotations to `Uint64`, `Uint128`, `Uint256`,
`Uint512`, `Decimal` and `Decimal256` math operations ([#1678])

[#1672]: https://github.com/CosmWasm/cosmwasm/pull/1672
[#1678]: https://github.com/CosmWasm/cosmwasm/pull/1678

### Deprecated

Expand Down
17 changes: 16 additions & 1 deletion packages/std/src/math/decimal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ impl Decimal {
}
}

#[must_use]
pub const fn is_zero(&self) -> bool {
self.0.is_zero()
}
Expand All @@ -180,6 +181,7 @@ impl Decimal {
/// assert_eq!(b.decimal_places(), 18);
/// assert_eq!(b.atomics(), Uint128::new(1));
/// ```
#[must_use]
#[inline]
pub const fn atomics(&self) -> Uint128 {
self.0
Expand All @@ -189,17 +191,20 @@ impl Decimal {
/// but this could potentially change as the type evolves.
///
/// See also [`Decimal::atomics()`].
#[must_use]
#[inline]
pub const fn decimal_places(&self) -> u32 {
Self::DECIMAL_PLACES
}

/// Rounds value down after decimal places.
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn floor(&self) -> Self {
Self((self.0 / Self::DECIMAL_FRACTIONAL) * Self::DECIMAL_FRACTIONAL)
}

/// Rounds value up after decimal places. Panics on overflow.
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn ceil(&self) -> Self {
match self.checked_ceil() {
Ok(value) => value,
Expand Down Expand Up @@ -248,6 +253,7 @@ impl Decimal {
}

/// Raises a value to the power of `exp`, panics if an overflow occurred.
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn pow(self, exp: u32) -> Self {
match self.checked_pow(exp) {
Ok(value) => value,
Expand Down Expand Up @@ -302,6 +308,7 @@ impl Decimal {
/// Returns the approximate square root as a Decimal.
///
/// This should not overflow or panic.
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn sqrt(&self) -> Self {
// Algorithm described in https://hackmd.io/@webmaster128/SJThlukj_
// We start with the highest precision possible and lower it until
Expand All @@ -321,6 +328,7 @@ impl Decimal {
/// Precision *must* be a number between 0 and 9 (inclusive).
///
/// Returns `None` if the internal multiplication overflows.
#[must_use = "this returns the result of the operation, without modifying the original"]
fn sqrt_with_precision(&self, precision: u32) -> Option<Self> {
let inner_mul = 100u128.pow(precision);
self.0.checked_mul(inner_mul.into()).ok().map(|inner| {
Expand All @@ -329,31 +337,36 @@ impl Decimal {
})
}

#[must_use = "this returns the result of the operation, without modifying the original"]
pub const fn abs_diff(self, other: Self) -> Self {
Self(self.0.abs_diff(other.0))
}

#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn saturating_add(self, other: Self) -> Self {
match self.checked_add(other) {
Ok(value) => value,
Err(_) => Self::MAX,
}
}

#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn saturating_sub(self, other: Self) -> Self {
match self.checked_sub(other) {
Ok(value) => value,
Err(_) => Self::zero(),
}
}

#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn saturating_mul(self, other: Self) -> Self {
match self.checked_mul(other) {
Ok(value) => value,
Err(_) => Self::MAX,
}
}

#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn saturating_pow(self, exp: u32) -> Self {
match self.checked_pow(exp) {
Ok(value) => value,
Expand All @@ -379,6 +392,7 @@ impl Decimal {
/// let d = Decimal::from_str("75.0").unwrap();
/// assert_eq!(d.to_uint_floor(), Uint128::new(75));
/// ```
#[must_use]
pub fn to_uint_floor(self) -> Uint128 {
self.0 / Self::DECIMAL_FRACTIONAL
}
Expand All @@ -401,6 +415,7 @@ impl Decimal {
/// let d = Decimal::from_str("75.0").unwrap();
/// assert_eq!(d.to_uint_ceil(), Uint128::new(75));
/// ```
#[must_use]
pub fn to_uint_ceil(self) -> Uint128 {
// Using `q = 1 + ((x - 1) / y); // if x != 0` with unsigned integers x, y, q
// from https://stackoverflow.com/a/2745086/2013738. We know `x + y` CAN overflow.
Expand Down Expand Up @@ -1976,7 +1991,7 @@ mod tests {
#[test]
#[should_panic]
fn decimal_pow_overflow_panics() {
Decimal::MAX.pow(2u32);
_ = Decimal::MAX.pow(2u32);
}

#[test]
Expand Down
17 changes: 16 additions & 1 deletion packages/std/src/math/decimal256.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ impl Decimal256 {
}
}

#[must_use]
pub const fn is_zero(&self) -> bool {
self.0.is_zero()
}
Expand All @@ -192,6 +193,7 @@ impl Decimal256 {
/// assert_eq!(b.decimal_places(), 18);
/// assert_eq!(b.atomics(), Uint256::from(1u128));
/// ```
#[must_use]
#[inline]
pub const fn atomics(&self) -> Uint256 {
self.0
Expand All @@ -201,17 +203,20 @@ impl Decimal256 {
/// but this could potentially change as the type evolves.
///
/// See also [`Decimal256::atomics()`].
#[must_use]
#[inline]
pub const fn decimal_places(&self) -> u32 {
Self::DECIMAL_PLACES
}

/// Rounds value down after decimal places.
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn floor(&self) -> Self {
Self((self.0 / Self::DECIMAL_FRACTIONAL) * Self::DECIMAL_FRACTIONAL)
}

/// Rounds value up after decimal places. Panics on overflow.
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn ceil(&self) -> Self {
match self.checked_ceil() {
Ok(value) => value,
Expand Down Expand Up @@ -260,6 +265,7 @@ impl Decimal256 {
}

/// Raises a value to the power of `exp`, panics if an overflow occurred.
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn pow(self, exp: u32) -> Self {
match self.checked_pow(exp) {
Ok(value) => value,
Expand Down Expand Up @@ -314,6 +320,7 @@ impl Decimal256 {
/// Returns the approximate square root as a Decimal256.
///
/// This should not overflow or panic.
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn sqrt(&self) -> Self {
// Algorithm described in https://hackmd.io/@webmaster128/SJThlukj_
// We start with the highest precision possible and lower it until
Expand All @@ -333,6 +340,7 @@ impl Decimal256 {
/// Precision *must* be a number between 0 and 9 (inclusive).
///
/// Returns `None` if the internal multiplication overflows.
#[must_use = "this returns the result of the operation, without modifying the original"]
fn sqrt_with_precision(&self, precision: u32) -> Option<Self> {
let inner_mul = Uint256::from(100u128).pow(precision);
self.0.checked_mul(inner_mul).ok().map(|inner| {
Expand All @@ -341,6 +349,7 @@ impl Decimal256 {
})
}

#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn abs_diff(self, other: Self) -> Self {
if self < other {
other - self
Expand All @@ -349,27 +358,31 @@ impl Decimal256 {
}
}

#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn saturating_add(self, other: Self) -> Self {
match self.checked_add(other) {
Ok(value) => value,
Err(_) => Self::MAX,
}
}

#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn saturating_sub(self, other: Self) -> Self {
match self.checked_sub(other) {
Ok(value) => value,
Err(_) => Self::zero(),
}
}

#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn saturating_mul(self, other: Self) -> Self {
match self.checked_mul(other) {
Ok(value) => value,
Err(_) => Self::MAX,
}
}

#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn saturating_pow(self, exp: u32) -> Self {
match self.checked_pow(exp) {
Ok(value) => value,
Expand All @@ -395,6 +408,7 @@ impl Decimal256 {
/// let d = Decimal256::from_str("75.0").unwrap();
/// assert_eq!(d.to_uint_floor(), Uint256::from(75u64));
/// ```
#[must_use]
pub fn to_uint_floor(self) -> Uint256 {
self.0 / Self::DECIMAL_FRACTIONAL
}
Expand All @@ -417,6 +431,7 @@ impl Decimal256 {
/// let d = Decimal256::from_str("75.0").unwrap();
/// assert_eq!(d.to_uint_ceil(), Uint256::from(75u64));
/// ```
#[must_use]
pub fn to_uint_ceil(self) -> Uint256 {
// Using `q = 1 + ((x - 1) / y); // if x != 0` with unsigned integers x, y, q
// from https://stackoverflow.com/a/2745086/2013738. We know `x + y` CAN overflow.
Expand Down Expand Up @@ -2125,7 +2140,7 @@ mod tests {
#[test]
#[should_panic]
fn decimal256_pow_overflow_panics() {
Decimal256::MAX.pow(2u32);
_ = Decimal256::MAX.pow(2u32);
}

#[test]
Expand Down
5 changes: 5 additions & 0 deletions packages/std/src/math/fraction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub trait Fraction<T>: Sized {
/// Returns the multiplicative inverse `q/p` for fraction `p/q`.
///
/// If `p` is zero, None is returned.
#[must_use = "this returns the result of the operation, without modifying the original"]
fn inv(&self) -> Option<Self>;
}

Expand Down Expand Up @@ -58,6 +59,7 @@ macro_rules! impl_mul_fraction {
}

/// Same operation as `checked_mul_floor` except unwrapped
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn mul_floor<F: Fraction<T>, T: Into<$Uint>>(self, rhs: F) -> Self {
self.checked_mul_floor(rhs).unwrap()
}
Expand Down Expand Up @@ -89,6 +91,7 @@ macro_rules! impl_mul_fraction {
}

/// Same operation as `checked_mul_ceil` except unwrapped
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn mul_ceil<F: Fraction<T>, T: Into<$Uint>>(self, rhs: F) -> Self {
self.checked_mul_ceil(rhs).unwrap()
}
Expand Down Expand Up @@ -119,6 +122,7 @@ macro_rules! impl_mul_fraction {
}

/// Same operation as `checked_div_floor` except unwrapped
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn div_floor<F: Fraction<T>, T: Into<$Uint>>(self, rhs: F) -> Self
where
Self: Sized,
Expand Down Expand Up @@ -156,6 +160,7 @@ macro_rules! impl_mul_fraction {
}

/// Same operation as `checked_div_ceil` except unwrapped
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn div_ceil<F: Fraction<T>, T: Into<$Uint>>(self, rhs: F) -> Self
where
Self: Sized,
Expand Down
1 change: 1 addition & 0 deletions packages/std/src/math/isqrt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::{Uint128, Uint256, Uint512, Uint64};
/// [integer square root](https://en.wikipedia.org/wiki/Integer_square_root).
pub trait Isqrt {
/// The [integer square root](https://en.wikipedia.org/wiki/Integer_square_root).
#[must_use = "this returns the result of the operation, without modifying the original"]
fn isqrt(self) -> Self;
}

Expand Down
Loading

0 comments on commit 1915d0e

Please sign in to comment.