Skip to content

Commit 4e2797d

Browse files
committed
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.
1 parent dc73052 commit 4e2797d

File tree

3 files changed

+46
-3
lines changed

3 files changed

+46
-3
lines changed

library/core/src/num/nonzero.rs

+16-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Definitions of integer that is known not to equal zero.
22
33
use crate::fmt;
4-
use crate::ops::{BitOr, BitOrAssign, Div, Rem};
4+
use crate::ops::{BitOr, BitOrAssign, Div, Neg, Rem};
55
use crate::str::FromStr;
66

77
use super::from_str_radix;
@@ -664,8 +664,7 @@ macro_rules! nonzero_signed_operations {
664664
/// assert_eq!(pos, pos.wrapping_abs());
665665
/// assert_eq!(pos, neg.wrapping_abs());
666666
/// assert_eq!(min, min.wrapping_abs());
667-
/// # // FIXME: add once Neg is implemented?
668-
/// # // assert_eq!(max, (-max).wrapping_abs());
667+
/// assert_eq!(max, (-max).wrapping_abs());
669668
/// # Some(())
670669
/// # }
671670
/// ```
@@ -868,6 +867,20 @@ macro_rules! nonzero_signed_operations {
868867
unsafe { $Ty::new_unchecked(result) }
869868
}
870869
}
870+
871+
#[stable(feature = "signed_nonzero_neg", since = "CURRENT_RUSTC_VERSION")]
872+
impl Neg for $Ty {
873+
type Output = $Ty;
874+
875+
#[inline]
876+
fn neg(self) -> $Ty {
877+
// SAFETY: negation of nonzero cannot yield zero values.
878+
unsafe { $Ty::new_unchecked(self.get().neg()) }
879+
}
880+
}
881+
882+
forward_ref_unop! { impl Neg, neg for $Ty,
883+
#[stable(feature = "signed_nonzero_neg", since = "CURRENT_RUSTC_VERSION")] }
871884
)+
872885
}
873886
}

library/core/tests/nonzero.rs

+18
Original file line numberDiff line numberDiff line change
@@ -336,3 +336,21 @@ fn test_nonzero_uint_rem() {
336336
let x: u32 = 42u32 % nz;
337337
assert_eq!(x, 2u32);
338338
}
339+
340+
#[test]
341+
fn test_signed_nonzero_neg() {
342+
assert_eq!((-NonZeroI8::new(1).unwrap()).get(), -1);
343+
assert_eq!((-NonZeroI8::new(-1).unwrap()).get(), 1);
344+
345+
assert_eq!((-NonZeroI16::new(1).unwrap()).get(), -1);
346+
assert_eq!((-NonZeroI16::new(-1).unwrap()).get(), 1);
347+
348+
assert_eq!((-NonZeroI32::new(1).unwrap()).get(), -1);
349+
assert_eq!((-NonZeroI32::new(-1).unwrap()).get(), 1);
350+
351+
assert_eq!((-NonZeroI64::new(1).unwrap()).get(), -1);
352+
assert_eq!((-NonZeroI64::new(-1).unwrap()).get(), 1);
353+
354+
assert_eq!((-NonZeroI128::new(1).unwrap()).get(), -1);
355+
assert_eq!((-NonZeroI128::new(-1).unwrap()).get(), 1);
356+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// run-fail
2+
// error-pattern:thread 'main' panicked at 'attempt to negate with overflow'
3+
// ignore-emscripten no processes
4+
// compile-flags: -C debug-assertions
5+
6+
#![allow(arithmetic_overflow)]
7+
8+
use std::num::NonZeroI8;
9+
10+
fn main() {
11+
let _x = -NonZeroI8::new(i8::MIN).unwrap();
12+
}

0 commit comments

Comments
 (0)