use crate::Ordering::{self, Equal, Greater, Less};
#[allow(unused_imports)]
use crate::{is, paste};
#[allow(unused_imports)]
#[cfg(nightly_float)]
use ::core::{f16, f128};
#[doc = crate::_tags!(logic namespace)]
#[doc = crate::_doc_location!("num/fin/ord")]
#[repr(transparent)]
pub struct Cmp<T>(pub T);
crate::_impl_init![ConstInit: <T: ConstInit> Self(T::INIT) => Cmp<T>];
#[rustfmt::skip]
mod core_impls {
use {super::{Cmp, Ordering}, core::fmt};
impl<T: Clone> Clone for Cmp<T> { fn clone(&self) -> Self { Self(self.0.clone()) } }
impl<T: Copy> Copy for Cmp<T> {}
impl<T: PartialEq> PartialEq for Cmp<T> {
fn eq(&self, other: &Self) -> bool { self.0.eq(&other.0) }
}
impl<T: Eq> Eq for Cmp<T> {}
impl<T: PartialOrd> PartialOrd for Cmp<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { self.0.partial_cmp(&other.0) }
}
impl<T: Ord> Ord for Cmp<T> {
fn cmp(&self, other: &Self) -> Ordering { self.0.cmp(&other.0) }
}
impl<T: fmt::Display> fmt::Display for Cmp<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
}
impl<T: fmt::Debug> fmt::Debug for Cmp<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("Cmp").field(&self.0).finish()
}
}
}
#[rustfmt::skip]
impl<T: PartialOrd> Cmp<T> {
#[must_use]
pub fn pclamp(self, min: T, max: T) -> Option<T> {
match self.0.partial_cmp(&min) {
Some(Less) => Some(min),
Some(Greater | Equal) => match self.0.partial_cmp(&max) {
Some(Greater) => Some(max),
Some(Less | Equal) => Some(self.0),
None => None,
},
None => None,
}
}
#[must_use]
pub fn pmax(self, other: T) -> Option<T> {
match self.0.partial_cmp(&other) {
Some(Less) => Some(other),
Some(Greater | Equal) => Some(self.0),
None => None,
}
}
#[must_use]
pub fn pmin(self, other: T) -> Option<T> {
match self.0.partial_cmp(&other) {
Some(Greater) => Some(other),
Some(Less | Equal) => Some(self.0),
None => None,
}
}
#[must_use]
pub fn pminmax(self, other: T) -> Option<(T, T)> {
match self.0.partial_cmp(&other) {
Some(Less | Equal) => Some((self.0, other)),
Some(Greater) => Some((other, self.0)),
None => None,
}
}
}
macro_rules! impl_comparing {
() => {
impl_comparing![int: u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize];
impl_comparing![float: f32:32:31, f64:64:63];
#[cfg(nightly_float)]
impl_comparing![float: f16:16:15, f128:128:127];
};
(
// $p: the integer type
// $cap: the optional capability feature associated with the `$p` type. E.g "_cmp_u8".
int: $($p:ty $(: $cap:literal)? ),+ $(,)?) => { $( impl_comparing![@int: $p $(:$cap)? ]; )+ };
(@int: $p:ty $(: $cap:literal)? ) => {
$( #[cfg(feature = $cap)] )?
impl Cmp<$p> {
#[must_use]
pub const fn total_cmp(self, other: $p) -> Ordering {
is![self.0 < other, Less, is![self.0 > other, Greater, Equal]]
}
#[must_use] #[inline(always)]
pub const fn clamp(self, min: $p, max: $p) -> $p {
if self.0 < min { min } else if self.0 > max { max } else { self.0 }
}
#[must_use] #[inline(always)]
pub const fn max(self, other: $p) -> $p { if self.0 > other { self.0 } else { other } }
#[must_use] #[inline(always)]
pub const fn min(self, other: $p) -> $p { if self.0 < other { self.0 } else { other } }
#[must_use] #[inline(always)]
pub const fn minmax(self, other: $p) -> ($p, $p) {
if self.0 < other { (self.0, other) } else { (other, self.0) }
}
#[must_use] #[inline(always)]
pub const fn eq(self, other: $p) -> bool { self.0 == other }
#[must_use] #[inline(always)]
pub const fn ne(self, other: $p) -> bool { self.0 != other }
#[must_use] #[inline(always)]
pub const fn lt(self, other: $p) -> bool { self.0 < other }
#[must_use] #[inline(always)]
pub const fn le(self, other: $p) -> bool { self.0 <= other }
#[must_use] #[inline(always)]
pub const fn gt(self, other: $p) -> bool { self.0 > other }
#[must_use] #[inline(always)]
pub const fn ge(self, other: $p) -> bool { self.0 >= other }
}
};
(
float: $($f:ty:$b:literal:$sh:literal $(:$fcap:literal )? ),+ $(,)?) => {
$( impl_comparing![@float: $f:$b:$sh $(:$fcap)?]; )+
};
(@float: $f:ty:$b:literal:$sh:literal $( :$fcap:literal )?) => { paste! {
$( #[cfg(feature = $fcap)] )?
impl Cmp<$f> {
#[doc = "A (`const`) port of `" $f "::`[`total_cmp`][prim@" $f "#method.total_cmp]."]
#[must_use]
pub const fn total_cmp(self, other: $f) -> Ordering {
let mut left = self.0.to_bits() as [<i $b>];
let mut right = other.to_bits() as [<i $b>];
left ^= (((left >> $sh) as [<u $b>]) >> 1) as [<i $b>];
right ^= (((right >> $sh) as [<u $b>]) >> 1) as [<i $b>];
is![left < right, Less, is![left > right, Greater, Equal]]
}
#[cfg_attr(nightly_float, doc = "# #![feature(f16, f128)]")]
#[doc = "assert_eq![2.0, Cmp(5.0" $f ").clamp(-1.0, 2.0)];"]
#[doc = "assert_eq![-1.0, Cmp(-5.0" $f ").clamp(-1.0, 2.0)];"]
#[must_use] #[inline(always)]
pub const fn clamp(self, min: $f, max: $f) -> $f { self.0.clamp(min, max) }
#[cfg_attr(nightly_float, doc = "# #![feature(f16, f128)]")]
#[doc = "assert_eq![2.0, Cmp(2.0" $f ").max(-1.0)];"]
#[doc = "assert_eq![2.0, Cmp(1.0" $f ").max(2.0)];"]
#[doc = "assert_eq![0.0, Cmp(-0.0" $f ").max(0.0)];"]
#[doc = "assert_eq![" $f "::INFINITY, Cmp(" $f "::INFINITY).max("
$f "::NEG_INFINITY)];"]
#[must_use] #[inline(always)]
pub const fn max(self, other: $f) -> $f { self.0.max(other) }
#[cfg_attr(nightly_float, doc = "# #![feature(f16, f128)]")]
#[doc = "assert_eq![-1.0, Cmp(2.0" $f ").min(-1.0)];"]
#[doc = "assert_eq![1.0, Cmp(1.0" $f ").min(2.0)];"]
#[doc = "assert_eq![-0.0, Cmp(-0.0" $f ").min(0.0)];"]
#[doc = "assert_eq![" $f "::NEG_INFINITY, Cmp(" $f "::INFINITY).min("
$f "::NEG_INFINITY)];"]
#[must_use] #[inline(always)]
pub const fn min(self, other: $f) -> $f { self.0.min(other) }
#[must_use] #[inline(always)]
pub const fn eq(self, other: $f) -> bool { Cmp(self.total_cmp(other)).eq(Equal) }
#[must_use] #[inline(always)]
pub const fn ne(self, other: $f) -> bool { Cmp(self.total_cmp(other)).ne(Equal) }
#[must_use] #[inline(always)]
pub const fn lt(self, other: $f) -> bool { Cmp(self.total_cmp(other)).eq(Less) }
#[must_use] #[inline(always)]
pub const fn le(self, other: $f) -> bool { Cmp(self.total_cmp(other)).ne(Greater) }
#[must_use] #[inline(always)]
pub const fn gt(self, other: $f) -> bool { Cmp(self.total_cmp(other)).eq(Greater) }
#[must_use] #[inline(always)]
pub const fn ge(self, other:$f) -> bool { Cmp(self.total_cmp(other)).ne(Less) }
#[must_use] #[inline(always)]
pub const fn is_positive(self) -> bool { self.0.is_sign_positive() }
#[must_use] #[inline(always)]
pub const fn is_negative(self) -> bool { self.0.is_sign_negative() }
#[must_use] #[inline(always)]
pub const fn is_infinite(self) -> bool { self.0.is_infinite() }
#[must_use] #[inline(always)]
pub const fn is_finite(self) -> bool { self.0.is_finite() }
#[must_use] #[inline(always)]
pub const fn is_nan(self) -> bool { self.0.is_nan() }
#[must_use] #[inline(always)]
pub const fn is_subnormal(self) -> bool { self.0.is_subnormal() }
#[must_use] #[inline(always)]
pub const fn is_normal(self) -> bool { self.0.is_normal() }
}
}};
}
impl_comparing!();
#[rustfmt::skip]
impl Cmp<Ordering> {
#[must_use]
pub const fn total_cmp(self, other: Ordering) -> Ordering {
if (self.0 as i8) < other as i8 { Less }
else if (self.0 as i8) > other as i8 { Greater }
else { Equal }
}
#[must_use]
pub const fn clamp(self, min: Ordering, max: Ordering) -> Ordering {
if (self.0 as i8) < min as i8 { min }
else if self.0 as i8 > max as i8 { max }
else { self.0 }
}
#[must_use]
pub const fn max(self, other: Ordering) -> Ordering {
if self.0 as i8 > other as i8 { self.0 } else { other }
}
#[must_use]
pub const fn min(self, other: Ordering) -> Ordering {
if (self.0 as i8) < other as i8 { self.0 } else { other }
}
#[must_use]
pub const fn eq(self, other: Ordering) -> bool { self.0 as i8 == other as i8 }
#[must_use]
pub const fn ne(self, other: Ordering) -> bool { self.0 as i8 != other as i8 }
#[must_use]
pub const fn lt(self, other: Ordering) -> bool { (self.0 as i8) < other as i8 }
#[must_use]
pub const fn le(self, other: Ordering) -> bool { self.0 as i8 <= other as i8 }
#[must_use]
pub const fn gt(self, other: Ordering) -> bool { self.0 as i8 > other as i8 }
#[must_use]
pub const fn ge(self, other: Ordering) -> bool { self.0 as i8 >= other as i8 }
}