odra_core/
arithmetic.rs

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