Skip to content

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

@JarvisCraft

Description

@JarvisCraft

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 --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

  • Status quo: these trait implementations are not obligatory and thus we can just not ignore them, but I don't see any reason for it, while implementing them seems to be a consistency enhancement.

Metadata

Metadata

Assignees

No one assigned

    Labels

    ACP-acceptedAPI Change Proposal is accepted (seconded with no objections)T-libs-apiapi-change-proposalA proposal to add or alter unstable APIs in the standard libraries

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions