1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
use core::{f32, f64};
use core::intrinsics;
use core::ops::Neg;
use core::num::Wrapping;

use super::Num;

pub trait Signed: Num + Neg<Output = Self> {
    /// # Example
    /// ```rust
    /// use number_traits::Signed;
    ///
    /// assert_eq!((-1).abs(), 1);
    /// assert_eq!((-1.0).abs(), 1.0);
    /// ```
    fn abs(&self) -> Self;
    /// # Example
    /// ```rust
    /// use number_traits::Signed;
    ///
    /// assert_eq!(2.abs_sub(&1), 1);
    /// assert_eq!(1.abs_sub(&2), 0);
    /// assert_eq!((-1.0).abs_sub(&-2.0), 1.0);
    /// assert_eq!((-2.0).abs_sub(&-1.0), 0.0);
    /// ```
    fn abs_sub(&self, other: &Self) -> Self;
    /// # Example
    /// ```rust
    /// use number_traits::Signed;
    ///
    /// assert_eq!(0.signum(), 0);
    /// assert_eq!((-1).signum(), -1);
    /// assert_eq!(1.signum(), 1);
    /// ```
    fn signum(&self) -> Self;
    /// # Example
    /// ```rust
    /// use number_traits::Signed;
    ///
    /// assert_eq!(1.is_positive(), true);
    /// assert_eq!((-1).is_positive(), false);
    /// ```
    fn is_positive(&self) -> bool;
    /// # Example
    /// ```rust
    /// use number_traits::Signed;
    ///
    /// assert_eq!(1.is_negative(), false);
    /// assert_eq!((-1).is_negative(), true);
    /// ```
    fn is_negative(&self) -> bool;
}

macro_rules! trait_signed {
    ($($T:ty),*) => (
        $(impl Signed for $T {
            #[inline]
            fn abs(&self) -> Self {
                if self.is_negative() { -*self } else { *self }
            }
            #[inline]
            fn abs_sub(&self, other: &Self) -> Self {
                if *self <= *other { 0 } else { *self - *other }
            }
            #[inline]
            fn signum(&self) -> Self {
                match *self {
                    n if n > 0 => 1,
                    0 => 0,
                    _ => -1,
                }
            }
            #[inline]
            fn is_positive(&self) -> bool { *self > 0 }
            #[inline]
            fn is_negative(&self) -> bool { *self < 0 }
        })*
    );
}
trait_signed!(isize, i8, i16, i32, i64, i128);

macro_rules! trait_float {
    ($T:ty, $nan:expr, $inf:expr, $neg_inf:expr, $fabs:path, $fcopysign:path, $fdim:ident) => (
        impl Signed for $T {
            #[inline]
            fn abs(&self) -> Self {
                unsafe { $fabs(*self) }
            }
            #[inline]
            fn abs_sub(&self, other: &Self) -> Self {
                extern { fn $fdim(a: $T, b: $T) -> $T; }
                unsafe { $fdim(*self, *other) }
            }
            #[inline]
            fn signum(&self) -> Self {
                if self != self { $nan } else {
                    unsafe { $fcopysign(1.0, *self) }
                }
            }
            #[inline]
            fn is_positive(&self) -> bool { *self > 0.0 || (1.0 / *self) == $inf }
            #[inline]
            fn is_negative(&self) -> bool { *self < 0.0 || (1.0 / *self) == $neg_inf }
        }
    );
}

trait_float!(
    f32,
    f32::NAN,
    f32::INFINITY,
    f32::NEG_INFINITY,
    intrinsics::fabsf32,
    intrinsics::copysignf32,
    fdimf
);
trait_float!(
    f64,
    f64::NAN,
    f64::INFINITY,
    f64::NEG_INFINITY,
    intrinsics::fabsf64,
    intrinsics::copysignf64,
    fdim
);

impl<T> Signed for Wrapping<T>
where
    T: Signed,
    Self: Num + Neg<Output = Self>,
{
    #[inline(always)]
    fn abs(&self) -> Self {
        Wrapping(Signed::abs(&self.0))
    }
    #[inline(always)]
    fn abs_sub(&self, other: &Self) -> Self {
        Wrapping(Signed::abs_sub(&self.0, &other.0))
    }
    #[inline(always)]
    fn signum(&self) -> Self {
        Wrapping(Signed::signum(&self.0))
    }
    #[inline(always)]
    fn is_positive(&self) -> bool {
        Signed::is_positive(&self.0)
    }
    #[inline(always)]
    fn is_negative(&self) -> bool {
        Signed::is_negative(&self.0)
    }
}