karpal_proof/
refinement.rs1#[cfg(not(feature = "std"))]
5use alloc::vec::Vec;
6
7use karpal_core::Semigroup;
8
9#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
17pub struct NonEmpty<C> {
18 inner: C,
19}
20
21impl<T> NonEmpty<Vec<T>> {
22 pub fn try_new(v: Vec<T>) -> Option<Self> {
25 if v.is_empty() {
26 None
27 } else {
28 Some(NonEmpty { inner: v })
29 }
30 }
31
32 pub fn from_parts(head: T, tail: Vec<T>) -> Self {
34 let mut v = tail;
35 v.insert(0, head);
36 NonEmpty { inner: v }
37 }
38
39 pub fn singleton(value: T) -> Self {
41 NonEmpty {
42 inner: [value].into(),
43 }
44 }
45
46 pub fn head(&self) -> &T {
48 &self.inner[0]
50 }
51
52 pub fn len(&self) -> usize {
54 self.inner.len()
55 }
56
57 pub fn is_empty(&self) -> bool {
59 false
60 }
61
62 pub fn push(&mut self, value: T) {
64 self.inner.push(value);
65 }
66
67 pub fn as_slice(&self) -> &[T] {
69 &self.inner
70 }
71
72 pub fn into_vec(self) -> Vec<T> {
74 self.inner
75 }
76
77 pub fn iter(&self) -> core::slice::Iter<'_, T> {
79 self.inner.iter()
80 }
81
82 pub fn map<U>(self, f: impl FnMut(T) -> U) -> NonEmpty<Vec<U>> {
84 NonEmpty {
85 inner: self.inner.into_iter().map(f).collect(),
86 }
87 }
88}
89
90impl<T: Semigroup + Clone> Semigroup for NonEmpty<Vec<T>> {
91 fn combine(mut self, other: Self) -> Self {
92 self.inner.extend(other.inner);
93 self
94 }
95}
96
97#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
102pub struct Positive<T> {
103 value: T,
104}
105
106macro_rules! impl_positive_float {
107 ($($t:ty),*) => {
108 $(
109 impl Positive<$t> {
110 pub fn try_new(v: $t) -> Option<Self> {
113 if v > 0.0 && v.is_finite() {
114 Some(Positive { value: v })
115 } else {
116 None
117 }
118 }
119
120 pub fn get(self) -> $t {
122 self.value
123 }
124
125 pub fn reciprocal(self) -> Self {
127 Positive { value: 1.0 / self.value }
128 }
129 }
130 )*
131 };
132}
133
134impl_positive_float!(f32, f64);
135
136macro_rules! impl_positive_int {
137 ($($t:ty),*) => {
138 $(
139 impl Positive<$t> {
140 pub fn try_new(v: $t) -> Option<Self> {
143 if v > 0 {
144 Some(Positive { value: v })
145 } else {
146 None
147 }
148 }
149
150 pub fn get(self) -> $t {
152 self.value
153 }
154 }
155 )*
156 };
157}
158
159impl_positive_int!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128);
160
161macro_rules! impl_positive_unsigned {
162 ($($t:ty),*) => {
163 $(
164 impl Positive<$t> {
165 pub fn from_nonzero(v: $t) -> Option<Self> {
168 if v > 0 {
169 Some(Positive { value: v })
170 } else {
171 None
172 }
173 }
174 }
175 )*
176 };
177}
178
179impl_positive_unsigned!(u8, u16, u32, u64, u128);
180
181#[cfg(test)]
182mod tests {
183 use super::*;
184
185 #[test]
186 fn non_empty_try_new() {
187 assert!(NonEmpty::try_new(Vec::<i32>::new()).is_none());
188 let ne = NonEmpty::try_new(vec![1, 2, 3]).unwrap();
189 assert_eq!(*ne.head(), 1);
190 assert_eq!(ne.len(), 3);
191 }
192
193 #[test]
194 fn non_empty_from_parts() {
195 let ne = NonEmpty::from_parts(10, vec![20, 30]);
196 assert_eq!(*ne.head(), 10);
197 assert_eq!(ne.as_slice(), &[10, 20, 30]);
198 }
199
200 #[test]
201 fn non_empty_singleton() {
202 let ne = NonEmpty::singleton(42);
203 assert_eq!(*ne.head(), 42);
204 assert_eq!(ne.len(), 1);
205 }
206
207 #[test]
208 fn non_empty_push() {
209 let mut ne = NonEmpty::singleton(1);
210 ne.push(2);
211 assert_eq!(ne.len(), 2);
212 assert_eq!(ne.as_slice(), &[1, 2]);
213 }
214
215 #[test]
216 fn non_empty_map() {
217 let ne = NonEmpty::from_parts(1, vec![2, 3]);
218 let doubled = ne.map(|x| x * 2);
219 assert_eq!(doubled.as_slice(), &[2, 4, 6]);
220 }
221
222 #[test]
223 fn non_empty_into_vec() {
224 let ne = NonEmpty::from_parts(1, vec![2]);
225 assert_eq!(ne.into_vec(), vec![1, 2]);
226 }
227
228 #[test]
229 fn non_empty_iter() {
230 let ne = NonEmpty::from_parts(1, vec![2, 3]);
231 let sum: i32 = ne.iter().sum();
232 assert_eq!(sum, 6);
233 }
234
235 #[test]
236 fn non_empty_semigroup() {
237 let a = NonEmpty::from_parts(1, vec![2]);
238 let b = NonEmpty::from_parts(3, vec![4]);
239 let c = a.combine(b);
240 assert_eq!(c.as_slice(), &[1, 2, 3, 4]);
241 }
242
243 #[test]
244 fn positive_f64() {
245 assert!(Positive::<f64>::try_new(0.0).is_none());
246 assert!(Positive::<f64>::try_new(-1.0).is_none());
247 assert!(Positive::<f64>::try_new(f64::NAN).is_none());
248 assert!(Positive::<f64>::try_new(f64::INFINITY).is_none());
249
250 let p = Positive::<f64>::try_new(4.0).unwrap();
251 assert_eq!(p.get(), 4.0);
252
253 let r = p.reciprocal();
254 assert!((r.get() - 0.25).abs() < 1e-10);
255 }
256
257 #[test]
258 fn positive_f32() {
259 let p = Positive::<f32>::try_new(2.0).unwrap();
260 assert!((p.reciprocal().get() - 0.5).abs() < 1e-6);
261 }
262
263 #[test]
264 fn positive_i32() {
265 assert!(Positive::<i32>::try_new(0).is_none());
266 assert!(Positive::<i32>::try_new(-5).is_none());
267 let p = Positive::<i32>::try_new(7).unwrap();
268 assert_eq!(p.get(), 7);
269 }
270
271 #[test]
272 fn positive_u32() {
273 assert!(Positive::<u32>::try_new(0).is_none());
274 let p = Positive::<u32>::try_new(10).unwrap();
275 assert_eq!(p.get(), 10);
276 }
277
278 #[test]
279 fn positive_u32_from_nonzero() {
280 assert!(Positive::<u32>::from_nonzero(0).is_none());
281 let p = Positive::<u32>::from_nonzero(5).unwrap();
282 assert_eq!(p.get(), 5);
283 }
284}