baseunits_rs/intervals/
interval_limit.rs

1use std::cmp::Ordering;
2use crate::intervals::LimitValue;
3
4#[derive(Debug, Clone)]
5pub struct IntervalLimit<T> {
6  pub(crate) closed: bool,
7  pub(crate) lower: bool,
8  pub(crate) value: LimitValue<T>,
9}
10
11impl<T: Default + Clone + PartialOrd> Default for IntervalLimit<T> {
12  fn default() -> Self {
13    IntervalLimit::new(false, false, LimitValue::default())
14  }
15}
16
17impl<T: Default + Clone + PartialEq + PartialOrd> PartialOrd for IntervalLimit<T> {
18  fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
19    match (&self.value, &other.value) {
20      (LimitValue::<T>::Limitless, LimitValue::<T>::Limitless) => {
21        if self.lower == other.lower {
22          Some(Ordering::Equal)
23        } else {
24          Some(self.lower_to_ordering(Ordering::Less, Ordering::Greater))
25        }
26      }
27      (LimitValue::<T>::Limitless, _) => {
28        Some(self.lower_to_ordering(Ordering::Less, Ordering::Greater))
29      }
30      (_, LimitValue::<T>::Limitless) => {
31        Some(other.lower_to_ordering(Ordering::Greater, Ordering::Less))
32      }
33      (LimitValue::<T>::Limit(ref lv), LimitValue::<T>::Limit(ref other_lv)) if lv == other_lv => {
34        match (self.lower, other.lower) {
35          (l, other_l) if l == other_l => {
36            if self.closed ^ other.closed {
37              Some(self.closed_to_ordering(Ordering::Greater, Ordering::Less))
38            } else {
39              Some(Ordering::Equal)
40            }
41          }
42          (l, other_l) if !l == !other_l => {
43            if self.closed ^ other.closed {
44              Some(self.closed_to_ordering(Ordering::Less, Ordering::Greater))
45            } else {
46              Some(Ordering::Equal)
47            }
48          }
49          _ => self.value.partial_cmp(&other.value),
50        }
51      }
52      _ => self.value.partial_cmp(&other.value),
53    }
54  }
55}
56
57impl<T: Default + Clone + PartialOrd> PartialEq for IntervalLimit<T> {
58  fn eq(&self, other: &Self) -> bool {
59    self.partial_cmp(other).unwrap() == Ordering::Equal
60  }
61}
62
63impl<T: Default + Clone + PartialEq + PartialOrd> IntervalLimit<T> {
64  pub fn new(closed: bool, lower: bool, value: LimitValue<T>) -> Self {
65    Self {
66      closed,
67      lower,
68      value,
69    }
70  }
71
72  pub fn lower(closed: bool, value: LimitValue<T>) -> Self {
73    Self::new(closed, true, value)
74  }
75
76  pub fn upper(closed: bool, value: LimitValue<T>) -> Self {
77    Self::new(closed, false, value)
78  }
79
80  fn lower_to_ordering<A>(&self, t: A, f: A) -> A {
81    if self.lower {
82      t
83    } else {
84      f
85    }
86  }
87
88  fn closed_to_ordering<A>(&self, t: A, f: A) -> A {
89    if self.closed {
90      t
91    } else {
92      f
93    }
94  }
95
96  pub fn infinity(&self) -> bool {
97    match self.value {
98      LimitValue::<T>::Limitless => true,
99      LimitValue::<T>::Limit(_) => false,
100    }
101  }
102
103  pub fn is_open(&self) -> bool {
104    !self.closed
105  }
106
107  pub fn is_upper(&self) -> bool {
108    !self.lower
109  }
110}
111
112#[cfg(test)]
113mod tests {
114  use super::*;
115  use crate::intervals::LimitValue;
116
117  #[test]
118  fn test_lower() {
119    assert_eq!(
120      IntervalLimit::lower(false, LimitValue::Limit(10)),
121      IntervalLimit::lower(false, LimitValue::Limit(10))
122    );
123    assert_ne!(
124      IntervalLimit::lower(false, LimitValue::Limit(10)),
125      IntervalLimit::lower(true, LimitValue::Limit(10))
126    );
127    assert_ne!(
128      IntervalLimit::lower(true, LimitValue::Limit(10)),
129      IntervalLimit::lower(false, LimitValue::Limit(10))
130    );
131    assert_eq!(
132      IntervalLimit::lower(true, LimitValue::Limit(10)),
133      IntervalLimit::lower(true, LimitValue::Limit(10))
134    );
135  }
136
137  #[test]
138  fn test_upper() {
139    assert_eq!(
140      IntervalLimit::upper(false, LimitValue::Limit(10)),
141      IntervalLimit::upper(false, LimitValue::Limit(10))
142    );
143    assert_ne!(
144      IntervalLimit::upper(false, LimitValue::Limit(10)),
145      IntervalLimit::upper(true, LimitValue::Limit(10))
146    );
147    assert_ne!(
148      IntervalLimit::upper(true, LimitValue::Limit(10)),
149      IntervalLimit::upper(false, LimitValue::Limit(10))
150    );
151    assert_eq!(
152      IntervalLimit::upper(true, LimitValue::Limit(10)),
153      IntervalLimit::upper(true, LimitValue::Limit(10))
154    );
155  }
156}