satellite_math/
lib.rs

1use num::{CheckedAdd, CheckedDiv, CheckedMul, CheckedSub};
2
3use primitive_types::U256;
4use thiserror::Error;
5
6#[derive(Error, Debug, PartialEq)]
7pub enum MathError {
8    #[error("Addition overflowed")]
9    AdditionOverflow,
10    #[error("Subtraction overflowed")]
11    SubtractionOverflow,
12    #[error("Multiplication overflowed")]
13    MultiplicationOverflow,
14    #[error("Division overflowed")]
15    DivisionOverflow,
16    #[error("Failed to convert a math result from U256 back to its original type")]
17    ConversionError,
18}
19
20pub fn safe_add<T>(a: T, b: T) -> Result<T, MathError>
21where
22    T: CheckedAdd,
23{
24    a.checked_add(&b).ok_or(MathError::AdditionOverflow)
25}
26
27pub fn safe_sub<T>(a: T, b: T) -> Result<T, MathError>
28where
29    T: CheckedSub,
30{
31    a.checked_sub(&b).ok_or(MathError::SubtractionOverflow)
32}
33
34pub fn safe_mul<T>(a: T, b: T) -> Result<T, MathError>
35where
36    T: CheckedMul,
37{
38    a.checked_mul(&b).ok_or(MathError::MultiplicationOverflow)
39}
40
41pub fn safe_div<T>(a: T, b: T) -> Result<T, MathError>
42where
43    T: CheckedDiv,
44{
45    a.checked_div(&b).ok_or(MathError::DivisionOverflow)
46}
47
48pub fn mul_div<T>(mul_a: T, mul_b: T, div: T) -> Result<T, MathError>
49where
50    T: TryFrom<U256>,
51    U256: From<T>,
52{
53    let a = U256::from(mul_a);
54    let b = U256::from(mul_b);
55
56    let mul = a.checked_mul(b).ok_or(MathError::MultiplicationOverflow)?;
57    let div = U256::from(div);
58
59    let res = mul.checked_div(div).ok_or(MathError::DivisionOverflow)?;
60
61    res.try_into().map_err(|_| MathError::ConversionError)
62}