levana_perpswap_cosmos/number/
nonzero.rs

1use std::{
2    fmt::{Display, Formatter},
3    str::FromStr,
4};
5
6use anyhow::Context;
7use cosmwasm_std::Decimal256;
8
9use crate::prelude::Signed;
10
11use super::types::{NonZero, UnsignedDecimal};
12
13impl<T: UnsignedDecimal> NonZero<T> {
14    /// Get the multiplicative inverse.
15    ///
16    /// Guaranteed not to fail, since all values here must be great than zero.
17    pub fn inverse(self) -> Self {
18        NonZero::new(T::from_decimal256(
19            Decimal256::one() / self.raw().into_decimal256(),
20        ))
21        .expect("NonZero::inverse failed but that should be impossible!")
22    }
23}
24
25impl<T: UnsignedDecimal> Display for NonZero<T> {
26    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
27        write!(f, "{}", self.raw())
28    }
29}
30
31impl<T: UnsignedDecimal> TryFrom<u128> for NonZero<T> {
32    type Error = anyhow::Error;
33
34    fn try_from(val: u128) -> Result<Self, Self::Error> {
35        Signed::<T>::from(val).try_into()
36    }
37}
38
39impl<T: UnsignedDecimal> TryFrom<u64> for NonZero<T> {
40    type Error = anyhow::Error;
41
42    fn try_from(val: u64) -> Result<Self, Self::Error> {
43        u128::from(val).try_into()
44    }
45}
46
47impl<T: UnsignedDecimal> TryFrom<&str> for NonZero<T> {
48    type Error = anyhow::Error;
49
50    fn try_from(value: &str) -> Result<Self, Self::Error> {
51        Self::from_str(value)
52    }
53}
54
55impl<T: UnsignedDecimal> FromStr for NonZero<T> {
56    type Err = anyhow::Error;
57
58    fn from_str(s: &str) -> Result<Self, Self::Err> {
59        Decimal256::from_str(s)
60            .ok()
61            .map(T::from_decimal256)
62            .and_then(NonZero::new)
63            .with_context(|| format!("Could not parse a non-zero value from: {s}"))
64    }
65}
66
67#[cfg(test)]
68mod tests {
69    use crate::prelude::{Number, NumberGtZero};
70
71    use quickcheck::quickcheck;
72
73    quickcheck! {
74        fn number_over_zero_roundtrip(num: u128) -> bool {
75            let number = (Number::from(num) + Number::ONE).unwrap();
76            let number_over_zero = NumberGtZero::try_from(number).unwrap();
77            let number2 = Number::from(number_over_zero);
78            assert_eq!(number, number2);
79            number == number2
80        }
81
82        fn negative_fails(num: u128) -> bool {
83            NumberGtZero::try_from(-Number::from(num)).unwrap_err();
84            true
85        }
86    }
87}