use crate::error::NumeraResult;
use core::num::{
NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize,
};
pub trait Sign {
fn can_positive(&self) -> bool;
fn can_negative(&self) -> bool;
fn is_positive(&self) -> bool;
fn is_negative(&self) -> bool;
}
pub trait Signed: Positive + Negative {}
pub trait Unsigned: Positive + NonNegative {}
pub trait Positive: Sign {}
pub trait Negative: Sign {}
pub trait NonNegative: Sign {}
pub trait NonPositive: Sign {
type InnerRepr;
fn new_neg(value: Self::InnerRepr) -> NumeraResult<Self>
where
Self: Sized;
}
impl<T: Positive + Negative> Signed for T {}
impl<T: Positive + NonNegative> Unsigned for T {}
macro_rules! impl_sign {
(many_signed_prim: $($t:ty),+) => {
$( impl_sign![signed_prim: $t]; )+
};
(signed_prim: $t:ty) => {
impl Sign for $t {
fn can_negative(&self) -> bool { true }
fn can_positive(&self) -> bool { true }
fn is_negative(&self) -> bool { <$t>::is_negative(*self) }
fn is_positive(&self) -> bool { <$t>::is_positive(*self) }
}
impl $crate::all::Positive for $t {}
impl $crate::all::Negative for $t {}
};
(many_signed_float: $($t:ty, $zero:expr),+) => {
$( impl_sign![signed_float: $t, $zero]; )+
};
(signed_float: $t:ty, $zero:expr) => {
impl Sign for $t {
fn can_negative(&self) -> bool { true }
fn can_positive(&self) -> bool { true }
fn is_negative(&self) -> bool { self.is_sign_negative() && *self != $zero }
fn is_positive(&self) -> bool { self.is_sign_positive() && *self != $zero }
}
impl $crate::all::Positive for $t {}
impl $crate::all::Negative for $t {}
};
(many_signed_nonzero: $($t:ty),+) => {
$( impl_sign![signed_nonzero: $t]; )+
};
(signed_nonzero: $t:ty) => {
impl Sign for $t {
fn can_negative(&self) -> bool { true }
fn can_positive(&self) -> bool { true }
fn is_negative(&self) -> bool { self.get().is_negative() }
fn is_positive(&self) -> bool { self.get().is_positive() }
}
impl $crate::all::Positive for $t {}
impl $crate::all::Negative for $t {}
};
(many_unsigned_prim: $($t:ty),+) => {
$( impl_sign![unsigned_prim: $t]; )+
};
(unsigned_prim: $t:ty) => {
impl Sign for $t {
fn can_negative(&self) -> bool { false }
fn can_positive(&self) -> bool { true }
fn is_negative(&self) -> bool { false }
fn is_positive(&self) -> bool { *self != 0 }
}
impl $crate::all::Positive for $t {}
impl $crate::all::NonNegative for $t {}
};
(many_unsigned_nonzero: $($t:ty),+) => {
$( impl_sign![unsigned_nonzero: $t]; )+
};
(unsigned_nonzero: $t:ty) => {
impl Sign for $t {
fn can_negative(&self) -> bool { false }
fn can_positive(&self) -> bool { true }
fn is_negative(&self) -> bool { false }
fn is_positive(&self) -> bool { true } }
impl $crate::all::Positive for $t {}
impl $crate::all::NonNegative for $t {}
};
}
impl_sign![many_signed_prim: i8, i16, i32, i64, i128, isize];
impl_sign![many_unsigned_prim: u8, u16, u32, u64, u128, usize];
impl_sign![many_signed_float: f32, 0.0, f64, 0.0];
#[rustfmt::skip]
impl_sign![many_signed_nonzero:
NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize];
#[rustfmt::skip]
impl_sign![many_unsigned_nonzero:
NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize];
#[cfg(feature = "dashu-int")]
#[rustfmt::skip]
mod impl_big {
use super::{Sign, Positive, Negative, NonNegative};
use dashu_int::{IBig, UBig};
impl Sign for IBig {
fn can_negative(&self) -> bool { true }
fn can_positive(&self) -> bool { true }
fn is_negative(&self) -> bool { *self < IBig::from(0u8) }
fn is_positive(&self) -> bool { *self > IBig::from(0u8) }
}
impl Positive for IBig {}
impl Negative for IBig {}
impl Sign for UBig {
fn can_negative(&self) -> bool { false }
fn can_positive(&self) -> bool { true }
fn is_negative(&self) -> bool { false }
fn is_positive(&self) -> bool { *self != UBig::from(0u8) }
}
impl Positive for UBig {}
impl NonNegative for UBig {}
}
#[cfg(feature = "twofloat")]
mod impl_twofloat {
use super::Sign;
use twofloat::TwoFloat;
impl_sign![signed_float: TwoFloat, TwoFloat::from_f64(0.0)];
}
#[cfg(feature = "half")]
mod impl_half {
use super::Sign;
use half::{bf16, f16};
impl_sign![many_signed_float: f16, f16::ZERO, bf16, bf16::ZERO];
}