carbotaniuman / auto_ops

Macros for overloading operators easily in Rust.
MIT License
34 stars 9 forks source link

Assignment operators aren't implemented for &mut T #9

Closed ollien closed 2 years ago

ollien commented 2 years ago

I wanted to add a += operator to a simple tuple struct, and attempted to do

struct BitCounts(u32, u32);

impl_op_ex!(+= |a: &mut BitCounts, b: &BitCounts| {
        a.0 += b.0;
        a.1 += b.1;
});

Looking at the expanded macro output, we can see the following implementations

impl ::std::ops::AddAssign<&BitCounts> for BitCounts {
    fn add_assign(&mut self, rhs: &BitCounts) {
        let mut lhs = self;
        {
            (|a: &mut BitCounts, b: &BitCounts| -> ()
                 { { a.0 += b.0; a.1 += b.1; } })(lhs, rhs);
        }
    }
}
impl ::std::ops::AddAssign<BitCounts> for BitCounts {
    fn add_assign(&mut self, rhs: BitCounts) {
        let mut lhs = self;
        {
            (|a: &mut BitCounts, b: &BitCounts| -> ()
                 { { a.0 += b.0; a.1 += b.1; } })(lhs, &rhs);
        }
    }
}

Which doesn't work if we want to perform += on a &mut BitCounts, we can't.

    let mut x = BitCounts(0, 0);
    let mut y = &mut x;
    y += BitCounts(1, 2);
error[E0368]: binary assignment operation `+=` cannot be applied to type `&mut BitCounts`
   --> src/main.rs:223:5
    |
223 |     y += BitCounts(1, 2);
    |     -^^^^^^^^^^^^^^^^^^^
    |     |
    |     cannot use `+=` on type `&mut BitCounts`
    |
    = note: an implementation of `std::ops::AddAssign` might be missing for `&mut BitCounts`

It would be really nice if all the necessary implementations were provided. I believe that for types T and U, the following would be necessary for addition (and obviously, replace AddAssign with the appropriate *Assign trait for other operations).

   AddAssign<U> for T
   AddAssign<&U> for T
   AddAssign<U> for &mut T
   AddAssign<&U> for &mut T

The following does work as a workaround (as a bit of an abuse of the way the macro rules are written), but is unclear.

impl_op_ex!(+= |a: &mut &mut BitCounts, b: &BitCounts| {
        a.0 += b.0;
        a.1 += b.1;
});
carbotaniuman commented 2 years ago

Fixed by #11. This is a breaking change as it adds a new trait implementation where there previously was one. This cannot currently be opted out of.