relp_num/non_zero/
sign.rs1use std::cmp::Ordering;
5use std::ops::{Mul, MulAssign, Neg, Not};
6
7use crate::{Negateable, Signed};
8use crate::non_zero::NonZero;
9use crate::sign::Sign;
10
11pub trait NonZeroSigned: NonZero + Signed {
13 fn non_zero_signum(&self) -> NonZeroSign;
15 #[inline]
17 fn non_zero_is_positive(&self) -> bool {
18 self.non_zero_signum() == NonZeroSign::Positive
19 }
20 #[inline]
22 fn non_zero_is_negative(&self) -> bool {
23 self.non_zero_signum() == NonZeroSign::Negative
24 }
25}
26
27#[derive(Eq, PartialEq, Copy, Clone, Debug)]
32pub enum NonZeroSign {
33 Positive = 1,
35 Negative = -1,
37}
38
39macro_rules! non_zero_signed_by_panic {
45 ($($t:ty),+ $(,)?) => {$(
46 impl NonZeroSigned for $t {
47 #[inline]
48 #[track_caller]
49 fn non_zero_signum(&self) -> NonZeroSign {
50 match Signed::signum(self) {
51 Sign::Positive => NonZeroSign::Positive,
52 Sign::Negative => NonZeroSign::Negative,
53 Sign::Zero => panic!(
54 "attempt to take the non zero sign of a zero value of type {}",
55 std::any::type_name::<$t>(),
56 ),
57 }
58 }
59 }
60 )+}
61}
62
63non_zero_signed_by_panic!(i8, i16, i32, i64, i128, isize);
64non_zero_signed_by_panic!(u8, u16, u32, u64, u128, usize);
65non_zero_signed_by_panic!(Sign);
66
67macro_rules! non_zero_signed_total {
69 ($t:ty, $sign:expr) => {
70 impl NonZeroSigned for $t {
72 #[inline]
73 fn non_zero_signum(&self) -> NonZeroSign {
74 $sign(self)
75 }
76 }
77 }
78}
79
80non_zero_signed_total!(crate::fixed::One, |_: &crate::fixed::One| NonZeroSign::Positive);
81non_zero_signed_total!(crate::fixed::SignedOne, |value: &crate::fixed::SignedOne| match value {
82 crate::fixed::SignedOne::PlusOne => NonZeroSign::Positive,
83 crate::fixed::SignedOne::MinusOne => NonZeroSign::Negative,
84});
85
86impl Signed for NonZeroSign {
87 fn signum(&self) -> Sign {
88 match self {
89 NonZeroSign::Positive => Sign::Positive,
90 NonZeroSign::Negative => Sign::Negative,
91 }
92 }
93}
94
95impl NonZero for NonZeroSign {
96 fn is_not_zero(&self) -> bool {
97 true
98 }
99}
100
101impl Negateable for NonZeroSign {
102 fn negate(&mut self) {
103 *self = match self {
104 NonZeroSign::Positive => NonZeroSign::Negative,
105 NonZeroSign::Negative => NonZeroSign::Positive,
106 }
107 }
108}
109
110impl Not for NonZeroSign {
111 type Output = Self;
112
113 fn not(mut self) -> Self::Output {
114 Negateable::negate(&mut self);
115 self
116 }
117}
118
119impl Neg for NonZeroSign {
120 type Output = Self;
121
122 fn neg(mut self) -> Self::Output {
123 Negateable::negate(&mut self);
124 self
125 }
126}
127
128impl From<Sign> for NonZeroSign {
129 fn from(other: Sign) -> Self {
130 debug_assert!(other.is_not_zero());
131
132 match other {
133 Sign::Positive => NonZeroSign::Positive,
134 Sign::Zero => panic!("attempt to convert a zero sign into a non zero sign"),
135 Sign::Negative => NonZeroSign::Negative,
136 }
137 }
138}
139
140impl Ord for NonZeroSign {
142 #[inline]
143 fn cmp(&self, other: &Self) -> Ordering {
144 (*self as i8).cmp(&(*other as i8))
145 }
146}
147
148impl PartialOrd for NonZeroSign {
149 #[inline]
150 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
151 Some(self.cmp(other))
152 }
153}
154
155impl Mul for NonZeroSign {
156 type Output = Self;
157
158 fn mul(mut self, rhs: Self) -> Self::Output {
159 MulAssign::mul_assign(&mut self, rhs);
160 self
161 }
162}
163
164impl MulAssign for NonZeroSign {
165 fn mul_assign(&mut self, rhs: Self) {
166 *self = match (*self, rhs) {
167 (NonZeroSign::Positive, NonZeroSign::Positive) => NonZeroSign::Positive,
168 (NonZeroSign::Positive, NonZeroSign::Negative) => NonZeroSign::Negative,
169 (NonZeroSign::Negative, NonZeroSign::Positive) => NonZeroSign::Negative,
170 (NonZeroSign::Negative, NonZeroSign::Negative) => NonZeroSign::Positive,
171 }
172 }
173}
174
175#[cfg(test)]
176mod test {
177 use std::cmp::Ordering;
178
179 use crate::{NonZeroSign, NonZeroSigned, Sign};
180 use crate::{R64, RB};
181
182 #[test]
183 fn test_cmp() {
184 assert!(NonZeroSign::Positive > NonZeroSign::Negative);
185 assert_eq!(NonZeroSign::Positive.partial_cmp(&NonZeroSign::Positive), Some(Ordering::Equal));
186 assert_eq!(NonZeroSign::Negative.partial_cmp(&NonZeroSign::Negative), Some(Ordering::Equal));
187 assert_eq!(NonZeroSign::Negative.partial_cmp(&NonZeroSign::Positive), Some(Ordering::Less));
188 }
189
190 #[test]
192 fn test_cmp_contract() {
193 for a in [NonZeroSign::Negative, NonZeroSign::Positive] {
194 assert_eq!(a.partial_cmp(&a), Some(Ordering::Equal));
195 assert!(a <= a);
196 assert!(a >= a);
197 for b in [NonZeroSign::Negative, NonZeroSign::Positive] {
198 assert_eq!(a == b, a.partial_cmp(&b) == Some(Ordering::Equal));
199 assert_eq!(a.partial_cmp(&b), Some(a.cmp(&b)));
200 assert_eq!(a.cmp(&b), b.cmp(&a).reverse());
201 }
202 }
203 assert!(NonZeroSign::Negative < NonZeroSign::Positive);
204 }
205
206 #[test]
207 fn test_numbers() {
208 use crate::Signed;
209 assert_eq!(Signed::signum(&RB!(1)), Sign::Positive);
210 assert_eq!(Signed::signum(&RB!(-1)), Sign::Negative);
211 assert!(RB!(1).is_positive());
212 assert!(RB!(-1).is_negative());
213 }
214
215 #[test]
216 fn test_numbers_non_zero() {
217 assert_eq!(1.non_zero_signum(), NonZeroSign::Positive);
218 assert_eq!((-1).non_zero_signum(), NonZeroSign::Negative);
219
220 assert_eq!(RB!(-1).non_zero_signum() * RB!(-1).non_zero_signum(), NonZeroSign::Positive);
221 assert_eq!(RB!(1).non_zero_signum() * RB!(1).non_zero_signum(), NonZeroSign::Positive);
222
223 assert_eq!(RB!(-1).non_zero_signum() * RB!(1).non_zero_signum(), NonZeroSign::Negative);
224
225 assert_eq!(R64!(1).non_zero_signum(), NonZeroSign::Positive);
226 assert_eq!(R64!(-1).non_zero_signum(), NonZeroSign::Negative);
227
228 assert_eq!(R64!(-1).non_zero_signum() * R64!(-1).non_zero_signum(), NonZeroSign::Positive);
229 assert_eq!(R64!(1).non_zero_signum() * R64!(1).non_zero_signum(), NonZeroSign::Positive);
230 assert_eq!(R64!(-1).non_zero_signum() * R64!(1).non_zero_signum(), NonZeroSign::Negative);
231 }
232
233 #[test]
234 #[should_panic]
235 fn test_zero() {
236 RB!(0).non_zero_signum();
237 }
238}