ranges/generic_range/
singleton.rs1use core::ops::Bound;
2
3use crate::{Domain, GenericRange};
4
5impl<T: Domain> GenericRange<T> {
6 #[must_use]
20 pub fn singleton(value: T) -> Self
21 where
22 T: Clone,
23 {
24 Self::new_with_bounds(Bound::Included(value.clone()), Bound::Included(value))
25 }
26
27 #[allow(clippy::needless_borrowed_reference)]
43 #[must_use]
44 pub fn is_singleton(&self) -> bool {
45 if self.is_empty() {
46 return false;
47 }
48
49 if <T as Domain>::DISCRETE {
50 match (&self.start, &self.end) {
51 (&Bound::Unbounded, _) | (_, &Bound::Unbounded) => false,
52
53 (&Bound::Included(ref x), &Bound::Excluded(ref y))
54 | (&Bound::Excluded(ref x), &Bound::Included(ref y)) => x < y && x.is_next_to(y),
55 (&Bound::Included(ref x), &Bound::Included(ref y)) => x == y,
56
57 (&Bound::Excluded(ref x), &Bound::Excluded(ref y)) => x.shares_neighbour_with(y),
58 }
59 } else {
60 match (&self.start, &self.end) {
61 (&Bound::Included(ref x), &Bound::Included(ref y)) => x == y,
62 _ => false,
63 }
64 }
65 }
66}
67
68impl<T: Domain + Clone> From<T> for GenericRange<T> {
69 #[must_use]
70 fn from(val: T) -> Self {
71 Self::singleton(val)
72 }
73}
74
75#[cfg(test)]
76mod tests_discrete {
77 use core::ops::Bound;
78
79 use crate::GenericRange;
80
81 #[test]
82 fn in_ex() {
83 assert!(!GenericRange::from(1..1).is_singleton());
84 assert!(GenericRange::from(1..2).is_singleton());
85 assert!(!GenericRange::from(1..42).is_singleton());
86 }
87
88 #[test]
89 fn in_in() {
90 assert!(GenericRange::from(1..=1).is_singleton());
91 assert!(!GenericRange::from(1..=2).is_singleton());
92 assert!(!GenericRange::from(1..=42).is_singleton());
93 }
94
95 #[test]
96 fn unbound() {
97 assert!(!GenericRange::from(1..).is_singleton());
98 assert!(!GenericRange::from(..2).is_singleton());
99 assert!(!GenericRange::from(..=2).is_singleton());
100 let generic: GenericRange<usize> = GenericRange::from(..);
101 assert!(!generic.is_singleton());
102 assert!(!GenericRange::from((Bound::Excluded(1), Bound::Unbounded)).is_singleton());
103 }
104
105 #[test]
106 fn ex_ex() {
107 assert!(!GenericRange::from((Bound::Excluded(1), Bound::Excluded(1))).is_singleton());
108 assert!(!GenericRange::from((Bound::Excluded(1), Bound::Excluded(2))).is_singleton());
109 assert!(!GenericRange::from((Bound::Excluded(1), Bound::Excluded(42))).is_singleton());
110 }
111
112 #[test]
113 fn ex_in() {
114 assert!(!GenericRange::from((Bound::Excluded(1), Bound::Included(1))).is_singleton());
115 assert!(GenericRange::from((Bound::Excluded(1), Bound::Included(2))).is_singleton());
116 assert!(!GenericRange::from((Bound::Excluded(1), Bound::Included(42))).is_singleton());
117 }
118}
119
120#[allow(clippy::tests_outside_test_module)]
121#[cfg(all(test, feature = "noisy_float"))]
122mod tests_continuous {
123 use core::ops::Bound;
124
125 use noisy_float::types::N64;
126
127 use crate::GenericRange;
128
129 #[test]
130 fn in_ex() {
131 let n64_1 = N64::new(1.);
132 let n64_2 = N64::new(2.);
133 let n64_42 = N64::new(42.);
134 assert!(!GenericRange::from(n64_1..n64_1).is_singleton());
135 assert!(!GenericRange::from(n64_1..n64_2).is_singleton());
136 assert!(!GenericRange::from(n64_1..n64_42).is_singleton());
137 }
138
139 #[test]
140 fn in_in() {
141 let n64_1 = N64::new(1.);
142 let n64_2 = N64::new(2.);
143 let n64_42 = N64::new(42.);
144 assert!(GenericRange::from(n64_1..=n64_1).is_singleton());
145 assert!(!GenericRange::from(n64_1..=n64_2).is_singleton());
146 assert!(!GenericRange::from(n64_1..=n64_42).is_singleton());
147 }
148
149 #[test]
150 fn unbound() {
151 let n64_1 = N64::new(1.);
152 let n64_2 = N64::new(2.);
153 assert!(!GenericRange::from(n64_1..).is_singleton());
154 assert!(!GenericRange::from(..n64_2).is_singleton());
155 assert!(!GenericRange::from(..=n64_2).is_singleton());
156 let generic: GenericRange<N64> = GenericRange::from(..);
157 assert!(!generic.is_singleton());
158 assert!(!GenericRange::from((Bound::Excluded(n64_1), Bound::Unbounded)).is_singleton());
159 }
160
161 #[test]
162 fn ex_ex() {
163 let n64_1 = N64::new(1.);
164 let n64_2 = N64::new(2.);
165 let n64_42 = N64::new(42.);
166 assert!(!GenericRange::from((Bound::Excluded(n64_1), Bound::Excluded(n64_1))).is_singleton());
167 assert!(!GenericRange::from((Bound::Excluded(n64_1), Bound::Excluded(n64_2))).is_singleton());
168 assert!(!GenericRange::from((Bound::Excluded(n64_1), Bound::Excluded(n64_42))).is_singleton());
169 }
170
171 #[test]
172 fn ex_in() {
173 let n64_1 = N64::new(1.);
174 let n64_2 = N64::new(2.);
175 let n64_42 = N64::new(42.);
176 assert!(!GenericRange::from((Bound::Excluded(n64_1), Bound::Included(n64_1))).is_singleton());
177 assert!(!GenericRange::from((Bound::Excluded(n64_1), Bound::Included(n64_2))).is_singleton());
178 assert!(!GenericRange::from((Bound::Excluded(n64_1), Bound::Included(n64_42))).is_singleton());
179 }
180}