Skip to content

Commit f1091aa

Browse files
committed
Implement OpAssign for Ratio
1 parent 7a5b207 commit f1091aa

File tree

1 file changed

+203
-8
lines changed

1 file changed

+203
-8
lines changed

src/lib.rs

Lines changed: 203 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,11 @@ impl<T: Clone + Integer> Ratio<T> {
110110

111111
// FIXME(#5992): assignment operator overloads
112112
// self.numer /= g;
113+
// T: Clone + Integer != T: Clone + NumAssign
113114
self.numer = self.numer.clone() / g.clone();
114115
// FIXME(#5992): assignment operator overloads
115116
// self.denom /= g;
117+
// T: Clone + Integer != T: Clone + NumAssign
116118
self.denom = self.denom.clone() / g;
117119

118120
// keep denom positive!
@@ -265,7 +267,6 @@ impl<T> From<T> for Ratio<T> where T: Clone + Integer {
265267
}
266268
}
267269

268-
269270
// From pair (through the `new` constructor)
270271
impl<T> From<(T, T)> for Ratio<T> where T: Clone + Integer {
271272
fn from(pair: (T, T)) -> Ratio<T> {
@@ -362,6 +363,114 @@ impl<T: Clone + Integer + Hash> Hash for Ratio<T> {
362363
}
363364
}
364365

366+
mod opassign {
367+
use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign};
368+
369+
use Ratio;
370+
use integer::Integer;
371+
use traits::NumAssign;
372+
373+
impl<T: Clone + Integer + NumAssign> AddAssign for Ratio<T> {
374+
fn add_assign(&mut self, other: Ratio<T>) {
375+
self.numer = (self.numer.clone() * other.denom.clone()).add(self.denom.clone() * other.numer);
376+
self.denom *= other.denom;
377+
self.reduce();
378+
}
379+
}
380+
381+
impl<T: Clone + Integer + NumAssign> DivAssign for Ratio<T> {
382+
fn div_assign(&mut self, other: Ratio<T>) {
383+
self.numer *= other.denom;
384+
self.denom *= other.numer;
385+
self.reduce();
386+
}
387+
}
388+
389+
impl<T: Clone + Integer + NumAssign> MulAssign for Ratio<T> {
390+
fn mul_assign(&mut self, other: Ratio<T>) {
391+
self.numer *= other.numer;
392+
self.denom *= other.denom;
393+
self.reduce();
394+
}
395+
}
396+
397+
impl<T: Clone + Integer + NumAssign> RemAssign for Ratio<T> {
398+
fn rem_assign(&mut self, other: Ratio<T>) {
399+
self.numer = (self.numer.clone() * other.denom.clone()).rem(self.denom.clone() * other.numer);
400+
self.denom *= other.denom;
401+
self.reduce();
402+
}
403+
}
404+
405+
impl<T: Clone + Integer + NumAssign> SubAssign for Ratio<T> {
406+
fn sub_assign(&mut self, other: Ratio<T>) {
407+
self.numer = (self.numer.clone() * other.denom.clone()).sub(self.denom.clone() * other.numer);
408+
self.denom *= other.denom;
409+
self.reduce();
410+
}
411+
}
412+
413+
// a/b + c/1 = (a*1 + b*c) / (b*1) = (a + b*c) / b
414+
impl<T: Clone + Integer + NumAssign> AddAssign<T> for Ratio<T> {
415+
fn add_assign(&mut self, other: T) {
416+
self.numer += self.denom.clone() * other;
417+
self.reduce();
418+
}
419+
}
420+
421+
impl<T: Clone + Integer + NumAssign> DivAssign<T> for Ratio<T> {
422+
fn div_assign(&mut self, other: T) {
423+
self.denom *= other;
424+
self.reduce();
425+
}
426+
}
427+
428+
impl<T: Clone + Integer + NumAssign> MulAssign<T> for Ratio<T> {
429+
fn mul_assign(&mut self, other: T) {
430+
self.numer *= other;
431+
self.reduce();
432+
}
433+
}
434+
435+
// a/b % c/1 = (a*1 % b*c) / (b*1) = (a % b*c) / b
436+
impl<T: Clone + Integer + NumAssign> RemAssign<T> for Ratio<T> {
437+
fn rem_assign(&mut self, other: T) {
438+
self.numer %= self.denom.clone() * other;
439+
self.reduce();
440+
}
441+
}
442+
443+
// a/b - c/1 = (a*1 - b*c) / (b*1) = (a - b*c) / b
444+
impl<T: Clone + Integer + NumAssign> SubAssign<T> for Ratio<T> {
445+
fn sub_assign(&mut self, other: T) {
446+
self.numer -= self.denom.clone() * other;
447+
self.reduce();
448+
}
449+
}
450+
451+
macro_rules! forward_op_assign {
452+
(impl $imp:ident, $method:ident) => {
453+
impl<'a, T: Clone + Integer + NumAssign> $imp<&'a Ratio<T>> for Ratio<T> {
454+
#[inline]
455+
fn $method(&mut self, other: &Ratio<T>) {
456+
self.$method(other.clone())
457+
}
458+
}
459+
impl<'a, T: Clone + Integer + NumAssign> $imp<&'a T> for Ratio<T> {
460+
#[inline]
461+
fn $method(&mut self, other: &T) {
462+
self.$method(other.clone())
463+
}
464+
}
465+
}
466+
}
467+
468+
forward_op_assign!(impl AddAssign, add_assign);
469+
forward_op_assign!(impl DivAssign, div_assign);
470+
forward_op_assign!(impl MulAssign, mul_assign);
471+
forward_op_assign!(impl RemAssign, rem_assign);
472+
forward_op_assign!(impl SubAssign, sub_assign);
473+
}
365474

