#![no_std]
#![warn(
invalid_html_tags,
missing_debug_implementations,
trivial_casts,
unused_lifetimes,
unused_import_braces
)]
#![deny(missing_docs, unaligned_references)]
use core::cmp::Ordering;
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct NumOrd<T>(pub T);
macro_rules! common_type_impl_body {
($Lhs:ty, $Rhs:ty, $CommonT:ty, $lhs:expr, $rhs:expr, $op:ident, $less:expr, $greater:expr, $nan:expr) => {{
($lhs as $CommonT).$op(&($rhs as $CommonT))
}};
}
macro_rules! int_float_impl_body {
($IntT:ty, $FloatT:ty, $_UnusedT:ty, $lhs:expr, $rhs:expr, $op:ident, $less:expr, $greater:expr, $nan:expr) => {{
let lhs = $lhs;
let rhs = $rhs;
const FLOAT_DENSE_INT_MIN: $IntT =
(0 as $IntT).saturating_sub(1) << <$FloatT>::MANTISSA_DIGITS;
const FLOAT_DENSE_INT_MAX: $IntT = 1 << <$FloatT>::MANTISSA_DIGITS;
const INT_MAX_POWER_OF_TWO: $IntT = <$IntT>::MAX ^ (<$IntT>::MAX >> 1);
const INT_ONE_ABOVE_MAX_AS_FLOAT: $FloatT = 2.0 * (INT_MAX_POWER_OF_TWO as $FloatT);
if FLOAT_DENSE_INT_MIN <= lhs && lhs <= FLOAT_DENSE_INT_MAX {
(lhs as $FloatT).$op(&rhs)
} else if INT_ONE_ABOVE_MAX_AS_FLOAT <= rhs {
$less
} else if <$IntT>::MIN as $FloatT > rhs {
$greater
} else if rhs.is_nan() {
$nan
} else {
lhs.$op(&(rhs as $IntT))
}
}};
}
macro_rules! int_uint_impl_body {
($IntT:ty, $UintT:ty, $_UnusedT:ty, $lhs:expr, $rhs:expr, $op:ident, $less:expr, $greater:expr, $nan:expr) => {{
let lhs = $lhs;
let rhs = $rhs;
if lhs < 0 {
$less
} else {
(lhs as $UintT).$op(&rhs)
}
}};
}
macro_rules! apply_impl_body {
($impl_body:ident, $Lhs:ty, $Rhs:ty, $CommonT:ty) => {
impl PartialEq<NumOrd<$Rhs>> for NumOrd<$Lhs> {
fn eq(&self, other: &NumOrd<$Rhs>) -> bool {
$impl_body!($Lhs, $Rhs, $CommonT, self.0, other.0, eq, false, false, false)
}
}
impl PartialOrd<NumOrd<$Rhs>> for NumOrd<$Lhs> {
fn partial_cmp(&self, other: &NumOrd<$Rhs>) -> Option<Ordering> {
$impl_body!(
$Lhs,
$Rhs,
$CommonT,
self.0,
other.0,
partial_cmp,
Some(Ordering::Less),
Some(Ordering::Greater),
None
)
}
fn lt(&self, other: &NumOrd<$Rhs>) -> bool {
$impl_body!($Lhs, $Rhs, $CommonT, self.0, other.0, lt, true, false, false)
}
fn le(&self, other: &NumOrd<$Rhs>) -> bool {
$impl_body!($Lhs, $Rhs, $CommonT, self.0, other.0, le, true, false, false)
}
fn gt(&self, other: &NumOrd<$Rhs>) -> bool {
$impl_body!($Lhs, $Rhs, $CommonT, self.0, other.0, gt, false, true, false)
}
fn ge(&self, other: &NumOrd<$Rhs>) -> bool {
$impl_body!($Lhs, $Rhs, $CommonT, self.0, other.0, ge, false, true, false)
}
}
impl PartialEq<NumOrd<$Lhs>> for NumOrd<$Rhs> {
fn eq(&self, other: &NumOrd<$Lhs>) -> bool {
other == self
}
}
impl PartialOrd<NumOrd<$Lhs>> for NumOrd<$Rhs> {
fn partial_cmp(&self, other: &NumOrd<$Lhs>) -> Option<Ordering> {
other.partial_cmp(self).map(|o| o.reverse())
}
fn lt(&self, other: &NumOrd<$Lhs>) -> bool {
other > self
}
fn le(&self, other: &NumOrd<$Lhs>) -> bool {
other >= self
}
fn gt(&self, other: &NumOrd<$Lhs>) -> bool {
other < self
}
fn ge(&self, other: &NumOrd<$Lhs>) -> bool {
other <= self
}
}
};
}
apply_impl_body!(int_float_impl_body, i64, f32, ());
apply_impl_body!(int_float_impl_body, i128, f32, ());
apply_impl_body!(int_float_impl_body, i64, f64, ());
apply_impl_body!(int_float_impl_body, i128, f64, ());
apply_impl_body!(int_float_impl_body, u64, f32, ());
apply_impl_body!(int_float_impl_body, u128, f32, ());
apply_impl_body!(int_float_impl_body, u64, f64, ());
apply_impl_body!(int_float_impl_body, u128, f64, ());
apply_impl_body!(int_uint_impl_body, i8, u128, ());
apply_impl_body!(int_uint_impl_body, i16, u128, ());
apply_impl_body!(int_uint_impl_body, i32, u128, ());
apply_impl_body!(int_uint_impl_body, i64, u128, ());
apply_impl_body!(int_uint_impl_body, i128, u128, ());
macro_rules! impl_common_type {
($($T:ty, $U:ty => $C:ty;)*) => {$(
apply_impl_body!(common_type_impl_body, $T, $U, $C);
)*}
}
impl_common_type! {
u8, i8 => i16;
u8, u16 => u16;
u8, i16 => i16;
u8, u32 => u32;
u8, i32 => i32;
u8, u64 => u64;
u8, i64 => i64;
u8, u128 => u128;
u8, i128 => i128;
u8, f32 => f32;
u8, f64 => f64;
i8, u16 => i32;
i8, i16 => i16;
i8, u32 => i64;
i8, i32 => i32;
i8, u64 => i128;
i8, i64 => i64;
i8, i128 => i128;
i8, f32 => f32;
i8, f64 => f64;
u16, i16 => i32;
u16, u32 => u32;
u16, i32 => i32;
u16, u64 => u64;
u16, i64 => i64;
u16, u128 => u128;
u16, i128 => i128;
u16, f32 => f32;
u16, f64 => f64;
i16, u32 => i64;
i16, i32 => i32;
i16, u64 => i128;
i16, i64 => i64;
i16, i128 => i128;
i16, f32 => f32;
i16, f64 => f64;
u32, i32 => i64;
u32, u64 => u64;
u32, i64 => i64;
u32, u128 => u128;
u32, i128 => i128;
u32, f32 => f64;
u32, f64 => f64;
i32, u64 => i128;
i32, i64 => i64;
i32, i128 => i128;
i32, f32 => f64;
i32, f64 => f64;
u64, i64 => i128;
u64, u128 => u128;
u64, i128 => i128;
i64, i128 => i128;
f32, f64 => f64;
}