levana_perpswap_cosmos/number/
ops.rs1use super::{Number, Signed, UnsignedDecimal};
2use anyhow::{anyhow, Result};
3use std::{
4 cmp::Ordering,
5 ops::{Add, Div, Mul, Sub},
6};
7
8impl<T: UnsignedDecimal> Signed<T> {
19 pub fn checked_add(self, rhs: Self) -> Result<Self> {
21 Ok(match (self.is_negative(), rhs.is_negative()) {
22 (false, false) => Self::new_positive(self.value().checked_add(rhs.value())?),
23 (true, true) => Self::new_negative(self.value().checked_add(rhs.value())?),
24 (false, true) => {
25 if self.value() >= rhs.value() {
26 Self::new_positive(self.value().checked_sub(rhs.value())?)
27 } else {
28 Self::new_negative(rhs.value().checked_sub(self.value())?)
29 }
30 }
31 (true, false) => {
32 if self.value() >= rhs.value() {
33 Self::new_negative(self.value().checked_sub(rhs.value())?)
34 } else {
35 Self::new_positive(rhs.value().checked_sub(self.value())?)
36 }
37 }
38 })
39 }
40
41 pub fn checked_sub(self, rhs: Self) -> Result<Self> {
43 self.checked_add(-rhs)
44 }
45}
46
47impl Number {
48 pub fn checked_mul(self, rhs: Self) -> Result<Self> {
50 match self.value().checked_mul(rhs.value()).ok() {
51 None => Err(anyhow!(
52 "Overflow while multiplying {} and {}",
53 self.value(),
54 rhs.value()
55 )),
56 Some(value) => Ok(if self.is_negative() == rhs.is_negative() {
57 Signed::new_positive(value)
58 } else {
59 Signed::new_negative(value)
60 }),
61 }
62 }
63
64 pub fn checked_div(self, rhs: Self) -> Result<Self> {
66 if rhs.is_zero() {
67 Err(anyhow!("Cannot divide with zero"))
68 } else {
69 match self.value().checked_div(rhs.value()).ok() {
70 None => Err(anyhow!(
71 "Overflow while dividing {} by {}",
72 self.value(),
73 rhs.value()
74 )),
75 Some(value) => Ok(if self.is_negative() == rhs.is_negative() {
76 Signed::new_positive(value)
77 } else {
78 Signed::new_negative(value)
79 }),
80 }
81 }
82 }
83
84 pub fn approx_eq(self, other: Number) -> Result<bool> {
86 Ok((self - other)?.abs() < Self::EPS_E7)
87 }
88
89 pub fn approx_eq_eps(self, other: Number, eps: Number) -> Result<bool> {
91 Ok((self - other)?.abs() < eps)
92 }
93
94 pub fn approx_lt_relaxed(self, other: Number) -> Result<bool> {
96 Ok(self < (other + Self::EPS_E7)?)
97 }
98
99 pub fn approx_gt_relaxed(self, other: Number) -> Result<bool> {
101 Ok(self > (other - Self::EPS_E7)?)
102 }
103
104 pub fn approx_gt_strict(self, other: Number) -> Result<bool> {
106 Ok(self > (other + Self::EPS_E7)?)
107 }
108}
109
110impl Mul for Number {
111 type Output = anyhow::Result<Self>;
112
113 fn mul(self, rhs: Self) -> Self::Output {
114 self.checked_mul(rhs)
115 }
116}
117
118impl Mul<u64> for Number {
119 type Output = anyhow::Result<Self>;
120
121 fn mul(self, rhs: u64) -> Self::Output {
122 self.checked_mul(rhs.into())
123 }
124}
125
126impl Div<u64> for Number {
127 type Output = anyhow::Result<Self>;
128
129 fn div(self, rhs: u64) -> Self::Output {
130 self.checked_div(rhs.into())
131 }
132}
133
134impl Div for Number {
135 type Output = anyhow::Result<Self>;
136
137 fn div(self, rhs: Self) -> Self::Output {
138 self.checked_div(rhs)
139 }
140}
141
142impl<T: UnsignedDecimal> Add for Signed<T> {
143 type Output = anyhow::Result<Self>;
144
145 fn add(self, rhs: Self) -> Self::Output {
146 self.checked_add(rhs)
147 }
148}
149
150impl<T: UnsignedDecimal> Sub for Signed<T> {
151 type Output = anyhow::Result<Self>;
152
153 fn sub(self, rhs: Self) -> Self::Output {
154 self.checked_sub(rhs)
155 }
156}
157
158impl<T: UnsignedDecimal> std::cmp::PartialOrd for Signed<T> {
159 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
160 Some(self.cmp(other))
161 }
162}
163
164impl<T: UnsignedDecimal> std::cmp::Ord for Signed<T> {
165 fn cmp(&self, other: &Self) -> Ordering {
166 match (self.is_positive_or_zero(), other.is_positive_or_zero()) {
167 (true, true) => self.value().cmp(&other.value()),
168 (false, false) => other.value().cmp(&self.value()),
169 (true, false) => Ordering::Greater,
170 (false, true) => Ordering::Less,
171 }
172 }
173}