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