@@ -9,10 +9,10 @@ use std::ops::{
99use std:: str:: FromStr ;
1010
1111use crate :: errors:: {
12- CheckedMultiplyRatioError , ConversionOverflowError , DivideByZeroError , OverflowError ,
13- OverflowOperation , StdError ,
12+ CheckedMultiplyFractionError , CheckedMultiplyRatioError , ConversionOverflowError ,
13+ DivideByZeroError , OverflowError , OverflowOperation , StdError ,
1414} ;
15- use crate :: { Uint128 , Uint512 , Uint64 } ;
15+ use crate :: { impl_mul_fraction , Fraction , Uint128 , Uint512 , Uint64 } ;
1616
1717/// This module is purely a workaround that lets us ignore lints for all the code
1818/// the `construct_uint!` macro generates.
@@ -336,6 +336,8 @@ impl Uint256 {
336336 }
337337}
338338
339+ impl_mul_fraction ! ( Uint256 ) ;
340+
339341impl From < Uint128 > for Uint256 {
340342 fn from ( val : Uint128 ) -> Self {
341343 val. u128 ( ) . into ( )
@@ -666,7 +668,8 @@ impl PartialEq<Uint256> for &Uint256 {
666668#[ cfg( test) ]
667669mod tests {
668670 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 } ;
670673
671674 #[ test]
672675 fn size_of_works ( ) {
@@ -1664,4 +1667,180 @@ mod tests {
16641667 assert_eq ! ( & lhs == & rhs, expected) ;
16651668 }
16661669 }
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+ }
16671846}
0 commit comments