1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use std::cmp::Ordering;
use std::fmt::{Display, Formatter, Debug};

use crate::LimitValue;
use std::hash::Hash;

#[derive(Debug, Clone, Hash, Eq, Ord)]
pub struct IntervalLimit<T: Display + Clone + Hash + Ord> {
  closed: bool,
  lower: bool,
  value: LimitValue<T>,
}

impl<T: Display + Clone + Hash + Eq + Ord + PartialEq + PartialOrd> PartialEq for IntervalLimit<T> {
  fn eq(&self, other: &Self) -> bool {
    self.partial_cmp(other) == Some(Ordering::Equal)
  }
}

impl<T: Display + Clone + Hash + Eq + Ord + PartialEq + PartialOrd> PartialOrd
  for IntervalLimit<T>
{
  fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
    if self.value.is_limitless() && other.value.is_limitless() {
      if self.lower == other.lower {
        Some(Ordering::Equal)
      } else {
        self.lower_to_ordering(Some(Ordering::Less), Some(Ordering::Greater))
      }
    } else if self.value.is_limitless() {
      self.lower_to_ordering(Some(Ordering::Less), Some(Ordering::Greater))
    } else if other.value.is_limitless() {
      other.lower_to_ordering(Some(Ordering::Greater), Some(Ordering::Less))
    } else if self.value == other.value {
      if self.lower && other.lower {
        if self.closed ^ other.closed {
          self.closed_to_ordering(Some(Ordering::Less), Some(Ordering::Greater))
        } else {
          Some(Ordering::Equal)
        }
      } else if !self.lower && !other.lower {
        if self.closed ^ other.closed {
          self.closed_to_ordering(Some(Ordering::Greater), Some(Ordering::Less))
        } else {
          Some(Ordering::Equal)
        }
      } else {
        self.lower_to_ordering(Some(Ordering::Less), Some(Ordering::Greater))
      }
    } else {
      self.value.partial_cmp(&other.value)
    }
  }
}

impl<T: Display + Clone + Hash + Eq + Ord + PartialEq + PartialOrd> IntervalLimit<T> {
  pub fn is_closed(&self) -> bool {
    self.closed
  }

  pub fn is_lower(&self) -> bool {
    self.lower
  }

  pub fn get_value(&self) -> &LimitValue<T> {
    &self.value
  }

  pub fn new(closed: bool, lower: bool, value: LimitValue<T>) -> Self {
    Self {
      closed: if value.is_limitless() { false } else { closed },
      lower,
      value,
    }
  }

  pub fn lower(closed: bool, value: LimitValue<T>) -> Self {
    Self::new(closed, true, value)
  }

  pub fn upper(closed: bool, value: LimitValue<T>) -> Self {
    Self::new(closed, false, value)
  }

  fn lower_to_ordering<A>(&self, t: A, f: A) -> A {
    if self.lower {
      t
    } else {
      f
    }
  }

  fn closed_to_ordering<A>(&self, t: A, f: A) -> A {
    if self.closed {
      t
    } else {
      f
    }
  }

  pub fn is_infinity(&self) -> bool {
    self.value.is_limitless()
  }

  pub fn non_infinity(&self) -> bool {
    self.value.is_limit()
  }

  pub fn is_open(&self) -> bool {
    !self.closed
  }

  pub fn is_upper(&self) -> bool {
    !self.lower
  }
}

impl<T: Display + Clone + Hash + Eq + Ord + PartialEq + PartialOrd> Display for IntervalLimit<T> {
  fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
    write!(
      f,
      "IntervalLimit({}, {}, {})",
      self.closed, self.lower, self.value
    )
  }
}