@@ -9,10 +9,10 @@ use std::ops::{
9
9
use std:: str:: FromStr ;
10
10
11
11
use crate :: errors:: {
12
- CheckedMultiplyRatioError , ConversionOverflowError , DivideByZeroError , OverflowError ,
13
- OverflowOperation , StdError ,
12
+ CheckedMultiplyFractionError , CheckedMultiplyRatioError , ConversionOverflowError ,
13
+ DivideByZeroError , OverflowError , OverflowOperation , StdError ,
14
14
} ;
15
- use crate :: { Uint128 , Uint512 , Uint64 } ;
15
+ use crate :: { impl_mul_fraction , Fraction , Uint128 , Uint512 , Uint64 } ;
16
16
17
17
/// This module is purely a workaround that lets us ignore lints for all the code
18
18
/// the `construct_uint!` macro generates.
@@ -336,6 +336,8 @@ impl Uint256 {
336
336
}
337
337
}
338
338
339
+ impl_mul_fraction ! ( Uint256 ) ;
340
+
339
341
impl From < Uint128 > for Uint256 {
340
342
fn from ( val : Uint128 ) -> Self {
341
343
val. u128 ( ) . into ( )
@@ -666,7 +668,8 @@ impl PartialEq<Uint256> for &Uint256 {
666
668
#[ cfg( test) ]
667
669
mod tests {
668
670
use super :: * ;
669
- use crate :: { from_slice, to_vec} ;
671
+ use crate :: errors:: CheckedMultiplyFractionError :: { ConversionOverflow , DivideByZero } ;
672
+ use crate :: { from_slice, to_vec, Decimal , Decimal256 } ;
670
673
671
674
#[ test]
672
675
fn size_of_works ( ) {
@@ -1664,4 +1667,180 @@ mod tests {
1664
1667
assert_eq ! ( & lhs == & rhs, expected) ;
1665
1668
}
1666
1669
}
1670
+
1671
+ #[ test]
1672
+ fn mul_floored_works_with_zero ( ) {
1673
+ let fraction = ( Uint256 :: zero ( ) , Uint256 :: from ( 21u32 ) ) ;
1674
+ let res = Uint256 :: from ( 123456u32 ) . mul_floored ( fraction) ;
1675
+ assert_eq ! ( Uint256 :: zero( ) , res)
1676
+ }
1677
+
1678
+ #[ test]
1679
+ fn mul_floored_does_nothing_with_one ( ) {
1680
+ let fraction = ( Uint256 :: one ( ) , Uint256 :: one ( ) ) ;
1681
+ let res = Uint256 :: from ( 123456u32 ) . mul_floored ( fraction) ;
1682
+ assert_eq ! ( Uint256 :: from( 123456u32 ) , res)
1683
+ }
1684
+
1685
+ #[ test]
1686
+ fn mul_floored_rounds_down_with_normal_case ( ) {
1687
+ let fraction = ( Uint256 :: from ( 8u128 ) , Uint256 :: from ( 21u128 ) ) ;
1688
+ let res = Uint256 :: from ( 123456u32 ) . mul_floored ( fraction) ; // 47030.8571
1689
+ assert_eq ! ( Uint256 :: from( 47030u32 ) , res)
1690
+ }
1691
+
1692
+ #[ test]
1693
+ fn mul_floored_works_when_operation_temporarily_takes_above_max ( ) {
1694
+ let fraction = ( 8u128 , 21u128 ) ;
1695
+ let res = Uint256 :: MAX . mul_floored ( fraction) ; // 44_111_272_090_406_169_685_169_899_050_928_726_801_245_708_444_053_548_205_507_651_050_633_573_196_165.71428571
1696
+ assert_eq ! (
1697
+ Uint256 :: from_str(
1698
+ "44111272090406169685169899050928726801245708444053548205507651050633573196165"
1699
+ )
1700
+ . unwrap( ) ,
1701
+ res
1702
+ )
1703
+ }
1704
+
1705
+ #[ test]
1706
+ fn mul_floored_works_with_decimal ( ) {
1707
+ let decimal = Decimal :: from_ratio ( 8u128 , 21u128 ) ;
1708
+ let res = Uint256 :: from ( 123456u32 ) . mul_floored ( decimal) ; // 47030.8571
1709
+ assert_eq ! ( Uint256 :: from( 47030u32 ) , res)
1710
+ }
1711
+
1712
+ #[ test]
1713
+ fn mul_floored_works_with_decimal256 ( ) {
1714
+ let decimal = Decimal256 :: from_ratio ( 8u128 , 21u128 ) ;
1715
+ let res = Uint256 :: from ( 123456u32 ) . mul_floored ( decimal) ; // 47030.8571
1716
+ assert_eq ! ( Uint256 :: from( 47030u32 ) , res)
1717
+ }
1718
+
1719
+ #[ test]
1720
+ #[ should_panic( expected = "ConversionOverflowError" ) ]
1721
+ fn mul_floored_panics_on_overflow ( ) {
1722
+ let fraction = ( 21u128 , 8u128 ) ;
1723
+ Uint256 :: MAX . mul_floored ( fraction) ;
1724
+ }
1725
+
1726
+ #[ test]
1727
+ fn checked_mul_floored_does_not_panic_on_overflow ( ) {
1728
+ let fraction = ( 21u128 , 8u128 ) ;
1729
+ assert_eq ! (
1730
+ Uint256 :: MAX . checked_mul_floored( fraction) ,
1731
+ Err ( ConversionOverflow ( ConversionOverflowError {
1732
+ source_type: "Uint512" ,
1733
+ target_type: "Uint256" ,
1734
+ value:
1735
+ "303954234247955012986873835647805758114833709747306480603576158020771965304829"
1736
+ . to_string( )
1737
+ } ) ) ,
1738
+ ) ;
1739
+ }
1740
+
1741
+ #[ test]
1742
+ #[ should_panic( expected = "DivideByZeroError" ) ]
1743
+ fn mul_floored_panics_on_zero_div ( ) {
1744
+ let fraction = ( 21u128 , 0u128 ) ;
1745
+ Uint256 :: from ( 123456u32 ) . mul_floored ( fraction) ;
1746
+ }
1747
+
1748
+ #[ test]
1749
+ fn checked_mul_floored_does_not_panic_on_zero_div ( ) {
1750
+ let fraction = ( 21u128 , 0u128 ) ;
1751
+ assert_eq ! (
1752
+ Uint256 :: from( 123456u32 ) . checked_mul_floored( fraction) ,
1753
+ Err ( DivideByZero ( DivideByZeroError {
1754
+ operand: "2592576" . to_string( )
1755
+ } ) ) ,
1756
+ ) ;
1757
+ }
1758
+
1759
+ #[ test]
1760
+ fn mul_ceil_works_with_zero ( ) {
1761
+ let fraction = ( Uint256 :: zero ( ) , Uint256 :: from ( 21u32 ) ) ;
1762
+ let res = Uint256 :: from ( 123456u32 ) . mul_ceil ( fraction) ;
1763
+ assert_eq ! ( Uint256 :: zero( ) , res)
1764
+ }
1765
+
1766
+ #[ test]
1767
+ fn mul_ceil_does_nothing_with_one ( ) {
1768
+ let fraction = ( Uint256 :: one ( ) , Uint256 :: one ( ) ) ;
1769
+ let res = Uint256 :: from ( 123456u32 ) . mul_ceil ( fraction) ;
1770
+ assert_eq ! ( Uint256 :: from( 123456u32 ) , res)
1771
+ }
1772
+
1773
+ #[ test]
1774
+ fn mul_ceil_rounds_up_with_normal_case ( ) {
1775
+ let fraction = ( 8u128 , 21u128 ) ;
1776
+ let res = Uint256 :: from ( 123456u32 ) . mul_ceil ( fraction) ; // 47030.8571
1777
+ assert_eq ! ( Uint256 :: from( 47031u32 ) , res)
1778
+ }
1779
+
1780
+ #[ test]
1781
+ fn mul_ceil_works_when_operation_temporarily_takes_above_max ( ) {
1782
+ let fraction = ( 8u128 , 21u128 ) ;
1783
+ let res = Uint256 :: MAX . mul_ceil ( fraction) ; // 44_111_272_090_406_169_685_169_899_050_928_726_801_245_708_444_053_548_205_507_651_050_633_573_196_165.71428571
1784
+ assert_eq ! (
1785
+ Uint256 :: from_str(
1786
+ "44111272090406169685169899050928726801245708444053548205507651050633573196166"
1787
+ )
1788
+ . unwrap( ) ,
1789
+ res
1790
+ )
1791
+ }
1792
+
1793
+ #[ test]
1794
+ fn mul_ceil_works_with_decimal ( ) {
1795
+ let decimal = Decimal :: from_ratio ( 8u128 , 21u128 ) ;
1796
+ let res = Uint256 :: from ( 123456u32 ) . mul_ceil ( decimal) ; // 47030.8571
1797
+ assert_eq ! ( Uint256 :: from( 47031u32 ) , res)
1798
+ }
1799
+
1800
+ #[ test]
1801
+ fn mul_ceil_works_with_decimal256 ( ) {
1802
+ let decimal = Decimal256 :: from_ratio ( 8u128 , 21u128 ) ;
1803
+ let res = Uint256 :: from ( 123456u32 ) . mul_ceil ( decimal) ; // 47030.8571
1804
+ assert_eq ! ( Uint256 :: from( 47031u32 ) , res)
1805
+ }
1806
+
1807
+ #[ test]
1808
+ #[ should_panic( expected = "ConversionOverflowError" ) ]
1809
+ fn mul_ceil_panics_on_overflow ( ) {
1810
+ let fraction = ( 21u128 , 8u128 ) ;
1811
+ Uint256 :: MAX . mul_ceil ( fraction) ;
1812
+ }
1813
+
1814
+ #[ test]
1815
+ fn checked_mul_ceil_does_not_panic_on_overflow ( ) {
1816
+ let fraction = ( 21u128 , 8u128 ) ;
1817
+ assert_eq ! (
1818
+ Uint256 :: MAX . checked_mul_ceil( fraction) ,
1819
+ Err ( ConversionOverflow ( ConversionOverflowError {
1820
+ source_type: "Uint512" ,
1821
+ target_type: "Uint256" ,
1822
+ value:
1823
+ "303954234247955012986873835647805758114833709747306480603576158020771965304829" // raises prior to rounding up
1824
+ . to_string( )
1825
+ } ) ) ,
1826
+ ) ;
1827
+ }
1828
+
1829
+ #[ test]
1830
+ #[ should_panic( expected = "DivideByZeroError" ) ]
1831
+ fn mul_ceil_panics_on_zero_div ( ) {
1832
+ let fraction = ( 21u128 , 0u128 ) ;
1833
+ Uint256 :: from ( 123456u32 ) . mul_ceil ( fraction) ;
1834
+ }
1835
+
1836
+ #[ test]
1837
+ fn checked_mul_ceil_does_not_panic_on_zero_div ( ) {
1838
+ let fraction = ( 21u128 , 0u128 ) ;
1839
+ assert_eq ! (
1840
+ Uint256 :: from( 123456u32 ) . checked_mul_ceil( fraction) ,
1841
+ Err ( DivideByZero ( DivideByZeroError {
1842
+ operand: "2592576" . to_string( )
1843
+ } ) ) ,
1844
+ ) ;
1845
+ }
1667
1846
}
0 commit comments