366475
macro_rules! forward_val_val_binop {
367476
(impl $imp:ident, $method:ident) => {
@@ -373,6 +482,14 @@ macro_rules! forward_val_val_binop {
373482
(&self).$method(&other)
374483
}
375484
}
485+
impl<T: Clone + Integer> $imp<T> for Ratio<T> {
486+
type Output = Ratio<T>;
487+
488+
#[inline]
489+
fn $method(self, other: T) -> Ratio<T> {
490+
(&self).$method(&other)
491+
}
492+
}
376493
}
377494
}
378495

@@ -388,6 +505,16 @@ macro_rules! forward_ref_val_binop {
388505
self.$method(&other)
389506
}
390507
}
508+
impl<'a, T> $imp<T> for &'a Ratio<T> where
509+
T: Clone + Integer
510+
{
511+
type Output = Ratio<T>;
512+
513+
#[inline]
514+
fn $method(self, other: T) -> Ratio<T> {
515+
self.$method(&other)
516+
}
517+
}
391518
}
392519
}
393520

@@ -403,6 +530,16 @@ macro_rules! forward_val_ref_binop {
403530
(&self).$method(other)
404531
}
405532
}
533+
impl<'a, T> $imp<&'a T> for Ratio<T> where
534+
T: Clone + Integer
535+
{
536+
type Output = Ratio<T>;
537+
538+
#[inline]
539+
fn $method(self, other: &T) -> Ratio<T> {
540+
(&self).$method(other)
541+
}
542+
}
406543
}
407544
}
408545

@@ -427,9 +564,20 @@ impl<'a, 'b, T> Mul<&'b Ratio<T>> for &'a Ratio<T>
427564
self.denom.clone() * rhs.denom.clone())
428565
}
429566
}
567+
// a/b * c/1 = (a*c) / (b*1) = (a*c) / b
568+
impl<'a, 'b, T> Mul<&'b T> for &'a Ratio<T>
569+
where T: Clone + Integer
570+
{
571+
type Output = Ratio<T>;
572+
#[inline]
573+
fn mul(self, rhs: &T) -> Ratio<T> {
574+
Ratio::new(self.numer.clone() * rhs.clone(),
575+
self.denom.clone())
576+
}
577+
}
430578

