diff --git a/decimal_core/src/checked_ops.rs b/decimal_core/src/checked_ops.rs index 7af8f02..b884e33 100644 --- a/decimal_core/src/checked_ops.rs +++ b/decimal_core/src/checked_ops.rs @@ -24,6 +24,17 @@ pub fn generate_checked_ops(characteristics: DecimalCharacteristics) -> proc_mac .ok_or_else(|| "checked_sub: (self - rhs) subtraction underflow")? )) } + + fn checked_div(self, rhs: Self) -> std::result::Result { + Ok(Self::new( + self.get() + .checked_mul(Self::one()) + .ok_or_else(|| "checked_div: (self * Self::one()) multiplication overflow")? + .checked_div(rhs.get()) + .ok_or_else(|| "checked_div: ((self * Self::one()) / rhs) division by zero")? + ) + ) + } } #[cfg(test)] @@ -54,6 +65,23 @@ pub fn generate_checked_ops(characteristics: DecimalCharacteristics) -> proc_mac assert_eq!(a.checked_sub(b), Ok(#struct_name::new(24))); } + #[test] + fn test_checked_div() { + let a = #struct_name::new(2); + let b = #struct_name::new(#struct_name::one()); + + assert_eq!(a.checked_div(b), Ok(#struct_name::new(2))); + } + + #[test] + fn test_0_checked_div() { + let a = #struct_name::new(47); + let b = #struct_name::new(0); + let result = a.checked_div(b); + + assert!(result.is_err()); + } + #[test] fn test_underflow_checked_sub() { let min = #struct_name::new(0); diff --git a/src/traits.rs b/src/traits.rs index 55f1376..e3f1cff 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -40,7 +40,6 @@ pub trait Factories: Sized { fn from_scale_up(integer: T, scale: u8) -> Self; } - pub trait BetweenDecimals: Sized { fn from_decimal(other: T) -> Self; fn checked_from_decimal(other: T) -> std::result::Result; @@ -70,4 +69,5 @@ pub trait ByNumber: Sized { pub trait CheckedOps: Sized { fn checked_add(self, rhs: Self) -> std::result::Result; fn checked_sub(self, rhs: Self) -> std::result::Result; + fn checked_div(self, rhs: Self) -> std::result::Result; } diff --git a/src/walkthrough.rs b/src/walkthrough.rs index f6237b5..8773245 100644 --- a/src/walkthrough.rs +++ b/src/walkthrough.rs @@ -86,12 +86,19 @@ mod walkthrough { let result = percentage.checked_sub(Percentage::new(10)); assert_eq!(result, Ok(Percentage::new(90))); } + // checked_div + { + let result = Price::from_integer(99).checked_div(Price::from_scale(5, 1)); + assert_eq!(result, Ok(Price::from_integer(198))); + } // checked big div { let price = Price::max_instance().checked_big_div(Price::new(50000)); - assert_eq!(price, Ok(Price::new(68056473384187692692674921486353642291))); + assert_eq!( + price, + Ok(Price::new(68056473384187692692674921486353642291)) + ); } - // checked_from_scale { let overflow_err = @@ -109,7 +116,8 @@ mod walkthrough { } // checked_from_scale_to_value { - let result = Price::checked_from_scale_to_value(max_price_value, price_scale - 1).unwrap(); + let result = + Price::checked_from_scale_to_value(max_price_value, price_scale - 1).unwrap(); assert_eq!( result, U256::from_dec_str("3402823669209384634633746074317682114550").unwrap() @@ -125,7 +133,7 @@ mod walkthrough { } // checked_from_decimal_to_value { - let result = Price::checked_from_decimal_to_value(Price::max_instance()).unwrap(); + let result = Price::checked_from_decimal_to_value(Price::max_instance()).unwrap(); assert_eq!(result, U256::from(Price::max_value())); } // checked_big_div_by_number & checked_big_div_by_number_up