use std::ops::Sub;
pub type Rangef = InclusiveRange<f32>;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct InclusiveRange<T: Copy + PartialOrd + Sub> {
pub min: T,
pub max: T
}
pub const RANGE_0_1_F32: InclusiveRange<f32> = InclusiveRange { min: 0.0, max: 1.0 };
fn pomax<T: PartialOrd>(a: T, b: T) -> T {
if a > b { a } else { b }
}
fn pomin<T: PartialOrd>(a: T, b: T) -> T {
if a < b { a } else { b }
}
impl<T: Copy + PartialOrd + Sub<Output=T>> InclusiveRange<T> {
pub fn new(min: T, max: T) -> InclusiveRange<T> {
assert!(min <= max);
InclusiveRange { min: min, max: max }
}
pub fn from_sorting(a: T, b: T) -> InclusiveRange<T> {
if a <= b {
InclusiveRange { min: a, max: b }
}
else {
InclusiveRange { min: b, max: a }
}
}
pub fn empty(self) -> bool {
self.min == self.max
}
pub fn length(self) -> T {
self.max - self.min
}
pub fn expand(&mut self, other: InclusiveRange<T>) {
self.min = pomin(self.min, other.min);
self.max = pomax(self.max, other.max);
}
}
pub fn range_clamp<T: Copy + PartialOrd + Sub<Output=T>>
(a: InclusiveRange<T>, b: InclusiveRange<T>)
-> Option<InclusiveRange<T>> {
let min = pomax(a.min, b.min);
let max = pomin(a.max, b.max);
if min <= max {
Some(InclusiveRange::new(min, max))
}
else {
None
}
}
pub fn range_combine<T: Copy + PartialOrd + Sub<Output=T>>(a: InclusiveRange<T>,
b: InclusiveRange<T>)
-> InclusiveRange<T> {
InclusiveRange::new(pomin(a.min, b.min),
pomax(a.max, b.max))
}
#[test]
fn test_from_sorting() {
assert_eq!(InclusiveRange::from_sorting(0, 1),
InclusiveRange::new(0, 1));
assert_eq!(InclusiveRange::from_sorting(1, 1),
InclusiveRange::new(1, 1));
assert_eq!(InclusiveRange::from_sorting(1, 0),
InclusiveRange::new(0, 1));
}
#[test]
fn test_empty() {
assert_eq!(InclusiveRange::new(0, 1).empty(), false);
assert_eq!(InclusiveRange::new(0, 0).empty(), true);
assert_eq!(InclusiveRange::new(0.5, 0.5).empty(), true);
}
#[test]
fn test_range_clamp() {
assert!(range_clamp(InclusiveRange::new(0, 2),
InclusiveRange::new(0, 2)) ==
Some(InclusiveRange::new(0, 2)));
assert!(range_clamp(InclusiveRange::new(0, 1),
InclusiveRange::new(2, 3)) ==
None);
assert!(range_clamp(InclusiveRange::new(2, 3),
InclusiveRange::new(0, 1)) ==
None);
assert!(range_clamp(InclusiveRange::new(0, 2),
InclusiveRange::new(1, 3)) ==
Some(InclusiveRange::new(1, 2)));
assert!(range_clamp(InclusiveRange::new(1, 3),
InclusiveRange::new(0, 2)) ==
Some(InclusiveRange::new(1, 2)));
assert!(range_clamp(InclusiveRange::new(1.0, 3.0),
InclusiveRange::new(0.0, 2.0)) ==
Some(InclusiveRange::new(1.0, 2.0)));
}
#[test]
fn test_range_expand() {
let mut r = InclusiveRange::new(0, 1);
r.expand(InclusiveRange::new(-1, 2));
assert!(r == InclusiveRange::new(-1, 2));
}
#[test]
fn test_range_combine() {
assert!(range_combine(InclusiveRange::new(0, 2),
InclusiveRange::new(-2, 1)) ==
InclusiveRange::new(-2, 2));
}
#[test]
fn test_range_length() {
assert!(InclusiveRange::new(-1, 2).length() == 3);
assert!(InclusiveRange::new(-1.0, 2.5).length() == 3.5);
}