#[allow(missing_doc)]; pub trait Normalizable { fn normalize(bound: RangeBound) -> RangeBound; } impl Normalizable for i32 { fn normalize(bound: RangeBound) -> RangeBound { match BoundSided::side(None::) { Upper if bound.type_ == Inclusive => { assert!(bound.value != Bounded::max_value()); RangeBound::new(bound.value + 1, Exclusive) } Lower if bound.type_ == Exclusive => { assert!(bound.value != Bounded::max_value()); RangeBound::new(bound.value + 1, Inclusive) } _ => bound } } } enum BoundSide { Upper, Lower } trait BoundSided { // param is a hack to get around lack of hints for self type fn side(_: Option) -> BoundSide; } #[deriving(Eq)] pub struct UpperBound; #[deriving(Eq)] pub struct LowerBound; impl BoundSided for UpperBound { fn side(_: Option) -> BoundSide { Upper } } impl BoundSided for LowerBound { fn side(_: Option) -> BoundSide { Lower } } #[deriving(Eq)] pub enum BoundType { Inclusive, Exclusive } #[deriving(Eq)] pub struct RangeBound { value: T, type_: BoundType } impl Ord for RangeBound { fn lt(&self, other: &RangeBound) -> bool { match (BoundSided::side(None::), self.type_, other.type_) { (Upper, Exclusive, Inclusive) | (Lower, Inclusive, Exclusive) => self.value <= other.value, _ => self.value < other.value } } } impl RangeBound { pub fn new(value: T, type_: BoundType) -> RangeBound { RangeBound { value: value, type_: type_ } } pub fn in_bounds(&self, value: &T) -> bool { match (self.type_, BoundSided::side(None::)) { (Inclusive, Upper) if value <= &self.value => true, (Exclusive, Upper) if value < &self.value => true, (Inclusive, Lower) if value >= &self.value => true, (Exclusive, Lower) if value > &self.value => true, _ => false } } } #[deriving(Eq)] pub enum RangeComparison { Above, Within, Below } #[deriving(Eq)] pub struct Range { priv lower: Option>, priv upper: Option>, } impl Range { pub fn new(lower: Option>, upper: Option>) -> Range { match (&lower, &upper) { (&Some(ref lower), &Some(ref upper)) => assert!(lower.value <= upper.value), _ => {} } Range { lower: lower.map(|bound| { Normalizable::normalize(bound) }), upper: upper.map(|bound| { Normalizable::normalize(bound) }), } } pub fn lower<'a>(&'a self) -> &'a Option> { &self.lower } pub fn upper<'a>(&'a self) -> &'a Option> { &self.upper } pub fn cmp(&self, value: &T) -> RangeComparison { let lower = do self.lower.as_ref().map_default(true) |b| { b.in_bounds(value) }; let upper = do self.upper.as_ref().map_default(true) |b| { b.in_bounds(value) }; match (lower, upper) { (true, false) => Above, (true, true) => Within, (false, true) => Below, _ => unreachable!() } } pub fn contains(&self, value: &T) -> bool { self.cmp(value) == Within } } #[cfg(test)] mod test { use super::*; #[test] fn test_range_bound_lower_lt() { fn check(val1: int, inc1: BoundType, val2: int, inc2: BoundType, expected: bool) { let a: RangeBound = RangeBound::new(val1, inc1); let b: RangeBound = RangeBound::new(val2, inc2); assert_eq!(expected, a < b); } check(1, Inclusive, 2, Exclusive, true); check(1, Exclusive, 2, Inclusive, true); check(1, Inclusive, 1, Exclusive, true); check(2, Inclusive, 1, Inclusive, false); check(2, Exclusive, 1, Exclusive, false); check(1, Exclusive, 1, Inclusive, false); check(1, Exclusive, 1, Exclusive, false); check(1, Inclusive, 1, Inclusive, false); } #[test] fn test_range_bound_upper_lt() { fn check(val1: int, inc1: BoundType, val2: int, inc2: BoundType, expected: bool) { let a: RangeBound = RangeBound::new(val1, inc1); let b: RangeBound = RangeBound::new(val2, inc2); assert_eq!(expected, a < b); } check(1, Inclusive, 2, Exclusive, true); check(1, Exclusive, 2, Exclusive, true); check(1, Exclusive, 1, Inclusive, true); check(2, Inclusive, 1, Inclusive, false); check(2, Exclusive, 1, Exclusive, false); check(1, Inclusive, 1, Exclusive, false); check(1, Inclusive, 1, Inclusive, false); check(1, Exclusive, 1, Exclusive, false); } #[test] fn test_range_bound_lower_in_bounds() { fn check(bound: int, inc: BoundType, val: int, expected: bool) { let b: RangeBound = RangeBound::new(bound, inc); assert_eq!(expected, b.in_bounds(&val)); } check(1, Inclusive, 1, true); check(1, Exclusive, 1, false); check(1, Inclusive, 2, true); check(1, Inclusive, 0, false); } #[test] fn test_range_bound_upper_in_bounds() { fn check(bound: int, inc: BoundType, val: int, expected: bool) { let b: RangeBound = RangeBound::new(bound, inc); assert_eq!(expected, b.in_bounds(&val)); } check(1, Inclusive, 1, true); check(1, Exclusive, 1, false); check(1, Inclusive, 2, false); check(1, Inclusive, 0, true); } #[test] fn test_range_cmp() { let r = Range::new(Some(RangeBound::new(1i32, Inclusive)), Some(RangeBound::new(3i32, Inclusive))); assert_eq!(Above, r.cmp(&4)); assert_eq!(Within, r.cmp(&3)); assert_eq!(Within, r.cmp(&2)); assert_eq!(Within, r.cmp(&1)); assert_eq!(Below, r.cmp(&0)); let r = Range::new(Some(RangeBound::new(1i32, Exclusive)), Some(RangeBound::new(3i32, Exclusive))); assert_eq!(Above, r.cmp(&4)); assert_eq!(Above, r.cmp(&3)); assert_eq!(Within, r.cmp(&2)); assert_eq!(Below, r.cmp(&1)); assert_eq!(Below, r.cmp(&0)); let r = Range::new(None, Some(RangeBound::new(3i32, Inclusive))); assert_eq!(Above, r.cmp(&4)); assert_eq!(Within, r.cmp(&2)); assert_eq!(Within, r.cmp(&Bounded::min_value())); let r = Range::new(Some(RangeBound::new(1i32, Inclusive)), None); assert_eq!(Within, r.cmp(&Bounded::max_value())); assert_eq!(Within, r.cmp(&4)); assert_eq!(Below, r.cmp(&0)); let r = Range::new(None, None); assert_eq!(Within, r.cmp(&Bounded::max_value())); assert_eq!(Within, r.cmp(&0i32)); assert_eq!(Within, r.cmp(&Bounded::min_value())); } #[test] fn test_normalize_lower() { let r: RangeBound = RangeBound::new(10i32, Inclusive); assert_eq!(RangeBound::new(10i32, Inclusive), Normalizable::normalize(r)); let r: RangeBound = RangeBound::new(10i32, Exclusive); assert_eq!(RangeBound::new(11i32, Inclusive), Normalizable::normalize(r)); } #[test] fn test_normalize_upper() { let r: RangeBound = RangeBound::new(10i32, Inclusive); assert_eq!(RangeBound::new(11i32, Exclusive), Normalizable::normalize(r)); let r: RangeBound = RangeBound::new(10i32, Exclusive); assert_eq!(RangeBound::new(10i32, Exclusive), Normalizable::normalize(r)); } #[test] fn test_range_normalizes() { let r1 = Range::new(Some(RangeBound::new(10i32, Exclusive)), Some(RangeBound::new(15i32, Inclusive))); let r2 = Range::new(Some(RangeBound::new(11i32, Inclusive)), Some(RangeBound::new(16i32, Exclusive))); assert_eq!(r1, r2); } }