431579
forward_all_binop!(impl Div, div);
432-
// (a/b) / (c/d) = (a*d)/(b*c)
580+
// (a/b) / (c/d) = (a*d) / (b*c)
433581
impl<'a, 'b, T> Div<&'b Ratio<T>> for &'a Ratio<T>
434582
where T: Clone + Integer
435583
{
@@ -441,11 +589,23 @@ impl<'a, 'b, T> Div<&'b Ratio<T>> for &'a Ratio<T>
441589
self.denom.clone() * rhs.numer.clone())
442590
}
443591
}
592+
// (a/b) / (c/1) = (a*1) / (b*c) = a / (b*c)
593+
impl<'a, 'b, T> Div<&'b T> for &'a Ratio<T>
594+
where T: Clone + Integer
595+
{
596+
type Output = Ratio<T>;
597+
598+
#[inline]
599+
fn div(self, rhs: &T) -> Ratio<T> {
600+
Ratio::new(self.numer.clone(),
601+
self.denom.clone() * rhs.clone())
602+
}
603+
}
444604

445-
// Abstracts the a/b `op` c/d = (a*d `op` b*c) / (b*d) pattern
446605
macro_rules! arith_impl {
447606
(impl $imp:ident, $method:ident) => {
448607
forward_all_binop!(impl $imp, $method);
608+
// Abstracts the a/b `op` c/d = (a*d `op` b*c) / (b*d) pattern
449609
impl<'a, 'b, T: Clone + Integer>
450610
$imp<&'b Ratio<T>> for &'a Ratio<T> {
451611
type Output = Ratio<T>;
@@ -455,16 +615,21 @@ macro_rules! arith_impl {
455615
self.denom.clone() * rhs.denom.clone())
456616
}
457617
}
618+
// Abstracts the a/b `op` c/1 = (a*1 `op` b*c) / (b*1) = (a `op` b*c) / b pattern
619+
impl<'a, 'b, T: Clone + Integer>
620+
$imp<&'b T> for &'a Ratio<T> {
621+
type Output = Ratio<T>;
622+
#[inline]
623+
fn $method(self, rhs: &'b T) -> Ratio<T> {
624+
Ratio::new(self.numer.clone().$method(self.denom.clone() * rhs.clone()),
625+
self.denom.clone())
626+
}
627+
}
458628
}
459629
}
460630

461-
// a/b + c/d = (a*d + b*c)/(b*d)
462631
arith_impl!(impl Add, add);
463-
464-
// a/b - c/d = (a*d - b*c)/(b*d)
465632
arith_impl!(impl Sub, sub);
466-
467-
// a/b % c/d = (a*d % b*c)/(b*d)
468633
arith_impl!(impl Rem, rem);
469634

