odra_types/
arithmetic.rs

1//! Safe, overflowing addition and subtraction utilities.
2use casper_types::{U128, U256, U512};
3
4use crate::ExecutionError;
5
6/// Overflowing addition, returning the result of addition or [ArithmeticsError::AdditionOverflow].
7pub trait OverflowingAdd: Sized {
8    /// Overflowing addition. Compute `self + rhs`, returns the result or error if overflowed.
9    fn overflowing_add(self, rhs: Self) -> Result<Self, ExecutionError>;
10}
11
12/// Overflowing subtraction, returning the result of addition or [ArithmeticsError::SubtractingOverflow].
13pub trait OverflowingSub: Sized {
14    /// Overflowing subtraction. Compute `self - rhs`, returns the result or error if overflowed.
15    fn overflowing_sub(self, rhs: Self) -> Result<Self, ExecutionError>;
16}
17
18/// Computation result error.
19#[cfg_attr(debug_assertions, derive(Debug, PartialEq, Eq))]
20pub enum ArithmeticsError {
21    // Addition result exceeds the max value.
22    AdditionOverflow,
23    // Subtraction result is lower than the min value.
24    SubtractingOverflow
25}
26
27/// Implements [OverflowingAdd] and [OverflowingSub] for all the given types.
28#[macro_export]
29macro_rules! impl_overflowing_add_sub {
30    ( $( $ty:ty ),+ ) => {
31        $(
32            impl OverflowingAdd for $ty {
33                fn overflowing_add(self, rhs: Self) -> Result<Self, ExecutionError> {
34                    let (res, is_overflowed)  = self.overflowing_add(rhs);
35                    match is_overflowed {
36                        true => Err(ArithmeticsError::AdditionOverflow.into()),
37                        false => Ok(res)
38                    }
39                }
40            }
41
42            impl OverflowingSub for $ty {
43                fn overflowing_sub(self, rhs: Self) -> Result<Self, ExecutionError> {
44                    let (res, is_overflowed)  = self.overflowing_sub(rhs);
45                    match is_overflowed {
46                        true => Err(ArithmeticsError::SubtractingOverflow.into()),
47                        false => Ok(res)
48                    }
49                }
50            }
51        )+
52    };
53}
54
55impl_overflowing_add_sub!(u8, u16, u32, u64, i8, i16, i32, i64, U128, U256, U512);
56
57#[cfg(test)]
58mod test {
59    use crate::arithmetic::{ArithmeticsError, OverflowingSub};
60
61    use super::OverflowingAdd;
62
63    #[test]
64    fn test_add() {
65        assert_eq!(<u8 as OverflowingAdd>::overflowing_add(2u8, 1u8), Ok(3u8));
66        assert_eq!(
67            <u8 as OverflowingAdd>::overflowing_add(u8::MAX, 1u8),
68            Err(ArithmeticsError::AdditionOverflow.into())
69        );
70    }
71
72    #[test]
73    fn test_sub() {
74        assert_eq!(<u8 as OverflowingSub>::overflowing_sub(2u8, 1u8), Ok(1u8));
75        assert_eq!(
76            <u8 as OverflowingSub>::overflowing_sub(u8::MIN, 1u8),
77            Err(ArithmeticsError::SubtractingOverflow.into())
78        );
79    }
80}