use core::num::Wrapping;
use core::ops::Neg;
use crate::Num;
use crate::float::FloatCore;
c0nst::c0nst! {
pub c0nst trait Signum: Sized {
type Output;
fn signum(self) -> Self::Output;
}
}
c0nst::c0nst! {
pub c0nst trait Signed: Sized + [c0nst] Num + [c0nst] Neg + [c0nst] Signum {
fn abs(self) -> <Self as Neg>::Output;
fn abs_sub(self, other: Self) -> <Self as Neg>::Output;
fn is_positive(self) -> bool;
fn is_negative(self) -> bool;
}
}
macro_rules! signed_impl {
($($t:ty)*) => ($(
c0nst::c0nst! {
c0nst impl Signum for $t {
type Output = $t;
#[inline]
fn signum(self) -> $t {
match self {
n if n > 0 => 1,
0 => 0,
_ => -1,
}
}
}
}
c0nst::c0nst! {
c0nst impl Signed for $t {
#[inline]
fn abs(self) -> $t {
self.saturating_abs()
}
#[inline]
fn abs_sub(self, other: $t) -> $t {
if self <= other { 0 } else { self.saturating_sub(other) }
}
#[inline]
fn is_positive(self) -> bool { self > 0 }
#[inline]
fn is_negative(self) -> bool { self < 0 }
}
}
)*)
}
signed_impl!(isize i8 i16 i32 i64 i128);
impl<T: Signum<Output = T>> Signum for Wrapping<T> {
type Output = Wrapping<T>;
#[inline]
fn signum(self) -> Self {
Wrapping(self.0.signum())
}
}
impl<T: Signed + Neg<Output = T> + Signum<Output = T>> 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 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) => {
impl Signum for $t {
type Output = $t;
#[inline]
fn signum(self) -> $t {
FloatCore::signum(self)
}
}
impl Signed for $t {
#[inline]
fn abs(self) -> $t {
FloatCore::abs(self)
}
#[inline]
fn abs_sub(self, other: $t) -> $t {
if self <= other { 0. } else { self - other }
}
#[inline]
fn is_positive(self) -> bool {
FloatCore::is_sign_positive(self)
}
#[inline]
fn is_negative(self) -> bool {
FloatCore::is_sign_negative(self)
}
}
};
}
signed_float_impl!(f32);
signed_float_impl!(f64);
c0nst::c0nst! {
#[inline(always)]
pub c0nst fn abs<T: [c0nst] Signed + [c0nst] Neg<Output = T> + [c0nst] Destruct>(value: T) -> T {
value.abs()
}
}
c0nst::c0nst! {
#[inline(always)]
pub c0nst fn abs_sub<T: [c0nst] Signed + [c0nst] Neg<Output = T> + [c0nst] Destruct>(x: T, y: T) -> T {
x.abs_sub(y)
}
}
c0nst::c0nst! {
#[inline(always)]
pub c0nst fn signum<T: [c0nst] Signed + [c0nst] Signum<Output = T> + [c0nst] Destruct>(value: T) -> T {
value.signum()
}
}
c0nst::c0nst! {
pub c0nst trait Unsigned: [c0nst] Num {}
}
macro_rules! empty_trait_impl {
($name:ident for $($t:ty)*) => ($(
c0nst::c0nst! {
c0nst impl $name for $t {}
}
)*)
}
empty_trait_impl!(Unsigned for usize u8 u16 u32 u64 u128);
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));
}
#[test]
fn signed_wrapping_is_signed() {
fn require_signed<T: Signed>(_: &T) {}
require_signed(&Wrapping(-42));
}
#[test]
fn abs_is_total_and_non_negative() {
assert_eq!(Signed::abs(-7i32), 7);
assert_eq!(Signed::abs(7i32), 7);
assert_eq!(Signed::abs(0i32), 0);
assert_eq!(Signed::abs(i8::MIN), i8::MAX);
assert_eq!(Signed::abs(i32::MIN), i32::MAX);
assert_eq!(Signed::abs(i64::MIN), i64::MAX);
assert_eq!(Signed::abs_sub(i32::MAX, i32::MIN), i32::MAX);
assert_eq!(Signed::abs_sub(5i32, 8), 0);
assert_eq!(Signed::abs_sub(8i32, 5), 3);
}