Skip to content

Commit

Permalink
Implement Neg for signed non-zero integers.
Browse files Browse the repository at this point in the history
Negating a non-zero integer currently requires unpacking to a
primitive and re-wrapping. Since negation of non-zero signed
integers always produces a non-zero result, it is safe to
implement `Neg` for `NonZeroI{N}`.

The new `impl` is marked as stable because trait implementations
for two stable types can't be marked unstable.
  • Loading branch information
jmillikin committed Apr 20, 2023
1 parent dc73052 commit 4e2797d
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 3 deletions.
19 changes: 16 additions & 3 deletions library/core/src/num/nonzero.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Definitions of integer that is known not to equal zero.
use crate::fmt;
use crate::ops::{BitOr, BitOrAssign, Div, Rem};
use crate::ops::{BitOr, BitOrAssign, Div, Neg, Rem};
use crate::str::FromStr;

use super::from_str_radix;
Expand Down Expand Up @@ -664,8 +664,7 @@ macro_rules! nonzero_signed_operations {
/// assert_eq!(pos, pos.wrapping_abs());
/// assert_eq!(pos, neg.wrapping_abs());
/// assert_eq!(min, min.wrapping_abs());
/// # // FIXME: add once Neg is implemented?
/// # // assert_eq!(max, (-max).wrapping_abs());
/// assert_eq!(max, (-max).wrapping_abs());
/// # Some(())
/// # }
/// ```
Expand Down Expand Up @@ -868,6 +867,20 @@ macro_rules! nonzero_signed_operations {
unsafe { $Ty::new_unchecked(result) }
}
}

#[stable(feature = "signed_nonzero_neg", since = "CURRENT_RUSTC_VERSION")]
impl Neg for $Ty {
type Output = $Ty;

#[inline]
fn neg(self) -> $Ty {
// SAFETY: negation of nonzero cannot yield zero values.
unsafe { $Ty::new_unchecked(self.get().neg()) }
}
}

forward_ref_unop! { impl Neg, neg for $Ty,
#[stable(feature = "signed_nonzero_neg", since = "CURRENT_RUSTC_VERSION")] }
)+
}
}
Expand Down
18 changes: 18 additions & 0 deletions library/core/tests/nonzero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,3 +336,21 @@ fn test_nonzero_uint_rem() {
let x: u32 = 42u32 % nz;
assert_eq!(x, 2u32);
}

#[test]
fn test_signed_nonzero_neg() {
assert_eq!((-NonZeroI8::new(1).unwrap()).get(), -1);
assert_eq!((-NonZeroI8::new(-1).unwrap()).get(), 1);

assert_eq!((-NonZeroI16::new(1).unwrap()).get(), -1);
assert_eq!((-NonZeroI16::new(-1).unwrap()).get(), 1);

assert_eq!((-NonZeroI32::new(1).unwrap()).get(), -1);
assert_eq!((-NonZeroI32::new(-1).unwrap()).get(), 1);

assert_eq!((-NonZeroI64::new(1).unwrap()).get(), -1);
assert_eq!((-NonZeroI64::new(-1).unwrap()).get(), 1);

assert_eq!((-NonZeroI128::new(1).unwrap()).get(), -1);
assert_eq!((-NonZeroI128::new(-1).unwrap()).get(), 1);
}
12 changes: 12 additions & 0 deletions tests/ui/numbers-arithmetic/overflowing-neg-nonzero.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// run-fail
// error-pattern:thread 'main' panicked at 'attempt to negate with overflow'
// ignore-emscripten no processes
// compile-flags: -C debug-assertions

#![allow(arithmetic_overflow)]

use std::num::NonZeroI8;

fn main() {
let _x = -NonZeroI8::new(i8::MIN).unwrap();
}

0 comments on commit 4e2797d

Please sign in to comment.