pub trait MaybeNonCmpPair: PartialEq {}
pub trait NeverNonCmpPair: Eq {}
impl<T: Eq> NeverNonCmpPair for T {}
pub trait IsNonCmpPair: PartialOrd {
fn is_non_cmp_pair(&self, other: &Self) -> bool;
fn is_cmp_pair(&self, other: &Self) -> bool {
!self.is_non_cmp_pair(other)
}
}
impl<T: PartialOrd> IsNonCmpPair for T {
default fn is_non_cmp_pair(&self, other: &Self) -> bool {
self.partial_cmp(other).is_none()
}
}
pub trait MaybeNonCmpValue: PartialEq {}
pub trait NeverNonCmpValue: Eq {}
impl<T: Eq> NeverNonCmpValue for T {}
pub trait IsNonCmpValue: PartialEq {
fn is_non_cmp_value(&self) -> bool;
fn is_cmp_value(&self) -> bool {
!self.is_non_cmp_value()
}
}
impl<T: PartialEq> IsNonCmpValue for T {
default fn is_non_cmp_value(&self) -> bool {
self != self
}
}
impl MaybeNonCmpPair for f32 {}
impl MaybeNonCmpPair for f64 {}
impl MaybeNonCmpValue for f32 {}
impl MaybeNonCmpValue for f64 {}
impl IsNonCmpPair for f32 {
fn is_non_cmp_pair(&self, other: &Self) -> bool {
self.partial_cmp(other).is_none()
}
}
impl IsNonCmpPair for f64 {
fn is_non_cmp_pair(&self, other: &Self) -> bool {
self.partial_cmp(other).is_none()
}
}
impl IsNonCmpValue for f32 {
fn is_non_cmp_value(&self) -> bool {
f32::is_nan(*self)
}
}
impl IsNonCmpValue for f64 {
fn is_non_cmp_value(&self) -> bool {
f64::is_nan(*self)
}
}
pub trait MinValue {
const MIN: Self;
}
pub trait MaxValue {
const MAX: Self;
}
pub trait IsMinValue: MinValue + PartialEq {
fn is_min_value(&self) -> bool
where
Self: Sized,
{
self.eq(&Self::MIN)
}
}
pub trait IsMaxValue: MaxValue + PartialEq {
fn is_max_value(&self) -> bool
where
Self: Sized,
{
self.eq(&Self::MAX)
}
}
macro_rules! impl_min_max_value {
($($t:ty),* $(,)?) => {
$(
impl MinValue for $t {
const MIN: Self = <$t>::MIN;
}
impl MaxValue for $t {
const MAX: Self = <$t>::MAX;
}
)*
};
}
impl_min_max_value!(i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, f32, f64);
impl<T: MinValue + PartialEq> IsMinValue for T {}
impl<T: MaxValue + PartialEq> IsMaxValue for T {}
pub trait MinMax: PartialOrd + IsNonCmpValue {
fn min(self, other: Self) -> Self
where
Self: Sized,
{
match self.partial_cmp(&other) {
Some(core::cmp::Ordering::Greater) => other,
_ => {
if self.is_non_cmp_value() {
other
} else {
self
}
}
}
}
fn max(self, other: Self) -> Self
where
Self: Sized,
{
match self.partial_cmp(&other) {
Some(core::cmp::Ordering::Less) => other,
_ => {
if self.is_non_cmp_value() {
other
} else {
self
}
}
}
}
fn clamp(self, min: Self, max: Self) -> Self
where
Self: Sized,
{
if self.is_non_cmp_value() {
return if min.is_non_cmp_value() {
max
} else if max.is_non_cmp_value() {
min
} else {
self
};
}
if min <= max {
if self < min {
min
} else if self > max {
max
} else {
self
}
} else if self < max {
max
} else if self > min {
min
} else {
self
}
}
fn min_opt(self, other: Option<Self>) -> Option<Self>
where
Self: Sized,
{
match other {
Some(v) => Some(self.min(v)),
None => None,
}
}
fn max_opt(self, other: Option<Self>) -> Option<Self>
where
Self: Sized,
{
match other {
Some(v) => Some(self.max(v)),
None => None,
}
}
fn clamp_opt(self, min: Option<Self>, max: Option<Self>) -> Option<Self>
where
Self: Sized,
{
match (min, max) {
(Some(min_v), Some(max_v)) => Some(self.clamp(min_v, max_v)),
(Some(min_v), None) => Some(self.max(min_v)),
(None, Some(max_v)) => Some(self.min(max_v)),
(None, None) => Some(self),
}
}
}
impl<T: MinMax> MinMax for Option<T> {
fn min(self, other: Option<T>) -> Option<T> {
match (self, other) {
(Some(a), Some(b)) => Some(MinMax::min(a, b)),
(Some(a), None) => Some(a),
(None, Some(b)) => Some(b),
(None, None) => None,
}
}
fn max(self, other: Option<T>) -> Option<T> {
match (self, other) {
(Some(a), Some(b)) => Some(MinMax::max(a, b)),
(Some(a), None) => Some(a),
(None, Some(b)) => Some(b),
(None, None) => None,
}
}
fn clamp(self, min: Option<T>, max: Option<T>) -> Option<T> {
match self {
Some(v) => MinMax::clamp_opt(v, min, max),
None => match (min, max) {
(Some(min_v), None) => Some(min_v),
(None, Some(max_v)) => Some(max_v),
_ => None,
},
}
}
}
macro_rules! impl_min_max_ord {
($($t:ty),* $(,)?) => {
$(
impl MinMax for $t {
fn min(self, other: Self) -> Self {
if self < other { self } else { other }
}
fn max(self, other: Self) -> Self {
if self > other { self } else { other }
}
fn clamp(self, min: Self, max: Self) -> Self {
if min <= max {
if self < min {
min
} else if self > max {
max
} else {
self
}
} else if self < max {
max
} else if self > min {
min
} else {
self
}
}
}
impl MinMax for &$t {
fn min(self, other: Self) -> Self {
if self < other { self } else { other }
}
fn max(self, other: Self) -> Self {
if self > other { self } else { other }
}
fn clamp(self, min: Self, max: Self) -> Self {
if min <= max {
if self < min {
min
} else if self > max {
max
} else {
self
}
} else if self < max {
max
} else if self > min {
min
} else {
self
}
}
}
)*
};
}
macro_rules! impl_min_max_float {
($($t:ty),* $(,)?) => {
$(
impl MinMax for $t {
fn min(self, other: Self) -> Self {
<$t>::min(self, other)
}
fn max(self, other: Self) -> Self {
<$t>::max(self, other)
}
}
impl MinMax for &$t {
fn min(self, other: Self) -> Self {
if *self < *other { self } else { other }
}
fn max(self, other: Self) -> Self {
if *self > *other { self } else { other }
}
}
)*
};
}
impl_min_max_ord!(i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize);
impl_min_max_float!(f32, f64);