1use core::{
4 cmp::Ordering,
5 ops::{Mul, MulAssign, Neg},
6};
7
8pub trait Abs {
16 type Output;
17
18 fn abs(self) -> Self::Output;
19}
20
21pub trait UnsignedAbs {
29 type Output;
30
31 fn unsigned_abs(self) -> Self::Output;
32}
33
34#[deprecated(since = "0.5.0", note = "AbsEq will be moved in AbsOrd in v0.5")] pub trait AbsEq<Rhs = Self> {
45 fn abs_eq(&self, rhs: &Rhs) -> bool;
46}
47
48pub trait AbsOrd<Rhs = Self> {
60 fn abs_cmp(&self, rhs: &Rhs) -> Ordering;
61}
62
63pub trait Signed {
81 fn sign(&self) -> Sign;
82
83 #[inline]
84 fn is_positive(&self) -> bool {
85 self.sign() == Sign::Positive
86 }
87 #[inline]
88 fn is_negative(&self) -> bool {
89 self.sign() == Sign::Negative
90 }
91}
92
93macro_rules! impl_abs_ops_prim {
94 ($($signed:ty;)*) => {$( impl Abs for $signed {
96 type Output = $signed;
97 #[inline]
98 fn abs(self) -> Self::Output {
99 if self.is_nan() || self >= 0. {
100 self
101 } else {
102 -self
103 }
104 }
105 }
106 )*};
107 ($($signed:ty => $unsigned:ty;)*) => {$(
108 impl Abs for $signed {
109 type Output = $signed;
110 #[inline]
111 fn abs(self) -> Self::Output {
112 <$signed>::abs(self)
113 }
114 }
115
116 impl UnsignedAbs for $signed {
117 type Output = $unsigned;
118 #[inline]
119 fn unsigned_abs(self) -> Self::Output {
120 <$signed>::unsigned_abs(self)
121 }
122 }
123 )*}
124}
125impl_abs_ops_prim!(i8 => u8; i16 => u16; i32 => u32; i64 => u64; i128 => u128; isize => usize;);
126impl_abs_ops_prim!(f32; f64;);
127
128#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
132pub enum Sign {
133 Positive,
134 Negative,
135}
136
137use Sign::*;
138
139impl From<bool> for Sign {
140 #[inline]
142 fn from(v: bool) -> Self {
143 match v {
144 true => Self::Negative,
145 false => Self::Positive,
146 }
147 }
148}
149
150impl From<Sign> for bool {
151 #[inline]
153 fn from(v: Sign) -> Self {
154 match v {
155 Sign::Negative => true,
156 Sign::Positive => false,
157 }
158 }
159}
160
161impl Neg for Sign {
162 type Output = Sign;
163
164 #[inline]
165 fn neg(self) -> Sign {
166 match self {
167 Positive => Negative,
168 Negative => Positive,
169 }
170 }
171}
172
173impl Mul<Sign> for Sign {
174 type Output = Sign;
175
176 #[inline]
177 fn mul(self, rhs: Sign) -> Sign {
178 match (self, rhs) {
179 (Positive, Positive) => Positive,
180 (Positive, Negative) => Negative,
181 (Negative, Positive) => Negative,
182 (Negative, Negative) => Positive,
183 }
184 }
185}
186
187impl Mul<Ordering> for Sign {
188 type Output = Ordering;
189 #[inline]
190 fn mul(self, rhs: Ordering) -> Self::Output {
191 match self {
192 Positive => rhs,
193 Negative => rhs.reverse(),
194 }
195 }
196}
197
198impl Mul<Sign> for Ordering {
199 type Output = Ordering;
200 #[inline]
201 fn mul(self, rhs: Sign) -> Self::Output {
202 match rhs {
203 Positive => self,
204 Negative => self.reverse(),
205 }
206 }
207}
208
209impl MulAssign<Sign> for Sign {
210 #[inline]
211 fn mul_assign(&mut self, rhs: Sign) {
212 *self = *self * rhs;
213 }
214}
215
216impl PartialOrd for Sign {
217 #[inline]
218 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
219 Some(self.cmp(other))
220 }
221}
222
223impl Ord for Sign {
224 #[inline]
225 fn cmp(&self, other: &Self) -> Ordering {
226 match (self, other) {
227 (Positive, Negative) => Ordering::Greater,
228 (Negative, Positive) => Ordering::Less,
229 _ => Ordering::Equal,
230 }
231 }
232}
233
234macro_rules! impl_sign_ops_for_primitives {
235 ($($t:ty)*) => {$(
236 impl Mul<$t> for Sign {
237 type Output = $t;
238
239 #[inline]
240 fn mul(self, rhs: $t) -> Self::Output {
241 match self {
242 Positive => rhs,
243 Negative => -rhs
244 }
245 }
246 }
247
248 impl Mul<Sign> for $t {
249 type Output = $t;
250
251 #[inline]
252 fn mul(self, rhs: Sign) -> Self::Output {
253 match rhs {
254 Positive => self,
255 Negative => -self
256 }
257 }
258 }
259 )*};
260}
261impl_sign_ops_for_primitives!(i8 i16 i32 i64 i128 isize f32 f64);
262
263macro_rules! impl_signed_for_int {
264 ($($t:ty)*) => {$(
265 impl Signed for $t {
266 #[inline]
267 fn sign(&self) -> Sign {
268 Sign::from(*self < 0)
269 }
270 }
271
272 #[allow(deprecated)]
273 impl AbsEq for $t {
274 #[inline]
275 fn abs_eq(&self, rhs: &Self) -> bool {
276 self.abs() == rhs.abs()
277 }
278 }
279
280 impl AbsOrd for $t {
281 #[inline]
282 fn abs_cmp(&self, rhs: &Self) -> Ordering {
283 self.abs().cmp(&rhs.abs())
284 }
285 }
286 )*};
287}
288impl_signed_for_int!(i8 i16 i32 i64 i128 isize);
289
290macro_rules! impl_signed_for_float {
291 ($t:ty, $shift:literal) => {
292 impl Signed for $t {
293 #[inline]
294 fn sign(&self) -> Sign {
295 if self.is_nan() {
296 panic!("nan doesn't have a sign")
297 } else if *self == -0. {
298 return Sign::Positive;
299 }
300 Sign::from(self.to_bits() >> $shift > 0)
301 }
302 }
303
304 #[allow(deprecated)]
305 impl AbsEq for $t {
306 #[inline]
307 fn abs_eq(&self, rhs: &Self) -> bool {
308 self.abs() == rhs.abs()
309 }
310 }
311
312 impl AbsOrd for $t {
313 #[inline]
314 fn abs_cmp(&self, rhs: &Self) -> Ordering {
315 self.abs()
316 .partial_cmp(&rhs.abs())
317 .expect("abs_cmp is not allowed on NaNs!")
318 }
319 }
320 };
321}
322impl_signed_for_float!(f32, 31);
323impl_signed_for_float!(f64, 63);
324
325#[cfg(test)]
326mod tests {
327 use super::*;
328
329 #[test]
330 fn test_signed() {
331 assert_eq!(0i32.sign(), Sign::Positive);
332 assert_eq!(1i32.sign(), Sign::Positive);
333 assert_eq!((-1i32).sign(), Sign::Negative);
334
335 assert_eq!(0f32.sign(), Sign::Positive);
336 assert_eq!((-0f32).sign(), Sign::Positive);
337 assert_eq!(1f32.sign(), Sign::Positive);
338 assert_eq!((-1f32).sign(), Sign::Negative);
339 }
340
341 #[test]
342 #[should_panic]
343 fn test_signed_nan() {
344 let _ = f32::NAN.sign();
345 }
346
347 #[test]
348 #[should_panic]
349 fn test_abs_cmp_nan() {
350 let _ = f32::NAN.abs_cmp(&f32::NAN);
351 }
352}