1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4pub mod prelude;
7
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub enum LowerBound<T> {
10 Inclusive(T),
11 Exclusive(T),
12}
13
14impl<T: PartialOrd> LowerBound<T> {
15 #[must_use]
16 pub fn allows(&self, value: &T) -> bool {
17 match self {
18 Self::Inclusive(bound) => value >= bound,
19 Self::Exclusive(bound) => value > bound,
20 }
21 }
22
23 #[must_use]
24 pub const fn value(&self) -> &T {
25 match self {
26 Self::Inclusive(bound) | Self::Exclusive(bound) => bound,
27 }
28 }
29}
30
31#[derive(Debug, Clone, PartialEq, Eq)]
32pub enum UpperBound<T> {
33 Inclusive(T),
34 Exclusive(T),
35}
36
37impl<T: PartialOrd> UpperBound<T> {
38 #[must_use]
39 pub fn allows(&self, value: &T) -> bool {
40 match self {
41 Self::Inclusive(bound) => value <= bound,
42 Self::Exclusive(bound) => value < bound,
43 }
44 }
45
46 #[must_use]
47 pub const fn value(&self) -> &T {
48 match self {
49 Self::Inclusive(bound) | Self::Exclusive(bound) => bound,
50 }
51 }
52}
53
54#[must_use]
55pub const fn minimum<T>(value: T) -> LowerBound<T> {
56 LowerBound::Inclusive(value)
57}
58
59#[must_use]
60pub const fn exclusive_minimum<T>(value: T) -> LowerBound<T> {
61 LowerBound::Exclusive(value)
62}
63
64#[must_use]
65pub const fn maximum<T>(value: T) -> UpperBound<T> {
66 UpperBound::Inclusive(value)
67}
68
69#[must_use]
70pub const fn exclusive_maximum<T>(value: T) -> UpperBound<T> {
71 UpperBound::Exclusive(value)
72}
73
74#[cfg(test)]
75mod tests {
76 use super::{exclusive_minimum, maximum};
77
78 #[test]
79 fn bounds_apply_inclusive_and_exclusive_logic() {
80 let lower = exclusive_minimum(0);
81 let upper = maximum(10);
82
83 assert!(lower.allows(&1));
84 assert!(!lower.allows(&0));
85 assert!(upper.allows(&10));
86 }
87}