#![warn(missing_docs)]
use batbox_range::*;
pub use std::cmp::{max, min};
pub trait MinMax: Sized {
type T;
fn min_max(self) -> (Self::T, Self::T);
fn min(self) -> Self::T {
self.min_max().0
}
fn max(self) -> Self::T {
self.min_max().1
}
}
impl<T: Ord> MinMax for (T, T) {
type T = T;
fn min_max(self) -> (T, T) {
let (a, b) = self;
if a.cmp(&b) == std::cmp::Ordering::Less {
(a, b)
} else {
(b, a)
}
}
}
pub fn min_max<T: Ord>(a: T, b: T) -> (T, T) {
(a, b).min_max()
}
pub trait PartialMinMax: Sized {
type T;
fn partial_min_max(self) -> (Self::T, Self::T);
fn partial_min(self) -> Self::T {
self.partial_min_max().0
}
fn partial_max(self) -> Self::T {
self.partial_min_max().1
}
}
impl<T: PartialOrd> PartialMinMax for (T, T) {
type T = T;
fn partial_min_max(self) -> (T, T) {
let (a, b) = self;
if a.partial_cmp(&b) == Some(std::cmp::Ordering::Less) {
(a, b)
} else {
(b, a)
}
}
}
pub fn partial_min<T: PartialOrd>(a: T, b: T) -> T {
(a, b).partial_min()
}
pub fn partial_max<T: PartialOrd>(a: T, b: T) -> T {
(a, b).partial_max()
}
pub fn partial_min_max<T: PartialOrd>(a: T, b: T) -> (T, T) {
(a, b).partial_min_max()
}
pub trait Clamp: Sized + PartialOrd {
fn clamp_range(mut self, range: impl FixedRangeBounds<Self>) -> Self
where
Self: Clone,
{
match range.start_bound() {
FixedBound::Included(start) => self = partial_max(self, start.clone()),
FixedBound::Unbounded => (),
}
match range.end_bound() {
FixedBound::Included(end) => self = partial_min(self, end.clone()),
FixedBound::Unbounded => (),
}
self
}
fn clamp_abs(self, max: Self) -> Self
where
Self: std::ops::Neg<Output = Self> + Copy,
{
self.clamp_range(-max..=max)
}
fn clamp_max(self, max: Self) -> Self {
partial_min(self, max)
}
fn clamp_min(self, min: Self) -> Self {
partial_max(self, min)
}
}
impl<T: PartialOrd> Clamp for T {}