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
use std::cmp::Ordering;
use std::fmt::{Display, Formatter, Debug};

use crate::Error;
use std::hash::{Hash, Hasher};

#[derive(Debug, Clone, Eq, Ord)]
pub enum LimitValue<T> {
  Limit(T),
  Limitless,
}

impl<T: ToString> Hash for LimitValue<T> {
  fn hash<H: Hasher>(&self, state: &mut H) {
    match self {
      LimitValue::Limit(value) => {
        "Limit".hash(state);
        value.to_string().hash(state)
      }
      LimitValue::Limitless => {
        "Limitless".hash(state);
      }
    }
  }
}

impl<T: Default> Default for LimitValue<T> {
  fn default() -> Self {
    LimitValue::Limit(T::default())
  }
}

impl<T: PartialEq> PartialEq for LimitValue<T> {
  fn eq(&self, other: &Self) -> bool {
    match (self, other) {
      (LimitValue::Limitless, LimitValue::Limitless) => true,
      (LimitValue::Limit(value), LimitValue::Limit(other_value)) => value == other_value,
      _ => false,
    }
  }
}

impl<T: PartialOrd> PartialOrd for LimitValue<T> {
  fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
    match (self, other) {
      (LimitValue::Limitless, LimitValue::Limitless) => Some(Ordering::Equal),
      (LimitValue::Limit(_), LimitValue::Limitless) => Some(Ordering::Greater),
      (LimitValue::Limitless, LimitValue::Limit(_)) => Some(Ordering::Less),
      (LimitValue::Limit(value), LimitValue::Limit(other_value)) => value.partial_cmp(other_value),
    }
  }
}

impl<T> From<Option<T>> for LimitValue<T> {
  fn from(value: Option<T>) -> Self {
    match value {
      None => LimitValue::Limitless,
      Some(v) => LimitValue::Limit(v),
    }
  }
}

impl<T> LimitValue<T> {
  pub fn is_limit(&self) -> bool {
    matches!(self, LimitValue::Limit(_))
  }

  pub fn is_limitless(&self) -> bool {
    matches!(self, LimitValue::Limitless)
  }

  pub fn to_value(&self) -> Result<&T, Error> {
    match self {
      LimitValue::Limit(a) => Ok(a),
      LimitValue::Limitless => Err(Error::NotFoundError),
    }
  }

  pub fn to_value_or<'a, TF>(&'a self, default: TF) -> &T
  where
    TF: Fn() -> &'a T,
  {
    match self {
      LimitValue::Limit(a) => a,
      LimitValue::Limitless => default(),
    }
  }
}

impl<T: Display> Display for LimitValue<T> {
  fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
    match self {
      LimitValue::Limit(a) => write!(f, "Limit({})", a),
      LimitValue::Limitless => write!(f, "Limitless"),
    }
  }
}