1use std::cmp::Ordering;
3use std::num::NonZero;
4
5use crate::Negateable;
6use crate::{NonZeroSign, NonZeroSigned};
7use crate::Sign;
8use crate::Signed;
9
10macro_rules! unsigned {
11 ($($ty:ty),+ $(,)?) => {$(
12 impl Signed for $ty {
13 #[inline]
14 fn signum(&self) -> Sign {
15 if *self == 0 {
16 Sign::Zero
17 } else {
18 Sign::Positive
19 }
20 }
21 }
22 )+}
23}
24
25unsigned!(u8, u16, u32, u64, u128, usize);
26
27macro_rules! signed {
28 ($($ty:ty),+ $(,)?) => {$(
29 impl Signed for $ty {
30 #[inline]
31 fn signum(&self) -> Sign {
32 match self.cmp(&0) {
33 Ordering::Less => Sign::Negative,
34 Ordering::Equal => Sign::Zero,
35 Ordering::Greater => Sign::Positive,
36 }
37 }
38 }
39
40 impl Negateable for $ty {
41 #[inline]
42 #[track_caller]
43 fn negate(&mut self) {
44 match self.checked_neg() {
49 Some(negated) => *self = negated,
50 None => panic!(concat!("cannot negate ", stringify!($ty), "::MIN")),
51 }
52 }
53 }
54 )+}
55}
56
57signed!(i8, i16, i32, i64, i128, isize);
58
59macro_rules! non_zero_unsigned {
60 ($($ty:ty),+ $(,)?) => {$(
61 impl Signed for NonZero<$ty> {
62 #[inline]
63 fn signum(&self) -> Sign {
64 Sign::Positive
65 }
66 }
67
68 impl NonZeroSigned for NonZero<$ty> {
70 #[inline]
71 fn non_zero_signum(&self) -> NonZeroSign {
72 NonZeroSign::Positive
73 }
74 }
75 )+}
76}
77
78non_zero_unsigned!(u8, u16, u32, u64, u128, usize);
79
80macro_rules! non_zero_signed {
81 ($($ty:ty),+ $(,)?) => {$(
82 impl Signed for NonZero<$ty> {
83 #[inline]
84 fn signum(&self) -> Sign {
85 if self.get() > 0 {
86 Sign::Positive
87 } else {
88 Sign::Negative
89 }
90 }
91 }
92
93 impl Negateable for NonZero<$ty> {
94 #[inline]
95 #[track_caller]
96 fn negate(&mut self) {
97 match self.get().checked_neg() {
101 Some(negated) => *self = unsafe {
102 NonZero::new_unchecked(negated)
104 },
105 None => panic!(concat!("cannot negate NonZero<", stringify!($ty), ">::MIN")),
106 }
107 }
108 }
109
110 impl NonZeroSigned for NonZero<$ty> {
112 #[inline]
113 fn non_zero_signum(&self) -> NonZeroSign {
114 if self.get() > 0 {
115 NonZeroSign::Positive
116 } else {
117 NonZeroSign::Negative
118 }
119 }
120 }
121 )+}
122}
123
124non_zero_signed!(i8, i16, i32, i64, i128, isize);
125
126#[cfg(test)]
127mod test {
128 use std::num::{NonZeroI8, NonZeroU8};
129
130 use crate::{Negateable, NonZeroSign, NonZeroSigned};
131
132 #[test]
133 fn test_zero_sign() {
134 assert_eq!(1_u32.non_zero_signum(), NonZeroSign::Positive);
135 assert_eq!(-1_u32.non_zero_signum(), NonZeroSign::Negative);
136
137 assert_eq!(NonZeroU8::new(1).unwrap().non_zero_signum(), NonZeroSign::Positive);
138 assert_eq!(NonZeroI8::new(1).unwrap().non_zero_signum(), NonZeroSign::Positive);
139 assert_eq!(NonZeroI8::new(-1).unwrap().non_zero_signum(), NonZeroSign::Negative);
140 }
141
142 #[test]
143 #[should_panic]
144 fn test_non_zero_on_zero() {
145 0_u32.non_zero_signum();
146 }
147
148 #[test]
149 #[should_panic]
150 fn test_non_zero_on_zero_signed() {
151 0_i8.non_zero_signum();
152 }
153
154 #[test]
157 fn test_negate_minimum_panics() {
158 macro_rules! check {
159 ($ty:ty, $nz:ty) => {
160 let mut value = <$ty>::MIN;
161 assert!(std::panic::catch_unwind(move || value.negate()).is_err());
162
163 let mut value = <$nz>::new(<$ty>::MIN).unwrap();
164 assert!(std::panic::catch_unwind(move || value.negate()).is_err());
165
166 for start in [<$ty>::MIN + 1, -1, 1, <$ty>::MAX] {
168 let mut value = start;
169 value.negate();
170 assert_eq!(value, -start, "{} {start}", stringify!($ty));
171 value.negate();
172 assert_eq!(value, start, "{} {start}", stringify!($ty));
173 }
174 }
175 }
176
177 let hook = std::panic::take_hook();
178 std::panic::set_hook(Box::new(|_| {}));
179
180 check!(i8, std::num::NonZeroI8);
181 check!(i16, std::num::NonZeroI16);
182 check!(i32, std::num::NonZeroI32);
183 check!(i64, std::num::NonZeroI64);
184 check!(i128, std::num::NonZeroI128);
185 check!(isize, std::num::NonZeroIsize);
186
187 std::panic::set_hook(hook);
188 }
189}