texcraft_stdext/collections/
nevec.rs

1//! A vector type that is statically guaranteed to be non-empty
2//!
3//! In situations where a vector is known to have at least 1 element, this
4//! data structure enables writing code without calls to `Vec::unwrap`. That is,
5//! it provides a way to statically enforce the invariant.
6
7use std::ops::Index;
8
9/// Non-empty vector type.
10#[derive(Debug, Default, Clone)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12pub struct Nevec<T> {
13    first: T,
14    tail: Vec<T>,
15}
16
17impl<T> Nevec<T> {
18    /// Creates a new `Nevec` with the provided first element.
19    pub fn new(first: T) -> Nevec<T> {
20        Nevec::<T>::new_with_tail(first, Vec::new())
21    }
22
23    /// Creates a new `Nevec` with the provided first element and initial capacity.
24    pub fn with_capacity(first: T, capacity: usize) -> Nevec<T> {
25        Nevec::<T>::new_with_tail(first, Vec::with_capacity(capacity))
26    }
27
28    /// Creates a new `Nevec` with the provided first element and remaining elements ("the tail").
29    pub fn new_with_tail(first: T, tail: Vec<T>) -> Nevec<T> {
30        Nevec { first, tail }
31    }
32
33    /// Gets a reference to the last element of the vector.
34    /// Because the vector is guaranteed to be non-empty, this will always succeed.
35    pub fn last(&self) -> &T {
36        match self.tail.last() {
37            None => &self.first,
38            Some(t) => t,
39        }
40    }
41
42    /// Gets a mutable reference to the last element of the vector.
43    /// Because the vector is guaranteed to be non-empty, this will always succeed.
44    pub fn last_mut(&mut self) -> &mut T {
45        match self.tail.last_mut() {
46            None => &mut self.first,
47            Some(t) => t,
48        }
49    }
50
51    /// Pushes an element onto the end of the vector.
52    pub fn push(&mut self, t: T) {
53        self.tail.push(t)
54    }
55
56    /// Pops an element from the end of the vector.
57    ///
58    /// Because the vector is guaranteed to be non-empty, this will always succeed.
59    /// However if the vector has only 1 element, then after popping it will no longer
60    /// be non-empty. For this reason, the pop method takes ownership of the vector,
61    /// and destroys it in the process.
62    ///
63    /// In the case when the vector has more than 1 element, the method `pop_from_tail`
64    /// can be used to retrieve the last element without destroying the vector.
65    pub fn pop(mut self) -> T {
66        match self.tail.pop() {
67            None => self.first,
68            Some(t) => t,
69        }
70    }
71
72    /// Pops an element from the tail of the vector; that is, the part of the vector
73    /// after the first element.
74    ///
75    /// Returns `None` if and only if the vector has exactly 1 element. In this
76    /// case the method `pop` is needed to take ownership of the element.
77    pub fn pop_from_tail(&mut self) -> Option<T> {
78        self.tail.pop()
79    }
80
81    /// Returns the length of the vector, which is guaranteed to be at least 1.
82    pub fn len(&self) -> usize {
83        1 + self.tail.len()
84    }
85
86    /// Returns whether the vector is non-empty, which it always is.
87    pub fn is_empty(&self) -> bool {
88        true
89    }
90
91    /// Get a reference to the element at the provided index.
92    pub fn get(&self, i: usize) -> Option<&T> {
93        if i == 0 {
94            return Some(&self.first);
95        }
96        self.tail.get(i - 1)
97    }
98
99    /// Get a mutable reference to the element at the provided index.
100    pub fn get_mut(&mut self, i: usize) -> Option<&mut T> {
101        if i == 0 {
102            return Some(&mut self.first);
103        }
104        self.tail.get_mut(i - 1)
105    }
106}
107
108impl<T> Index<usize> for Nevec<T> {
109    type Output = T;
110
111    fn index(&self, i: usize) -> &Self::Output {
112        if i == 0 {
113            &self.first
114        } else {
115            &self.tail[i - 1]
116        }
117    }
118}
119
120impl<'a, T> IntoIterator for &'a Nevec<T> {
121    type Item = &'a T;
122    type IntoIter = NevecIter<'a, T>;
123
124    fn into_iter(self) -> NevecIter<'a, T> {
125        NevecIter { vec: self, i: 0 }
126    }
127}
128
129impl<T: std::fmt::Display> std::fmt::Display for Nevec<T> {
130    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
131        for t in self {
132            write![f, "{t}"]?;
133        }
134        Ok(())
135    }
136}
137
138pub struct NevecIter<'a, T> {
139    vec: &'a Nevec<T>,
140    i: usize,
141}
142
143impl<'a, T> Iterator for NevecIter<'a, T> {
144    type Item = &'a T;
145    fn next(&mut self) -> Option<Self::Item> {
146        if self.i >= self.vec.len() {
147            None
148        } else {
149            self.i += 1;
150            Some(&self.vec[self.i - 1])
151        }
152    }
153}
154
155/// Create a new [Nevec] (non-empty vector).
156#[macro_export]
157macro_rules! nevec {
158    ( $first: expr, $ ( $ x : expr ) , * ) => (
159        Nevec::new_with_tail($first, vec![$ ( $ x ) , *])
160    );
161    ( $first: expr, $ ( $ x : expr , ) * ) => ( nevec ! [ $first, $ ( $ x ) , * ] );
162    ( $first: expr ) => {
163      Nevec::new($first)
164    };
165}
166
167#[cfg(test)]
168mod tests {
169    use super::*;
170
171    #[test]
172    fn singleton_vector() {
173        let mut v = nevec![3];
174        assert_eq![v.len(), 1];
175        assert_eq![v.last(), &3];
176        assert_eq![v.last_mut(), &3];
177        assert_eq![v.pop_from_tail(), None];
178        assert_eq![v.pop(), 3];
179    }
180
181    #[test]
182    fn two_element_vector() {
183        let mut v = nevec![3, 4];
184        assert_eq![v.len(), 2];
185        assert_eq![v.last(), &4];
186        assert_eq![v.last_mut(), &4];
187        assert_eq![v[0], 3];
188        assert_eq![v[1], 4];
189        assert_eq![v.pop_from_tail(), Some(4)];
190        assert_eq![v.last(), &3];
191        assert_eq![v.last_mut(), &3];
192        assert_eq![v.pop_from_tail(), None];
193    }
194
195    #[test]
196    fn vector_with_push() {
197        let mut v = nevec![3, 4,];
198        assert_eq![v.len(), 2];
199        v.push(5);
200        assert_eq![v.len(), 3];
201        assert_eq![v.last(), &5];
202        assert_eq![v.last_mut(), &5];
203        assert_eq![v.pop_from_tail(), Some(5)];
204    }
205
206    #[test]
207    fn other_macro_constructor_case() {
208        let mut v = nevec![3,];
209        assert_eq![v.len(), 1];
210        assert_eq![v.last(), &3];
211        assert_eq![v.last_mut(), &3];
212        assert_eq![v.pop_from_tail(), None];
213        assert_eq![v.pop(), 3];
214    }
215}