Implement `Neg` for signed non-zero integers.

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.
This commit is contained in:
John Millikin 2022-09-27 11:40:39 +09:00
parent dc730521ef
commit 4e2797dd76
3 changed files with 46 additions and 3 deletions

View File

@ -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;
@ -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(())
/// # }
/// ```
@ -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")] }
)+
}
}

View File

@ -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);
}

View File

@ -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();
}