use core::num::{
NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize,
};
pub trait Bound {
fn is_lower_bounded(&self) -> bool;
fn is_upper_bounded(&self) -> bool;
fn lower_bound(&self) -> Option<Self>
where
Self: Sized;
fn upper_bound(&self) -> Option<Self>
where
Self: Sized;
}
pub trait Bounded: LowerBounded + UpperBounded {}
pub trait LowerBounded: Bound {
fn new_min() -> Self;
}
pub trait UpperBounded: Bound {
fn new_max() -> Self;
}
pub trait ConstBounded: ConstLowerBounded + ConstUpperBounded {}
pub trait ConstLowerBounded: Bound {
const MIN: Self;
}
pub trait ConstUpperBounded: Bound {
const MAX: Self;
}
pub trait NonLowerBounded: Bound {}
pub trait NonUpperBounded: Bound {}
pub trait NonBounded: NonLowerBounded + NonUpperBounded {}
macro_rules! impl_bounded {
(many_both: $($t:ty),+) => {
$( impl_bounded![both: $t]; )+
};
(both: $t:ty) => {
impl Bound for $t {
fn is_lower_bounded(&self) -> bool { true }
fn is_upper_bounded(&self) -> bool { true }
fn lower_bound(&self) -> Option<Self> where Self: Sized { Some(<$t>::MIN) }
fn upper_bound(&self) -> Option<Self> where Self: Sized { Some(<$t>::MAX) }
}
impl ConstLowerBounded for $t { const MIN: Self = <$t>::MIN; }
impl LowerBounded for $t { fn new_min() -> Self { <$t>::MIN }}
impl ConstUpperBounded for $t { const MAX: Self = <$t>::MAX; }
impl UpperBounded for $t { fn new_max() -> Self { <$t>::MAX }}
};
}
macro_rules! impl_bounded_nonzero {
(many_both: $($t:ty, $lb:expr, $ub:expr),+) => {
$( impl_bounded_nonzero![both: $t, $lb, $ub]; )+
};
(both: $t:ty, $lb:expr, $ub:expr) => {
impl Bound for $t {
fn is_lower_bounded(&self) -> bool { true }
fn is_upper_bounded(&self) -> bool { true }
fn lower_bound(&self) -> Option<Self> { Some(<$t as ConstLowerBounded>::MIN) }
fn upper_bound(&self) -> Option<Self> { Some(<$t as ConstUpperBounded>::MAX) }
}
impl ConstLowerBounded for $t {
#[cfg(feature = "safe")]
const MIN: Self = if let Some(n) = <$t>::new($lb)
{ n } else { unreachable!() };
#[cfg(not(feature = "safe"))]
const MIN: Self = unsafe { <$t>::new_unchecked($lb) };
}
impl ConstUpperBounded for $t {
#[cfg(feature = "safe")]
const MAX: Self = if let Some(n) = <$t>::new($ub)
{ n } else { unreachable!() };
#[cfg(not(feature = "safe"))]
const MAX: Self = unsafe { <$t>::new_unchecked($ub) };
}
impl LowerBounded for $t {
fn new_min() -> Self {
#[cfg(feature = "safe")]
return <$t>::new($lb).unwrap();
#[cfg(not(feature = "safe"))]
return unsafe { <$t>::new_unchecked($lb) };
}
}
impl UpperBounded for $t {
fn new_max() -> Self {
#[cfg(feature = "safe")]
return <$t>::new($ub).unwrap();
#[cfg(not(feature = "safe"))]
return unsafe { <$t>::new_unchecked($ub) };
}
}
};
}
#[rustfmt::skip]
#[allow(unused_macros)]
macro_rules! impl_nonconst_bounded {
(only_lower: $t:ty, $b:expr) => {
impl Bound for $t {
fn is_lower_bounded(&self) -> bool { true }
fn is_upper_bounded(&self) -> bool { false }
fn lower_bound(&self) -> Option<Self> { Some($b) }
fn upper_bound(&self) -> Option<Self> { None }
}
impl LowerBounded for $t { fn new_min() -> Self { $b } }
impl NonUpperBounded for UBig {}
};
(only_upper: $t:ty, $b:expr) => {
impl Bound for $t {
fn is_lower_bounded(&self) -> bool { false }
fn is_upper_bounded(&self) -> bool { true }
fn lower_bound(&self) -> Option<Self> { None }
fn upper_bound(&self) -> Option<Self> { Some($b) }
}
impl UpperBounded for $t { fn new_max() -> Self { $b } }
impl NonLowerBounded for UBig {}
};
}
#[allow(unused_macros)]
macro_rules! impl_nonbounded {
($t:ty) => {
impl Bound for $t {
fn is_lower_bounded(&self) -> bool {
false
}
fn is_upper_bounded(&self) -> bool {
false
}
fn lower_bound(&self) -> Option<Self> {
None
}
fn upper_bound(&self) -> Option<Self> {
None
}
}
impl NonUpperBounded for $t {}
impl NonLowerBounded for $t {}
};
}
impl<T: LowerBounded + UpperBounded> Bounded for T {}
impl<T: ConstLowerBounded + ConstUpperBounded> ConstBounded for T {}
impl<T: NonLowerBounded + NonUpperBounded> NonBounded for T {}
#[rustfmt::skip]
impl_bounded![many_both:
f32, f64, i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize];
#[rustfmt::skip]
impl_bounded_nonzero![many_both:
NonZeroU8, 1, u8::MAX, NonZeroU16, 1, u16::MAX, NonZeroU32, 1, u32::MAX,
NonZeroU64, 1, u64::MAX, NonZeroU128, 1, u128::MAX, NonZeroUsize, 1, usize::MAX,
NonZeroI8, i8::MIN, i8::MAX, NonZeroI16, i16::MIN, i16::MAX,
NonZeroI32, i32::MIN, i32::MAX, NonZeroI64, i64::MIN, i64::MAX,
NonZeroI128, i128::MIN, i128::MAX, NonZeroIsize, isize::MIN, isize::MAX
];
#[cfg(feature = "twofloat")]
impl_bounded![both: twofloat::TwoFloat];
#[cfg(feature = "half")]
impl_bounded![many_both: half::bf16, half::f16];
#[cfg(feature = "dashu-int")]
mod impl_big {
use super::*;
use dashu_int::{IBig, UBig};
impl_nonconst_bounded![only_lower: UBig, UBig::from(0u8)];
impl_nonbounded![IBig];
}