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);
36}
37
38#[derive(Eq, PartialEq, Copy, Clone, Debug)]
40pub enum Sign {
41 Positive = 1,
43 Zero = 0,
45 Negative = -1,
47}
48
49impl Signed for Sign {
50 #[inline]
51 fn signum(&self) -> Sign {
52 *self
53 }
54
55 #[inline]
56 fn is_positive(&self) -> bool {
57 *self == Sign::Positive
58 }
59
60 #[inline]
61 fn is_negative(&self) -> bool {
62 *self == Sign::Negative
63 }
64}
65
66impl Negateable for Sign {
67 #[inline]
68 fn negate(&mut self) {
69 match self {
70 Sign::Positive => *self = Sign::Negative,
71 Sign::Zero => {}
72 Sign::Negative => *self = Sign::Positive,
73 }
74 }
75}
76
77impl Neg for Sign {
78 type Output = Self;
79
80 #[must_use]
81 #[inline]
82 fn neg(self) -> Self::Output {
83 match self {
84 Sign::Positive => Sign::Negative,
85 Sign::Zero => Sign::Zero,
86 Sign::Negative => Sign::Positive,
87 }
88 }
89}
90
91impl Not for Sign {
92 type Output = Self;
93
94 #[must_use]
95 #[inline]
96 fn not(self) -> Self::Output {
97 match self {
98 Sign::Positive => Sign::Negative,
99 Sign::Zero => Sign::Zero,
100 Sign::Negative => Sign::Positive,
101 }
102 }
103}
104
105impl NonZero for Sign {
106 #[must_use]
107 #[inline]
108 fn is_not_zero(&self) -> bool {
109 *self != Sign::Zero
110 }
111}
112
113impl MulAssign for Sign {
114 #[inline]
115 fn mul_assign(&mut self, rhs: Self) {
116 *self = match (&self, rhs) {
117 (Sign::Positive, Sign::Positive) | (Sign::Negative, Sign::Negative) => Sign::Positive,
118 (Sign::Zero, _) | (_, Sign::Zero) => Sign::Zero,
119 (Sign::Positive, Sign::Negative) | (Sign::Negative, Sign::Positive) => Sign::Negative,
120 };
121 }
122}
123
124impl Mul for Sign {
125 type Output = Self;
126
127 #[must_use]
128 #[inline]
129 fn mul(mut self, rhs: Self) -> Self::Output {
130 self *= rhs;
131 self
132 }
133}
134
135impl PartialOrd for Sign {
136 #[must_use]
137 #[inline]
138 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
139 match (self, other) {
140 (Sign::Negative, Sign::Zero | Sign::Positive) | (Sign::Zero, Sign::Positive) => Some(Ordering::Less),
141 (Sign::Zero, Sign::Zero) => Some(Ordering::Equal),
142 (Sign::Positive, Sign::Zero | Sign::Negative) | (Sign::Zero, Sign::Negative) => Some(Ordering::Greater),
143 (Sign::Negative, Sign::Negative) | (Sign::Positive, Sign::Positive) => None,
144 }
145 }
146}
147
148impl From<NonZeroSign> for Sign {
149 #[must_use]
150 #[inline]
151 fn from(sign: NonZeroSign) -> Self {
152 match sign {
153 NonZeroSign::Positive => Sign::Positive,
154 NonZeroSign::Negative => Sign::Negative,
155 }
156 }
157}
158
159impl fmt::Display for Sign {
160 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161 f.write_str(match self {
162 Sign::Negative => "-",
163 Sign::Zero => "0",
164 Sign::Positive => "+",
165 })
166 }
167}
168
169#[cfg(test)]
170mod test {
171 use crate::{Sign, Signed};
172 use crate::RB;
173
174 #[test]
175 fn test_integer() {
176 assert_eq!(Signed::signum(&0_i32), Sign::Zero);
177 assert_eq!(Signed::signum(&-1), Sign::Negative);
178 assert_eq!(Signed::signum(&1_i128), Sign::Positive);
179 assert_eq!(Signed::signum(&0_u32), Sign::Zero);
180 assert_eq!(Signed::signum(&1_u64), Sign::Positive);
181 }
182
183 #[test]
184 fn test_sign_boolean() {
185 assert!(6.is_positive());
186 assert!((-5).is_negative());
187 assert!(!0.is_positive());
188 assert!(!0.is_negative());
189 assert!(!6.is_negative());
190 assert!(!(-5).is_positive());
191 }
192
193 #[test]
194 fn test_sign() {
195 assert_eq!(!Sign::Zero, Sign::Zero);
196 assert_eq!(!Sign::Positive, Sign::Negative);
197 assert_eq!(!Sign::Negative, Sign::Positive);
198 assert_eq!(Sign::Positive, -Sign::Negative);
199 assert_eq!(Sign::Positive * Sign::Positive, Sign::Positive);
200 assert_eq!(Sign::Negative * Sign::Negative, Sign::Positive);
201 assert_eq!(Sign::Negative * Sign::Zero, -Sign::Zero);
202 }
203
204 #[test]
205 fn test_sign_ord() {
206 assert_eq!(Sign::Zero < Sign::Positive, true);
207 assert_eq!(Sign::Positive < Sign::Positive, false);
208 assert_eq!(Sign::Positive == Sign::Positive, true);
209 assert_eq!(Sign::Zero == Sign::Zero, true);
210 assert_eq!(Sign::Negative < Sign::Positive, true);
211 assert_eq!(Sign::Negative < Sign::Zero, true);
212 assert_eq!(Sign::Negative < Sign::Negative, false);
213 }
214
215 #[test]
216 fn test_sign_conversion() {
217 assert_eq!(Sign::Positive, crate::NonZeroSign::Positive.into());
218 }
219
220 #[test]
221 fn test_numbers() {
222 assert_eq!(Signed::signum(&1), Sign::Positive);
223 assert_eq!(Signed::signum(&0), Sign::Zero);
224 assert_eq!(Signed::signum(&(-1)), Sign::Negative);
225
226 assert_eq!(RB!(0).signum(), Sign::Zero);
227 assert_eq!(RB!(1).signum(), Sign::Positive);
228 assert_eq!(RB!(-1).signum(), Sign::Negative);
229
230 assert_eq!(RB!(-1).signum() * RB!(-1).signum(), Sign::Positive);
231 assert_eq!(RB!(1).signum() * RB!(1).signum(), Sign::Positive);
232 assert_eq!(RB!(-1).signum() * RB!(1).signum(), Sign::Negative);
233 }
234}