1use std::cmp::Ordering;
8use std::fmt;
9use std::ops::{Mul, MulAssign, Neg, Not};
10
11use crate::non_zero::NonZeroSign;
12use crate::NonZero;
13
14pub trait Signed {
18 fn signum(&self) -> Sign;
20 #[inline]
22 fn is_positive(&self) -> bool {
23 self.signum() == Sign::Positive
24 }
25 #[inline]
27 fn is_negative(&self) -> bool {
28 self.signum() == Sign::Negative
29 }
30}
31
32pub trait Negateable: Signed {
34 fn negate(&mut self);
42}
43
44#[derive(Eq, PartialEq, Copy, Clone, Debug)]
46pub enum Sign {
47 Positive = 1,
49 Zero = 0,
51 Negative = -1,
53}
54
55impl Signed for Sign {
56 #[inline]
57 fn signum(&self) -> Sign {
58 *self
59 }
60
61 #[inline]
62 fn is_positive(&self) -> bool {
63 *self == Sign::Positive
64 }
65
66 #[inline]
67 fn is_negative(&self) -> bool {
68 *self == Sign::Negative
69 }
70}
71
72impl Negateable for Sign {
73 #[inline]
74 fn negate(&mut self) {
75 match self {
76 Sign::Positive => *self = Sign::Negative,
77 Sign::Zero => {}
78 Sign::Negative => *self = Sign::Positive,
79 }
80 }
81}
82
83impl Neg for Sign {
84 type Output = Self;
85
86 #[inline]
87 fn neg(self) -> Self::Output {
88 match self {
89 Sign::Positive => Sign::Negative,
90 Sign::Zero => Sign::Zero,
91 Sign::Negative => Sign::Positive,
92 }
93 }
94}
95
96impl Not for Sign {
97 type Output = Self;
98
99 #[inline]
100 fn not(self) -> Self::Output {
101 match self {
102 Sign::Positive => Sign::Negative,
103 Sign::Zero => Sign::Zero,
104 Sign::Negative => Sign::Positive,
105 }
106 }
107}
108
109impl NonZero for Sign {
110 #[inline]
111 fn is_not_zero(&self) -> bool {
112 *self != Sign::Zero
113 }
114}
115
116impl MulAssign for Sign {
117 #[inline]
118 fn mul_assign(&mut self, rhs: Self) {
119 *self = match (&self, rhs) {
120 (Sign::Positive, Sign::Positive) | (Sign::Negative, Sign::Negative) => Sign::Positive,
121 (Sign::Zero, _) | (_, Sign::Zero) => Sign::Zero,
122 (Sign::Positive, Sign::Negative) | (Sign::Negative, Sign::Positive) => Sign::Negative,
123 };
124 }
125}
126
127impl Mul for Sign {
128 type Output = Self;
129
130 #[inline]
131 fn mul(mut self, rhs: Self) -> Self::Output {
132 self *= rhs;
133 self
134 }
135}
136
137impl Ord for Sign {
139 #[inline]
140 fn cmp(&self, other: &Self) -> Ordering {
141 (*self as i8).cmp(&(*other as i8))
142 }
143}
144
145impl PartialOrd for Sign {
146 #[inline]
147 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
148 Some(self.cmp(other))
149 }
150}
151
152impl From<NonZeroSign> for Sign {
153 #[inline]
154 fn from(sign: NonZeroSign) -> Self {
155 match sign {
156 NonZeroSign::Positive => Sign::Positive,
157 NonZeroSign::Negative => Sign::Negative,
158 }
159 }
160}
161
162impl fmt::Display for Sign {
163 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164 f.write_str(match self {
165 Sign::Negative => "-",
166 Sign::Zero => "0",
167 Sign::Positive => "+",
168 })
169 }
170}
171
172#[cfg(test)]
173mod test {
174 use std::cmp::Ordering;
175
176 use crate::{Sign, Signed};
177 use crate::RB;
178
179 #[test]
180 fn test_integer() {
181 assert_eq!(Signed::signum(&0_i32), Sign::Zero);
182 assert_eq!(Signed::signum(&-1), Sign::Negative);
183 assert_eq!(Signed::signum(&1_i128), Sign::Positive);
184 assert_eq!(Signed::signum(&0_u32), Sign::Zero);
185 assert_eq!(Signed::signum(&1_u64), Sign::Positive);
186 }
187
188 #[test]
189 fn test_sign_boolean() {
190 assert!(6.is_positive());
191 assert!((-5).is_negative());
192 assert!(!0.is_positive());
193 assert!(!0.is_negative());
194 assert!(!6.is_negative());
195 assert!(!(-5).is_positive());
196 }
197
198 #[test]
199 fn test_sign() {
200 assert_eq!(!Sign::Zero, Sign::Zero);
201 assert_eq!(!Sign::Positive, Sign::Negative);
202 assert_eq!(!Sign::Negative, Sign::Positive);
203 assert_eq!(Sign::Positive, -Sign::Negative);
204 assert_eq!(Sign::Positive * Sign::Positive, Sign::Positive);
205 assert_eq!(Sign::Negative * Sign::Negative, Sign::Positive);
206 assert_eq!(Sign::Negative * Sign::Zero, -Sign::Zero);
207 }
208
209 #[test]
211 fn test_sign_ord_contract() {
212 for a in [Sign::Negative, Sign::Zero, Sign::Positive] {
213 assert_eq!(a.partial_cmp(&a), Some(Ordering::Equal));
214 assert!(a <= a);
215 assert!(a >= a);
216 for b in [Sign::Negative, Sign::Zero, Sign::Positive] {
217 assert_eq!(a == b, a.partial_cmp(&b) == Some(Ordering::Equal));
218 assert_eq!(a.partial_cmp(&b), Some(a.cmp(&b)));
219 assert_eq!(a.cmp(&b), b.cmp(&a).reverse());
220 }
221 }
222 assert!(Sign::Negative < Sign::Zero && Sign::Zero < Sign::Positive);
223 }
224
225 #[test]
226 fn test_sign_ord() {
227 assert_eq!(Sign::Zero < Sign::Positive, true);
228 assert_eq!(Sign::Positive < Sign::Positive, false);
229 assert_eq!(Sign::Positive == Sign::Positive, true);
230 assert_eq!(Sign::Zero == Sign::Zero, true);
231 assert_eq!(Sign::Negative < Sign::Positive, true);
232 assert_eq!(Sign::Negative < Sign::Zero, true);
233 assert_eq!(Sign::Negative < Sign::Negative, false);
234 }
235
236 #[test]
237 fn test_sign_conversion() {
238 assert_eq!(Sign::Positive, crate::NonZeroSign::Positive.into());
239 }
240
241 #[test]
242 fn test_numbers() {
243 assert_eq!(Signed::signum(&1), Sign::Positive);
244 assert_eq!(Signed::signum(&0), Sign::Zero);
245 assert_eq!(Signed::signum(&(-1)), Sign::Negative);
246
247 assert_eq!(RB!(0).signum(), Sign::Zero);
248 assert_eq!(RB!(1).signum(), Sign::Positive);
249 assert_eq!(RB!(-1).signum(), Sign::Negative);
250
251 assert_eq!(RB!(-1).signum() * RB!(-1).signum(), Sign::Positive);
252 assert_eq!(RB!(1).signum() * RB!(1).signum(), Sign::Positive);
253 assert_eq!(RB!(-1).signum() * RB!(1).signum(), Sign::Negative);
254 }
255}