470635
// Like `std::try!` for Option<T>, unwrap the value or early-return None.
@@ -1164,69 +1329,99 @@ mod test {
11641329
fn test_add() {
11651330
fn test(a: Rational, b: Rational, c: Rational) {
11661331
assert_eq!(a + b, c);
1332+
assert_eq!({ let mut x = a; x += b; x}, c);
11671333
assert_eq!(to_big(a) + to_big(b), to_big(c));
11681334
assert_eq!(a.checked_add(&b), Some(c));
11691335
assert_eq!(to_big(a).checked_add(&to_big(b)), Some(to_big(c)));
11701336
}
1337+
fn test_assign(a: Rational, b: isize, c: Rational) {
1338+
assert_eq!(a + b, c);
1339+
assert_eq!({ let mut x = a; x += b; x}, c);
1340+
}
11711341

11721342
test(_1, _1_2, _3_2);
11731343
test(_1, _1, _2);
11741344
test(_1_2, _3_2, _2);
11751345
test(_1_2, _NEG1_2, _0);
1346+
test_assign(_1_2, 1, _3_2);
11761347
}
11771348

11781349
#[test]
11791350
fn test_sub() {
11801351
fn test(a: Rational, b: Rational, c: Rational) {
11811352
assert_eq!(a - b, c);
1353+
assert_eq!({ let mut x = a; x -= b; x}, c);
11821354
assert_eq!(to_big(a) - to_big(b), to_big(c));
11831355
assert_eq!(a.checked_sub(&b), Some(c));
11841356
assert_eq!(to_big(a).checked_sub(&to_big(b)), Some(to_big(c)));
11851357
}
1358+
fn test_assign(a: Rational, b: isize, c: Rational) {
1359+
assert_eq!(a - b, c);
1360+
assert_eq!({ let mut x = a; x -= b; x}, c);
1361+
}
11861362

11871363
test(_1, _1_2, _1_2);
11881364
test(_3_2, _1_2, _1);
11891365
test(_1, _NEG1_2, _3_2);
1366+
test_assign(_1_2, 1, _NEG1_2);
11901367
}
11911368

11921369
#[test]
11931370
fn test_mul() {
11941371
fn test(a: Rational, b: Rational, c: Rational) {
11951372
assert_eq!(a * b, c);
1373+
assert_eq!({ let mut x = a; x *= b; x}, c);
11961374
assert_eq!(to_big(a) * to_big(b), to_big(c));
11971375
assert_eq!(a.checked_mul(&b), Some(c));
11981376
assert_eq!(to_big(a).checked_mul(&to_big(b)), Some(to_big(c)));
11991377
}
1378+
fn test_assign(a: Rational, b: isize, c: Rational) {
1379+
assert_eq!(a * b, c);
1380+
assert_eq!({ let mut x = a; x *= b; x}, c);
1381+
}
12001382

12011383
test(_1, _1_2, _1_2);
12021384
test(_1_2, _3_2, Ratio::new(3, 4));
12031385
test(_1_2, _NEG1_2, Ratio::new(-1, 4));
1386+
test_assign(_1_2, 2, _1);
12041387
}
12051388

12061389
#[test]
12071390
fn test_div() {
12081391
fn test(a: Rational, b: Rational, c: Rational) {
12091392
assert_eq!(a / b, c);
1393+
assert_eq!({ let mut x = a; x /= b; x}, c);
12101394
assert_eq!(to_big(a) / to_big(b), to_big(c));
12111395
assert_eq!(a.checked_div(&b), Some(c));
12121396
assert_eq!(to_big(a).checked_div(&to_big(b)), Some(to_big(c)));
12131397
}
1398+
fn test_assign(a: Rational, b: isize, c: Rational) {
1399+
assert_eq!(a / b, c);
1400+
assert_eq!({ let mut x = a; x /= b; x}, c);
1401+
}
12141402

12151403
test(_1, _1_2, _2);
12161404
test(_3_2, _1_2, _1 + _2);
12171405
test(_1, _NEG1_2, _NEG1_2 + _NEG1_2 + _NEG1_2 + _NEG1_2);
1406+
test_assign(_1, 2, _1_2);
12181407
}
12191408

12201409
#[test]
12211410
fn test_rem() {
12221411
fn test(a: Rational, b: Rational, c: Rational) {
12231412
assert_eq!(a % b, c);
1413+
assert_eq!({ let mut x = a; x %= b; x}, c);
12241414
assert_eq!(to_big(a) % to_big(b), to_big(c))
12251415
}
1416+
fn test_assign(a: Rational, b: isize, c: Rational) {
1417+
assert_eq!(a % b, c);
1418+
assert_eq!({ let mut x = a; x %= b; x}, c);
1419+
}
12261420

12271421
test(_3_2, _1, _1_2);
12281422
test(_2, _NEG1_2, _0);
12291423
test(_1_2, _2, _1_2);
1424+
test_assign(_3_2, 1, _1_2);
12301425
}
12311426

12321427
#[test]

0 commit comments

Comments
 (0)