Skip to main content

stillwater/
nonempty.rs

1//! Non-empty vector type for type-safe collections
2//!
3//! This module provides the `NonEmptyVec<T>` type, which is a vector guaranteed to contain
4//! at least one element. This provides type-level guarantees that prevent runtime errors
5//! when operations assume a non-empty collection.
6//!
7//! # Examples
8//!
9//! ```
10//! use stillwater::NonEmptyVec;
11//!
12//! let nev = NonEmptyVec::new(1, vec![2, 3, 4]);
13//! assert_eq!(nev.head(), &1);
14//! assert_eq!(nev.tail(), &[2, 3, 4]);
15//! assert_eq!(nev.len(), 4);
16//! ```
17//!
18//! # Use Cases
19//!
20//! - Validation errors: When a `Validation` fails, there's always at least one error
21//! - Aggregations: Operations like `head()`, `max()`, `min()` require non-empty data
22//! - Type safety: Prevent `None`/`panic!` in operations that need elements
23
24use crate::Semigroup;
25
26/// A non-empty vector guaranteed to contain at least one element.
27///
28/// This type provides type-level guarantees that operations like `head()`,
29/// `max()`, and `min()` will always succeed without returning `Option`.
30///
31/// # Example
32///
33/// ```
34/// use stillwater::NonEmptyVec;
35///
36/// let nev = NonEmptyVec::new(1, vec![2, 3, 4]);
37/// assert_eq!(nev.head(), &1);
38/// assert_eq!(nev.tail(), &[2, 3, 4]);
39/// assert_eq!(nev.len(), 4);
40/// ```
41#[derive(Debug, Clone, PartialEq, Eq)]
42pub struct NonEmptyVec<T> {
43    head: T,
44    tail: Vec<T>,
45}
46
47impl<T> NonEmptyVec<T> {
48    /// Create a new non-empty vector with a head element and tail.
49    ///
50    /// # Example
51    ///
52    /// ```
53    /// use stillwater::NonEmptyVec;
54    ///
55    /// let nev = NonEmptyVec::new(1, vec![2, 3]);
56    /// assert_eq!(nev.len(), 3);
57    /// ```
58    pub fn new(head: T, tail: Vec<T>) -> Self {
59        Self { head, tail }
60    }
61
62    /// Create a non-empty vector from a single element.
63    ///
64    /// # Example
65    ///
66    /// ```
67    /// use stillwater::NonEmptyVec;
68    ///
69    /// let nev = NonEmptyVec::singleton(42);
70    /// assert_eq!(nev.len(), 1);
71    /// assert_eq!(nev.head(), &42);
72    /// ```
73    pub fn singleton(value: T) -> Self {
74        Self::new(value, Vec::new())
75    }
76
77    /// Try to create a non-empty vector from a `Vec`.
78    ///
79    /// Returns `None` if the vector is empty.
80    ///
81    /// # Example
82    ///
83    /// ```
84    /// use stillwater::NonEmptyVec;
85    ///
86    /// let nev = NonEmptyVec::from_vec(vec![1, 2, 3]).unwrap();
87    /// assert_eq!(nev.len(), 3);
88    ///
89    /// let empty = NonEmptyVec::from_vec(Vec::<i32>::new());
90    /// assert!(empty.is_none());
91    /// ```
92    pub fn from_vec(mut vec: Vec<T>) -> Option<Self> {
93        if vec.is_empty() {
94            None
95        } else {
96            let head = vec.remove(0);
97            Some(Self::new(head, vec))
98        }
99    }
100
101    /// Create a non-empty vector from a `Vec` without checking.
102    ///
103    /// # Panics
104    ///
105    /// Panics if the vector is empty.
106    ///
107    /// # Example
108    ///
109    /// ```
110    /// use stillwater::NonEmptyVec;
111    ///
112    /// let nev = NonEmptyVec::from_vec_unchecked(vec![1, 2, 3]);
113    /// assert_eq!(nev.len(), 3);
114    /// ```
115    ///
116    /// ```should_panic
117    /// use stillwater::NonEmptyVec;
118    ///
119    /// let nev = NonEmptyVec::from_vec_unchecked(Vec::<i32>::new()); // panics
120    /// ```
121    pub fn from_vec_unchecked(vec: Vec<T>) -> Self {
122        Self::from_vec(vec).expect("NonEmptyVec::from_vec_unchecked called on empty Vec")
123    }
124
125    /// Get the first element (always succeeds).
126    ///
127    /// # Example
128    ///
129    /// ```
130    /// use stillwater::NonEmptyVec;
131    ///
132    /// let nev = NonEmptyVec::new(1, vec![2, 3]);
133    /// assert_eq!(nev.head(), &1);
134    /// ```
135    pub fn head(&self) -> &T {
136        &self.head
137    }
138
139    /// Get the tail (all elements except the first).
140    ///
141    /// # Example
142    ///
143    /// ```
144    /// use stillwater::NonEmptyVec;
145    ///
146    /// let nev = NonEmptyVec::new(1, vec![2, 3]);
147    /// assert_eq!(nev.tail(), &[2, 3]);
148    /// ```
149    pub fn tail(&self) -> &[T] {
150        &self.tail
151    }
152
153    /// Get the last element (always succeeds).
154    ///
155    /// # Example
156    ///
157    /// ```
158    /// use stillwater::NonEmptyVec;
159    ///
160    /// let nev = NonEmptyVec::new(1, vec![2, 3]);
161    /// assert_eq!(nev.last(), &3);
162    ///
163    /// let single = NonEmptyVec::singleton(42);
164    /// assert_eq!(single.last(), &42);
165    /// ```
166    pub fn last(&self) -> &T {
167        self.tail.last().unwrap_or(&self.head)
168    }
169
170    /// Get the number of elements.
171    ///
172    /// Always >= 1.
173    ///
174    /// # Example
175    ///
176    /// ```
177    /// use stillwater::NonEmptyVec;
178    ///
179    /// let nev = NonEmptyVec::new(1, vec![2, 3]);
180    /// assert_eq!(nev.len(), 3);
181    /// ```
182    pub fn len(&self) -> usize {
183        1 + self.tail.len()
184    }
185
186    /// Check if the vector is empty.
187    ///
188    /// Always returns `false` since a NonEmptyVec is guaranteed to have at least one element.
189    ///
190    /// This method exists to satisfy clippy's `len_without_is_empty` lint.
191    ///
192    /// # Example
193    ///
194    /// ```
195    /// use stillwater::NonEmptyVec;
196    ///
197    /// let nev = NonEmptyVec::singleton(42);
198    /// assert!(!nev.is_empty());
199    /// ```
200    pub fn is_empty(&self) -> bool {
201        false
202    }
203
204    /// Push an element to the end.
205    ///
206    /// # Example
207    ///
208    /// ```
209    /// use stillwater::NonEmptyVec;
210    ///
211    /// let mut nev = NonEmptyVec::singleton(1);
212    /// nev.push(2);
213    /// nev.push(3);
214    /// assert_eq!(nev.len(), 3);
215    /// ```
216    pub fn push(&mut self, value: T) {
217        self.tail.push(value);
218    }
219
220    /// Pop an element from the end.
221    ///
222    /// Returns `None` if there's only one element (the head).
223    ///
224    /// # Example
225    ///
226    /// ```
227    /// use stillwater::NonEmptyVec;
228    ///
229    /// let mut nev = NonEmptyVec::new(1, vec![2, 3]);
230    /// assert_eq!(nev.pop(), Some(3));
231    /// assert_eq!(nev.pop(), Some(2));
232    /// assert_eq!(nev.pop(), None); // Can't remove head
233    /// ```
234    pub fn pop(&mut self) -> Option<T> {
235        self.tail.pop()
236    }
237
238    /// Map a function over all elements.
239    ///
240    /// # Example
241    ///
242    /// ```
243    /// use stillwater::NonEmptyVec;
244    ///
245    /// let nev = NonEmptyVec::new(1, vec![2, 3]);
246    /// let doubled = nev.map(|x| x * 2);
247    /// assert_eq!(doubled.head(), &2);
248    /// assert_eq!(doubled.tail(), &[4, 6]);
249    /// ```
250    pub fn map<U, F>(self, mut f: F) -> NonEmptyVec<U>
251    where
252        F: FnMut(T) -> U,
253    {
254        let head = f(self.head);
255        let tail = self.tail.into_iter().map(f).collect();
256        NonEmptyVec::new(head, tail)
257    }
258
259    /// Filter elements (may return empty Vec).
260    ///
261    /// Since filtering might remove all elements, this returns `Vec<T>`.
262    ///
263    /// # Example
264    ///
265    /// ```
266    /// use stillwater::NonEmptyVec;
267    ///
268    /// let nev = NonEmptyVec::new(1, vec![2, 3, 4]);
269    /// let evens = nev.filter(|x| x % 2 == 0);
270    /// assert_eq!(evens, vec![2, 4]);
271    ///
272    /// let none = NonEmptyVec::singleton(1).filter(|x| x % 2 == 0);
273    /// assert_eq!(none, vec![]);
274    /// ```
275    pub fn filter<F>(self, mut predicate: F) -> Vec<T>
276    where
277        F: FnMut(&T) -> bool,
278    {
279        let mut result = Vec::new();
280        if predicate(&self.head) {
281            result.push(self.head);
282        }
283        result.extend(self.tail.into_iter().filter(predicate));
284        result
285    }
286
287    /// Convert to a regular `Vec`.
288    ///
289    /// # Example
290    ///
291    /// ```
292    /// use stillwater::NonEmptyVec;
293    ///
294    /// let nev = NonEmptyVec::new(1, vec![2, 3]);
295    /// let vec = nev.into_vec();
296    /// assert_eq!(vec, vec![1, 2, 3]);
297    /// ```
298    pub fn into_vec(self) -> Vec<T> {
299        let mut vec = vec![self.head];
300        vec.extend(self.tail);
301        vec
302    }
303
304    /// Iterate over all elements.
305    ///
306    /// # Example
307    ///
308    /// ```
309    /// use stillwater::NonEmptyVec;
310    ///
311    /// let nev = NonEmptyVec::new(1, vec![2, 3]);
312    /// let sum: i32 = nev.iter().sum();
313    /// assert_eq!(sum, 6);
314    /// ```
315    pub fn iter(&self) -> impl Iterator<Item = &T> {
316        std::iter::once(&self.head).chain(self.tail.iter())
317    }
318}
319
320// Semigroup: concatenation
321impl<T> Semigroup for NonEmptyVec<T> {
322    fn combine(mut self, other: Self) -> Self {
323        self.tail.push(other.head);
324        self.tail.extend(other.tail);
325        self
326    }
327}
328
329// IntoIterator
330impl<T> IntoIterator for NonEmptyVec<T> {
331    type Item = T;
332    type IntoIter = std::iter::Chain<std::iter::Once<T>, std::vec::IntoIter<T>>;
333
334    fn into_iter(self) -> Self::IntoIter {
335        std::iter::once(self.head).chain(self.tail)
336    }
337}
338
339// Note: We cannot implement FromIterator for Option<NonEmptyVec<T>> due to orphan rules.
340// Instead, use NonEmptyVec::from_vec(vec) where vec is collected from an iterator.
341
342// Index
343impl<T> std::ops::Index<usize> for NonEmptyVec<T> {
344    type Output = T;
345
346    fn index(&self, index: usize) -> &Self::Output {
347        if index == 0 {
348            &self.head
349        } else {
350            &self.tail[index - 1]
351        }
352    }
353}
354
355#[cfg(test)]
356mod tests {
357    use super::*;
358
359    #[test]
360    fn test_singleton() {
361        let nev = NonEmptyVec::singleton(42);
362        assert_eq!(nev.head(), &42);
363        assert_eq!(nev.tail(), &[] as &[i32]);
364        assert_eq!(nev.len(), 1);
365    }
366
367    #[test]
368    fn test_new() {
369        let nev = NonEmptyVec::new(1, vec![2, 3]);
370        assert_eq!(nev.head(), &1);
371        assert_eq!(nev.tail(), &[2, 3]);
372        assert_eq!(nev.len(), 3);
373    }
374
375    #[test]
376    fn test_from_vec() {
377        let nev = NonEmptyVec::from_vec(vec![1, 2, 3]).unwrap();
378        assert_eq!(nev.head(), &1);
379        assert_eq!(nev.tail(), &[2, 3]);
380
381        let empty = NonEmptyVec::from_vec(Vec::<i32>::new());
382        assert!(empty.is_none());
383    }
384
385    #[test]
386    fn test_from_vec_unchecked() {
387        let nev = NonEmptyVec::from_vec_unchecked(vec![1, 2, 3]);
388        assert_eq!(nev.head(), &1);
389        assert_eq!(nev.tail(), &[2, 3]);
390    }
391
392    #[test]
393    #[should_panic(expected = "NonEmptyVec::from_vec_unchecked called on empty Vec")]
394    fn test_from_vec_unchecked_panics() {
395        NonEmptyVec::from_vec_unchecked(Vec::<i32>::new());
396    }
397
398    #[test]
399    fn test_last() {
400        let nev = NonEmptyVec::new(1, vec![2, 3]);
401        assert_eq!(nev.last(), &3);
402
403        let single = NonEmptyVec::singleton(42);
404        assert_eq!(single.last(), &42);
405    }
406
407    #[test]
408    fn test_push_pop() {
409        let mut nev = NonEmptyVec::singleton(1);
410        nev.push(2);
411        nev.push(3);
412        assert_eq!(nev.len(), 3);
413
414        assert_eq!(nev.pop(), Some(3));
415        assert_eq!(nev.pop(), Some(2));
416        assert_eq!(nev.pop(), None);
417        assert_eq!(nev.len(), 1);
418    }
419
420    #[test]
421    fn test_map() {
422        let nev = NonEmptyVec::new(1, vec![2, 3]);
423        let doubled = nev.map(|x| x * 2);
424        assert_eq!(doubled.into_vec(), vec![2, 4, 6]);
425    }
426
427    #[test]
428    fn test_filter() {
429        let nev = NonEmptyVec::new(1, vec![2, 3, 4]);
430        let evens = nev.filter(|x| x % 2 == 0);
431        assert_eq!(evens, vec![2, 4]);
432
433        let nev2 = NonEmptyVec::singleton(1);
434        let empty = nev2.filter(|x| x % 2 == 0);
435        assert_eq!(empty, Vec::<i32>::new());
436    }
437
438    #[test]
439    fn test_into_vec() {
440        let nev = NonEmptyVec::new(1, vec![2, 3]);
441        let vec = nev.into_vec();
442        assert_eq!(vec, vec![1, 2, 3]);
443    }
444
445    #[test]
446    fn test_iter() {
447        let nev = NonEmptyVec::new(1, vec![2, 3]);
448        let sum: i32 = nev.iter().sum();
449        assert_eq!(sum, 6);
450
451        let collected: Vec<_> = nev.iter().copied().collect();
452        assert_eq!(collected, vec![1, 2, 3]);
453    }
454
455    #[test]
456    fn test_semigroup() {
457        let nev1 = NonEmptyVec::new(1, vec![2]);
458        let nev2 = NonEmptyVec::new(3, vec![4]);
459        let combined = nev1.combine(nev2);
460        assert_eq!(combined.into_vec(), vec![1, 2, 3, 4]);
461    }
462
463    #[test]
464    fn test_into_iter() {
465        let nev = NonEmptyVec::new(1, vec![2, 3]);
466        let vec: Vec<_> = nev.into_iter().collect();
467        assert_eq!(vec, vec![1, 2, 3]);
468    }
469
470    #[test]
471    fn test_from_vec_with_iterator() {
472        // Since we can't implement FromIterator, test the pattern of collect + from_vec
473        let vec: Vec<i32> = vec![1, 2, 3].into_iter().collect();
474        let nev = NonEmptyVec::from_vec(vec);
475        assert!(nev.is_some());
476        assert_eq!(nev.unwrap().into_vec(), vec![1, 2, 3]);
477
478        let vec_empty: Vec<i32> = vec![].into_iter().collect();
479        let nev_empty = NonEmptyVec::from_vec(vec_empty);
480        assert!(nev_empty.is_none());
481    }
482
483    #[test]
484    fn test_index() {
485        let nev = NonEmptyVec::new(1, vec![2, 3]);
486        assert_eq!(nev[0], 1);
487        assert_eq!(nev[1], 2);
488        assert_eq!(nev[2], 3);
489    }
490
491    #[test]
492    #[should_panic]
493    fn test_index_out_of_bounds() {
494        let nev = NonEmptyVec::singleton(42);
495        let _ = nev[1]; // Should panic
496    }
497}