rust-lang / libs-team

The home of the library team
Apache License 2.0
110 stars 18 forks source link

ACP: `impl {Div,Rem}Assign<NonZeroX> for X` #346

Closed JarvisCraft closed 4 months ago

JarvisCraft commented 4 months ago

Proposal

Problem statement

At the moment, there are impl {Div,Rem}<NonZeroX> for X which use the fact that the division by a non-zero value are always infallible.

Yet there seem to be no corresponding {Div,Rem}Assign implementations. While the lhs %= rhs and lhs/= rhs can be described in user code with lhs = lhs / rhs and lhs = lhs % rhs respectively, there seems to be no reason to not implement the corresponding traits on numeric types themselves.

Motivating examples or use cases

Simply,

let mut b = 123u8;
let a = NonZeroU8::new(1).unwrap();
b = b / a;

compiles; but

let mut b = 123u8;
let a = NonZeroU8::new(1).unwrap();
b /= a;

does not.

Solution sketch

The implementation (tested against master) adds the following into core::num::nonzero::nonzero_integer_signedness_dependent_impls:

        #[stable(feature = "nonzero_div2", since = "CURRENT_RUSTC_VERSION")]
        impl DivAssign<$Ty> for $Int {
            /// This operation rounds towards zero,
            /// truncating any fractional part of the exact result, and cannot panic.
            #[inline]
            fn div_assign(&mut self, other: $Ty) {
                *self = *self / other;
            }
        }

        #[stable(feature = "nonzero_div2", since = "CURRENT_RUSTC_VERSION")]
        impl RemAssign<$Ty> for $Int {
            /// This operation satisfies `n % d == n - (n / d) * d`, and cannot panic.
            #[inline]
            fn rem_assign(&mut self, other: $Ty) {
                *self = *self % other;
            }
        }
Diff ```diff diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 9e34c0d240d..61257cd71e3 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -5,7 +5,7 @@ use crate::hash::{Hash, Hasher}; use crate::intrinsics; use crate::marker::StructuralPartialEq; -use crate::ops::{BitOr, BitOrAssign, Div, Neg, Rem}; +use crate::ops::{BitOr, BitOrAssign, Div, DivAssign, Neg, Rem, RemAssign}; use crate::str::FromStr; use super::from_str_radix; @@ -800,6 +800,16 @@ fn div(self, other: $Ty) -> $Int { } } + #[stable(feature = "nonzero_div2", since = "CURRENT_RUSTC_VERSION")] + impl DivAssign<$Ty> for $Int { + /// This operation rounds towards zero, + /// truncating any fractional part of the exact result, and cannot panic. + #[inline] + fn div_assign(&mut self, other: $Ty) { + *self = *self / other; + } + } + #[stable(feature = "nonzero_div", since = "1.51.0")] impl Rem<$Ty> for $Int { type Output = $Int; @@ -812,6 +822,15 @@ fn rem(self, other: $Ty) -> $Int { unsafe { intrinsics::unchecked_rem(self, other.get()) } } } + + #[stable(feature = "nonzero_div2", since = "CURRENT_RUSTC_VERSION")] + impl RemAssign<$Ty> for $Int { + /// This operation satisfies `n % d == n - (n / d) * d`, and cannot panic. + #[inline] + fn rem_assign(&mut self, other: $Ty) { + *self = *self % other; + } + } }; // Impls for signed nonzero types only. ```

I've used the synthetic nonzero_div2 feature for these and, IMO, they may be an insta-stable API.

Alternatives

m-ou-se commented 4 months ago

We briefly discussed this in the libs-api meeting. This looks fine to us.

Since this is insta-stable, we'll propose an FCP on the PR.