use core::ops::Neg;
use core::{f32, f64};
use core::num::Wrapping;
use Num;
pub trait Signed: Sized + Num + Neg<Output = Self> {
fn abs(&self) -> Self;
fn abs_sub(&self, other: &Self) -> Self;
fn signum(&self) -> Self;
fn is_positive(&self) -> bool;
fn is_negative(&self) -> bool;
}
macro_rules! signed_impl {
($($t:ty)*) => ($(
impl Signed for $t {
#[inline]
fn abs(&self) -> $t {
if self.is_negative() { -*self } else { *self }
}
#[inline]
fn abs_sub(&self, other: &$t) -> $t {
if *self <= *other { 0 } else { *self - *other }
}
#[inline]
fn signum(&self) -> $t {
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 }
}
)*)
}
signed_impl!(isize i8 i16 i32 i64);
impl<T: Signed> Signed for Wrapping<T> where Wrapping<T>: Num + Neg<Output=Wrapping<T>>
{
#[inline]
fn abs(&self) -> Self {
Wrapping(self.0.abs())
}
#[inline]
fn abs_sub(&self, other: &Self) -> Self {
Wrapping(self.0.abs_sub(&other.0))
}
#[inline]
fn signum(&self) -> Self {
Wrapping(self.0.signum())
}
#[inline]
fn is_positive(&self) -> bool { self.0.is_positive() }
#[inline]
fn is_negative(&self) -> bool { self.0.is_negative() }
}
macro_rules! signed_float_impl {
($t:ty, $nan:expr, $inf:expr, $neg_inf:expr) => {
impl Signed for $t {
#[inline]
#[cfg(feature = "std")]
fn abs(&self) -> $t {
(*self).abs()
}
#[inline]
#[cfg(not(feature = "std"))]
fn abs(&self) -> $t {
if self.is_positive() {
*self
} else if self.is_negative() {
-*self
} else {
$nan
}
}
#[inline]
fn abs_sub(&self, other: &$t) -> $t {
if *self <= *other { 0. } else { *self - *other }
}
#[inline]
#[cfg(feature = "std")]
fn signum(&self) -> $t {
use Float;
Float::signum(*self)
}
#[inline]
#[cfg(not(feature = "std"))]
fn signum(&self) -> $t {
if self.is_positive() {
1.0
} else if self.is_negative() {
-1.0
} else {
$nan
}
}
#[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 }
}
}
}
signed_float_impl!(f32, f32::NAN, f32::INFINITY, f32::NEG_INFINITY);
signed_float_impl!(f64, f64::NAN, f64::INFINITY, f64::NEG_INFINITY);
#[inline(always)]
pub fn abs<T: Signed>(value: T) -> T {
value.abs()
}
#[inline(always)]
pub fn abs_sub<T: Signed>(x: T, y: T) -> T {
x.abs_sub(&y)
}
#[inline(always)] pub fn signum<T: Signed>(value: T) -> T { value.signum() }
pub trait Unsigned: Num {}
macro_rules! empty_trait_impl {
($name:ident for $($t:ty)*) => ($(
impl $name for $t {}
)*)
}
empty_trait_impl!(Unsigned for usize u8 u16 u32 u64);
impl<T: Unsigned> Unsigned for Wrapping<T> where Wrapping<T>: Num {}
#[test]
fn unsigned_wrapping_is_unsigned() {
fn require_unsigned<T: Unsigned>(_: &T) {}
require_unsigned(&Wrapping(42_u32));
}