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 Sign {
140 #[inline]
154 pub const fn as_sign_str(self, sign_plus: bool) -> &'static str {
155 match self {
156 Sign::Negative => "-",
157 Sign::Positive if sign_plus => "+",
158 _ => "",
159 }
160 }
161}
162
163impl From<bool> for Sign {
164 #[inline]
166 fn from(v: bool) -> Self {
167 match v {
168 true => Self::Negative,
169 false => Self::Positive,
170 }
171 }
172}
173
174impl From<Sign> for bool {
175 #[inline]
177 fn from(v: Sign) -> Self {
178 match v {
179 Sign::Negative => true,
180 Sign::Positive => false,
181 }
182 }
183}
184
185impl Neg for Sign {
186 type Output = Sign;
187
188 #[inline]
189 fn neg(self) -> Sign {
190 match self {
191 Positive => Negative,
192 Negative => Positive,
193 }
194 }
195}
196
197impl Mul<Sign> for Sign {
198 type Output = Sign;
199
200 #[inline]
201 fn mul(self, rhs: Sign) -> Sign {
202 match (self, rhs) {
203 (Positive, Positive) => Positive,
204 (Positive, Negative) => Negative,
205 (Negative, Positive) => Negative,
206 (Negative, Negative) => Positive,
207 }
208 }
209}
210
211impl Mul<Ordering> for Sign {
212 type Output = Ordering;
213 #[inline]
214 fn mul(self, rhs: Ordering) -> Self::Output {
215 match self {
216 Positive => rhs,
217 Negative => rhs.reverse(),
218 }
219 }
220}
221
222impl Mul<Sign> for Ordering {
223 type Output = Ordering;
224 #[inline]
225 fn mul(self, rhs: Sign) -> Self::Output {
226 match rhs {
227 Positive => self,
228 Negative => self.reverse(),
229 }
230 }
231}
232
233impl MulAssign<Sign> for Sign {
234 #[inline]
235 fn mul_assign(&mut self, rhs: Sign) {
236 *self = *self * rhs;
237 }
238}
239
240impl PartialOrd for Sign {
241 #[inline]
242 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
243 Some(self.cmp(other))
244 }
245}
246
247impl Ord for Sign {
248 #[inline]
249 fn cmp(&self, other: &Self) -> Ordering {
250 match (self, other) {
251 (Positive, Negative) => Ordering::Greater,
252 (Negative, Positive) => Ordering::Less,
253 _ => Ordering::Equal,
254 }
255 }
256}
257
258macro_rules! impl_sign_ops_for_primitives {
259 ($($t:ty)*) => {$(
260 impl Mul<$t> for Sign {
261 type Output = $t;
262
263 #[inline]
264 fn mul(self, rhs: $t) -> Self::Output {
265 match self {
266 Positive => rhs,
267 Negative => -rhs
268 }
269 }
270 }
271
272 impl Mul<Sign> for $t {
273 type Output = $t;
274
275 #[inline]
276 fn mul(self, rhs: Sign) -> Self::Output {
277 match rhs {
278 Positive => self,
279 Negative => -self
280 }
281 }
282 }
283 )*};
284}
285impl_sign_ops_for_primitives!(i8 i16 i32 i64 i128 isize f32 f64);
286
287macro_rules! impl_signed_for_int {
288 ($($t:ty)*) => {$(
289 impl Signed for $t {
290 #[inline]
291 fn sign(&self) -> Sign {
292 Sign::from(*self < 0)
293 }
294 }
295
296 #[allow(deprecated)]
297 impl AbsEq for $t {
298 #[inline]
299 fn abs_eq(&self, rhs: &Self) -> bool {
300 self.abs() == rhs.abs()
301 }
302 }
303
304 impl AbsOrd for $t {
305 #[inline]
306 fn abs_cmp(&self, rhs: &Self) -> Ordering {
307 self.abs().cmp(&rhs.abs())
308 }
309 }
310 )*};
311}
312impl_signed_for_int!(i8 i16 i32 i64 i128 isize);
313
314macro_rules! impl_signed_for_float {
315 ($t:ty, $shift:literal) => {
316 impl Signed for $t {
317 #[inline]
318 fn sign(&self) -> Sign {
319 if self.is_nan() {
320 panic!("nan doesn't have a sign")
321 } else if *self == -0. {
322 return Sign::Positive;
323 }
324 Sign::from(self.to_bits() >> $shift > 0)
325 }
326 }
327
328 #[allow(deprecated)]
329 impl AbsEq for $t {
330 #[inline]
331 fn abs_eq(&self, rhs: &Self) -> bool {
332 self.abs() == rhs.abs()
333 }
334 }
335
336 impl AbsOrd for $t {
337 #[inline]
338 fn abs_cmp(&self, rhs: &Self) -> Ordering {
339 self.abs()
340 .partial_cmp(&rhs.abs())
341 .expect("abs_cmp is not allowed on NaNs!")
342 }
343 }
344 };
345}
346impl_signed_for_float!(f32, 31);
347impl_signed_for_float!(f64, 63);
348
349#[cfg(test)]
350mod tests {
351 use super::*;
352
353 #[test]
354 fn test_signed() {
355 assert_eq!(0i32.sign(), Sign::Positive);
356 assert_eq!(1i32.sign(), Sign::Positive);
357 assert_eq!((-1i32).sign(), Sign::Negative);
358
359 assert_eq!(0f32.sign(), Sign::Positive);
360 assert_eq!((-0f32).sign(), Sign::Positive);
361 assert_eq!(1f32.sign(), Sign::Positive);
362 assert_eq!((-1f32).sign(), Sign::Negative);
363 }
364
365 #[test]
366 #[should_panic]
367 fn test_signed_nan() {
368 let _ = f32::NAN.sign();
369 }
370
371 #[test]
372 #[should_panic]
373 fn test_abs_cmp_nan() {
374 let _ = f32::NAN.abs_cmp(&f32::NAN);
375 }
376}