use super::multiplicative::IsNaN;
pub trait MinValue {
const MIN: Self;
}
pub trait MaxValue {
const MAX: Self;
}
pub trait Bounds: MinValue + MaxValue {}
impl<T: MinValue + MaxValue> Bounds for T {}
macro_rules! impl_bounds_value {
($($t:ty),* $(,)?) => {
$(
impl MinValue for $t {
const MIN: $t = <$t>::MIN;
}
impl MaxValue for $t {
const MAX: $t = <$t>::MAX;
}
)*
};
}
impl_bounds_value!(i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, f32, f64);
pub trait MinMax:PartialOrd{
fn min(self, other: Self) -> Self
where Self: Sized{
match self.partial_cmp(&other) {
Some(core::cmp::Ordering::Greater) => other,
_ => {
if self.is_nan() { 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_nan() { other }
else { self }
}
}
}
fn clamp(self,min:Self,max:Self) -> Self
where Self: Sized{
if(self.is_nan()){
return if (min.is_nan()) { max }
else if (max.is_nan()) { 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(value) => {Some(self.min(value))}
None => {None}
}
}
fn max_opt(self,other:Option<Self>)-> Option<Self>
where Self: Sized{
match other {
Some(value) => {Some(self.max(value))}
None => {None}
}
}
fn clamp_opt(self,min:Option<Self>,max:Option<Self>)-> Option<Self>
where Self: Sized{
match (min,max) {
(Some(min),Some(max)) => Some(self.clamp(min,max)),
(Some(min),None) => Some(self.max(min)),
(None,Some(max)) => Some(self.min(max)),
(None,None) => Some(self),
}
}
}
impl<T:MinMax> MinMax for Option<T>{
fn min(self, other: Option<T>) -> Option<T>
where Self: Sized,{
match (self, other) {
(Some(v1), Some(v2)) => Some(v1.min(v2)),
(Some(v1), None) => Some(v1),
(None, Some(v2)) => Some(v2),
(None, None) => None,
}
}
fn max(self, other: Option<T>) -> Option<T>
where Self: Sized,{
match (self, other) {
(Some(v1), Some(v2)) => Some(v1.max(v2)),
(Some(v1), None) => Some(v1),
(None, Some(v2)) => Some(v2),
(None, None) => None,
}
}
fn clamp(self, min: Option<T>, max: Option<T>) -> Option<T>
where Self: Sized,{
match self {
Some(v) => v.clamp_opt(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_min_max_ord!(i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize);
macro_rules! impl_min_max_float {
($($t:ty),*$(,)?) => {
$(
impl MinMax for $t {
fn min(self, other: Self) -> Self {
self.min(other)
}
fn max(self, other: Self) -> Self {
self.max(other)
}
}
)*
};
}
impl_min_max_float!(f32, f64);
#[cfg(test)]
macro_rules! min {
($first:expr $(, $rest:expr)* $(,)?) => {{
let mut min = $first;
$(
min = MinMax::min(min, $rest);
)*
min
}};
}
#[cfg(test)]
macro_rules! max {
($first:expr $(, $rest:expr)* $(,)?) => {{
let mut max = $first;
$(
max = MinMax::max(max, $rest);
)*
max
}};
}
#[cfg(test)]
mod test{
use super::*;
fn assert_f32_eq_or_nan(left: f32, right: f32) {
if left.is_nan() && right.is_nan() {
return;
}
assert_eq!(left, right);
}
fn assert_opt_f32_eq_or_nan(left: Option<f32>, right: Option<f32>) {
match (left, right) {
(None, None) => {}
(Some(a), Some(b)) => assert_f32_eq_or_nan(a, b),
_ => panic!("option mismatch"),
}
}
#[test]
fn test_min_macro(){
assert_eq!(
min!(4i32,3,2,1,0,-1,-2,-3,-4),
-4
)
}
#[test]
fn test_max_macro(){
assert_eq!(
max!(4,3,2,1,0,-1,-2,-3,-4),
4
)
}
#[test]
fn test_min_max_ord_values() {
assert_eq!(MinMax::min(5i32, 2), 2);
assert_eq!(MinMax::max(5i32, 2), 5);
assert_eq!(MinMax::clamp(5i32, 1, 3), 3);
assert_eq!(MinMax::clamp(2i32, 5, 1), 2); }
#[test]
fn test_min_max_float_with_nan() {
assert_f32_eq_or_nan(MinMax::min(1.0f32, f32::NAN), 1.0);
assert_f32_eq_or_nan(MinMax::min(f32::NAN, 1.0), 1.0);
assert!(MinMax::min(f32::NAN, f32::NAN).is_nan());
assert_f32_eq_or_nan(MinMax::max(1.0f32, f32::NAN), 1.0);
assert_f32_eq_or_nan(MinMax::max(f32::NAN, 1.0), 1.0);
assert!(MinMax::max(f32::NAN, f32::NAN).is_nan());
}
#[test]
fn test_clamp_float_with_nan_and_bounds() {
assert!(MinMax::clamp(f32::NAN, 0.0, 1.0).is_nan());
assert_f32_eq_or_nan(MinMax::clamp(f32::NAN, 0.0, f32::NAN), 0.0);
assert_f32_eq_or_nan(MinMax::clamp(f32::NAN, f32::NAN, 1.0), 1.0);
}
#[test]
fn test_min_opt_max_opt_clamp_opt_for_value() {
assert_opt_f32_eq_or_nan(3.0f32.min_opt(Some(1.0)), Some(1.0));
assert_opt_f32_eq_or_nan(3.0f32.min_opt(None), None);
assert_opt_f32_eq_or_nan(3.0f32.max_opt(Some(5.0)), Some(5.0));
assert_opt_f32_eq_or_nan(3.0f32.max_opt(None), None);
assert_opt_f32_eq_or_nan(3.0f32.clamp_opt(Some(1.0), Some(2.0)), Some(2.0));
assert_opt_f32_eq_or_nan(3.0f32.clamp_opt(Some(1.0), None), Some(3.0));
assert_opt_f32_eq_or_nan(3.0f32.clamp_opt(None, Some(2.0)), Some(2.0));
assert_opt_f32_eq_or_nan(3.0f32.clamp_opt(None, None), Some(3.0));
}
#[test]
fn test_option_min_max_clamp_with_option_rhs() {
assert_opt_f32_eq_or_nan(Some(3.0f32).min(Some(1.0)), Some(1.0));
assert_opt_f32_eq_or_nan(Some(3.0f32).min(None), Some(3.0));
assert_opt_f32_eq_or_nan(None::<f32>.min(Some(1.0)), Some(1.0));
assert_opt_f32_eq_or_nan(None::<f32>.min(None), None);
assert_opt_f32_eq_or_nan(Some(3.0f32).max(Some(5.0)), Some(5.0));
assert_opt_f32_eq_or_nan(Some(3.0f32).max(None), Some(3.0));
assert_opt_f32_eq_or_nan(None::<f32>.max(Some(5.0)), Some(5.0));
assert_opt_f32_eq_or_nan(None::<f32>.max(None), None);
assert_opt_f32_eq_or_nan(Some(3.0f32).clamp(Some(1.0), Some(2.0)), Some(2.0));
assert_opt_f32_eq_or_nan(Some(3.0f32).clamp(Some(1.0), None), Some(3.0));
assert_opt_f32_eq_or_nan(Some(3.0f32).clamp(None, Some(2.0)), Some(2.0));
assert_opt_f32_eq_or_nan(None::<f32>.clamp(Some(1.0), None), Some(1.0));
assert_opt_f32_eq_or_nan(None::<f32>.clamp(None, Some(2.0)), Some(2.0));
assert_opt_f32_eq_or_nan(None::<f32>.clamp(Some(1.0), Some(2.0)), None);
}
#[test]
fn test_option_with_nan_values() {
assert_opt_f32_eq_or_nan(Some(f32::NAN).min(Some(1.0)), Some(1.0));
assert_opt_f32_eq_or_nan(Some(1.0).min(Some(f32::NAN)), Some(1.0));
assert_opt_f32_eq_or_nan(Some(f32::NAN).max(Some(1.0)), Some(1.0));
assert_opt_f32_eq_or_nan(Some(1.0).max(Some(f32::NAN)), Some(1.0));
}
pub struct TestStruct<T>{
a:T,
}
impl<T:MinMax> TestStruct<T>{
fn max2(self, other:Self) -> T{
self.a.max(other.a)
}
}
}