@@ -33,7 +33,7 @@ use std::str::FromStr;
33
33
use bigint:: { BigInt , BigUint , Sign } ;
34
34
35
35
use integer:: Integer ;
36
- use traits:: { FromPrimitive , Float , PrimInt , Num , Signed , Zero , One , Bounded , NumCast } ;
36
+ use traits:: { FromPrimitive , Float , PrimInt , Num , Signed , Zero , One , Bounded , NumCast , CheckedAdd , CheckedSub , CheckedMul , CheckedDiv } ;
37
37
38
38
/// Represents the ratio between 2 numbers.
39
39
#[ derive( Copy , Clone , Debug ) ]
@@ -442,7 +442,7 @@ impl<'a, 'b, T> Div<&'b Ratio<T>> for &'a Ratio<T>
442
442
}
443
443
}
444
444
445
- // Abstracts the a/b `op` c/d = (a*d `op` b*d ) / (b*d) pattern
445
+ // Abstracts the a/b `op` c/d = (a*d `op` b*c ) / (b*d) pattern
446
446
macro_rules! arith_impl {
447
447
( impl $imp: ident, $method: ident) => {
448
448
forward_all_binop!( impl $imp, $method) ;
@@ -467,6 +467,62 @@ arith_impl!(impl Sub, sub);
467
467
// a/b % c/d = (a*d % b*c)/(b*d)
468
468
arith_impl ! ( impl Rem , rem) ;
469
469
470
+ // Like `std::try!` for Option<T>, unwrap the value or early-return None.
471
+ // Since Rust 1.22 this can be replaced by the `?` operator.
472
+ macro_rules! otry {
473
+ ( $expr: expr) => ( match $expr {
474
+ Some ( val) => val,
475
+ None => return None ,
476
+ } )
477
+ }
478
+
479
+ // a/b * c/d = (a*c)/(b*d)
480
+ impl < T > CheckedMul for Ratio < T >
481
+ where T : Clone + Integer + CheckedMul
482
+ {
483
+ #[ inline]
484
+ fn checked_mul ( & self , rhs : & Ratio < T > ) -> Option < Ratio < T > > {
485
+ Some ( Ratio :: new ( otry ! ( self . numer. checked_mul( & rhs. numer) ) ,
486
+ otry ! ( self . denom. checked_mul( & rhs. denom) ) ) )
487
+ }
488
+ }
489
+
490
+ // (a/b) / (c/d) = (a*d)/(b*c)
491
+ impl < T > CheckedDiv for Ratio < T >
492
+ where T : Clone + Integer + CheckedMul
493
+ {
494
+ #[ inline]
495
+ fn checked_div ( & self , rhs : & Ratio < T > ) -> Option < Ratio < T > > {
496
+ let bc = otry ! ( self . denom. checked_mul( & rhs. numer) ) ;
497
+ if bc. is_zero ( ) {
498
+ None
499
+ } else {
500
+ Some ( Ratio :: new ( otry ! ( self . numer. checked_mul( & rhs. denom) ) , bc) )
501
+ }
502
+ }
503
+ }
504
+
505
+ // As arith_impl! but for Checked{Add,Sub} traits
506
+ macro_rules! checked_arith_impl {
507
+ ( impl $imp: ident, $method: ident) => {
508
+ impl <T : Clone + Integer + CheckedMul + $imp> $imp for Ratio <T > {
509
+ #[ inline]
510
+ fn $method( & self , rhs: & Ratio <T >) -> Option <Ratio <T >> {
511
+ let ad = otry!( self . numer. checked_mul( & rhs. denom) ) ;
512
+ let bc = otry!( self . denom. checked_mul( & rhs. numer) ) ;
513
+ let bd = otry!( self . denom. checked_mul( & rhs. denom) ) ;
514
+ Some ( Ratio :: new( otry!( ad. $method( & bc) ) , bd) )
515
+ }
516
+ }
517
+ }
518
+ }
519
+
520
+ // a/b + c/d = (a*d + b*c)/(b*d)
521
+ checked_arith_impl ! ( impl CheckedAdd , checked_add) ;
522
+
523
+ // a/b - c/d = (a*d - b*c)/(b*d)
524
+ checked_arith_impl ! ( impl CheckedSub , checked_sub) ;
525
+
470
526
impl < T > Neg for Ratio < T >
471
527
where T : Clone + Integer + Neg < Output = T >
472
528
{
@@ -1102,12 +1158,15 @@ mod test {
1102
1158
mod arith {
1103
1159
use super :: { _0, _1, _2, _1_2, _3_2, _NEG1_2, to_big} ;
1104
1160
use super :: super :: { Ratio , Rational } ;
1161
+ use traits:: { CheckedAdd , CheckedSub , CheckedMul , CheckedDiv } ;
1105
1162
1106
1163
#[ test]
1107
1164
fn test_add ( ) {
1108
1165
fn test ( a : Rational , b : Rational , c : Rational ) {
1109
1166
assert_eq ! ( a + b, c) ;
1110
1167
assert_eq ! ( to_big( a) + to_big( b) , to_big( c) ) ;
1168
+ assert_eq ! ( a. checked_add( & b) , Some ( c) ) ;
1169
+ assert_eq ! ( to_big( a) . checked_add( & to_big( b) ) , Some ( to_big( c) ) ) ;
1111
1170
}
1112
1171
1113
1172
test ( _1, _1_2, _3_2) ;
@@ -1120,7 +1179,9 @@ mod test {
1120
1179
fn test_sub ( ) {
1121
1180
fn test ( a : Rational , b : Rational , c : Rational ) {
1122
1181
assert_eq ! ( a - b, c) ;
1123
- assert_eq ! ( to_big( a) - to_big( b) , to_big( c) )
1182
+ assert_eq ! ( to_big( a) - to_big( b) , to_big( c) ) ;
1183
+ assert_eq ! ( a. checked_sub( & b) , Some ( c) ) ;
1184
+ assert_eq ! ( to_big( a) . checked_sub( & to_big( b) ) , Some ( to_big( c) ) ) ;
1124
1185
}
1125
1186
1126
1187
test ( _1, _1_2, _1_2) ;
@@ -1132,7 +1193,9 @@ mod test {
1132
1193
fn test_mul ( ) {
1133
1194
fn test ( a : Rational , b : Rational , c : Rational ) {
1134
1195
assert_eq ! ( a * b, c) ;
1135
- assert_eq ! ( to_big( a) * to_big( b) , to_big( c) )
1196
+ assert_eq ! ( to_big( a) * to_big( b) , to_big( c) ) ;
1197
+ assert_eq ! ( a. checked_mul( & b) , Some ( c) ) ;
1198
+ assert_eq ! ( to_big( a) . checked_mul( & to_big( b) ) , Some ( to_big( c) ) ) ;
1136
1199
}
1137
1200
1138
1201
test ( _1, _1_2, _1_2) ;
@@ -1144,7 +1207,9 @@ mod test {
1144
1207
fn test_div ( ) {
1145
1208
fn test ( a : Rational , b : Rational , c : Rational ) {
1146
1209
assert_eq ! ( a / b, c) ;
1147
- assert_eq ! ( to_big( a) / to_big( b) , to_big( c) )
1210
+ assert_eq ! ( to_big( a) / to_big( b) , to_big( c) ) ;
1211
+ assert_eq ! ( a. checked_div( & b) , Some ( c) ) ;
1212
+ assert_eq ! ( to_big( a) . checked_div( & to_big( b) ) , Some ( to_big( c) ) ) ;
1148
1213
}
1149
1214
1150
1215
test ( _1, _1_2, _2) ;
@@ -1188,6 +1253,17 @@ mod test {
1188
1253
fn test_div_0 ( ) {
1189
1254
let _a = _1 / _0;
1190
1255
}
1256
+
1257
+ #[ test]
1258
+ fn test_checked_failures ( ) {
1259
+ let big = Ratio :: new ( 128u8 , 1 ) ;
1260
+ let small = Ratio :: new ( 1 , 128u8 ) ;
1261
+ assert_eq ! ( big. checked_add( & big) , None ) ;
1262
+ assert_eq ! ( small. checked_sub( & big) , None ) ;
1263
+ assert_eq ! ( big. checked_mul( & big) , None ) ;
1264
+ assert_eq ! ( small. checked_div( & big) , None ) ;
1265
+ assert_eq ! ( _1. checked_div( & _0) , None ) ;
1266
+ }
1191
1267
}
1192
1268
1193
1269
#[ test]
0 commit comments