nonempty_collections/
slice.rs

1//! Non-empty Slices.
2
3use core::fmt;
4use std::iter::FilterMap;
5use std::num::NonZeroUsize;
6use std::ops::Index;
7use std::slice::Chunks;
8
9use crate::iter::IntoNonEmptyIterator;
10use crate::iter::NonEmptyIterator;
11
12/// A non-empty slice. Like [`crate::NEVec`], but guaranteed to have borrowed
13/// contents.
14///
15/// [`NESlice::try_from_slice`] is the simplest way to construct this from
16/// borrowed data.
17///
18/// Unfortunately there is no macro for this, but if you want one, just use
19/// `nev!` and handle the ownership manually. Also consider
20/// [`crate::NEVec::as_nonempty_slice`].
21#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
22pub struct NESlice<'a, T> {
23    inner: &'a [T],
24}
25
26impl<'a, T> NESlice<'a, T> {
27    /// Get the first element. Never fails.
28    #[must_use]
29    pub const fn first(&self) -> &T {
30        &self.inner[0]
31    }
32
33    /// Using `try_from_slice` gives a proof that the input slice is non-empty
34    /// in the `Some` branch.
35    #[must_use]
36    pub const fn try_from_slice(slice: &'a [T]) -> Option<Self> {
37        if slice.is_empty() {
38            None
39        } else {
40            Some(NESlice { inner: slice })
41        }
42    }
43
44    #[must_use]
45    pub(crate) const fn from_slice_unchecked(slice: &'a [T]) -> Self {
46        NESlice { inner: slice }
47    }
48
49    /// Get the length of the slice.
50    #[must_use]
51    pub fn len(&self) -> NonZeroUsize {
52        debug_assert!(!self.inner.is_empty());
53        unsafe { NonZeroUsize::new_unchecked(self.inner.len()) }
54    }
55
56    /// No, this slice is not empty.
57    #[deprecated(note = "A NESlice is never empty.")]
58    #[must_use]
59    pub const fn is_empty(&self) -> bool {
60        false
61    }
62
63    /// Returns a regular iterator over the values in this non-empty slice.
64    ///
65    /// For a `NonEmptyIterator` see `Self::nonempty_iter()`.
66    pub fn iter(&self) -> std::slice::Iter<'_, T> {
67        self.inner.iter()
68    }
69
70    /// Returns a non-empty iterator.
71    pub fn nonempty_iter(&self) -> Iter<'_, T> {
72        Iter {
73            iter: self.inner.iter(),
74        }
75    }
76
77    /// Returns a non-empty iterator over `chunk_size` elements of the `NESlice`
78    /// at a time, starting at the beginning of the `NESlice`.
79    ///
80    /// ```
81    /// use std::num::NonZeroUsize;
82    ///
83    /// use nonempty_collections::*;
84    ///
85    /// let v = nev![1, 2, 3, 4, 5, 6];
86    /// let s = v.as_nonempty_slice();
87    /// let n = NonZeroUsize::new(2).unwrap();
88    /// let r = s.nonempty_chunks(n).collect::<NEVec<_>>();
89    ///
90    /// let a = nev![1, 2];
91    /// let b = nev![3, 4];
92    /// let c = nev![5, 6];
93    ///
94    /// assert_eq!(
95    ///     r,
96    ///     nev![
97    ///         a.as_nonempty_slice(),
98    ///         b.as_nonempty_slice(),
99    ///         c.as_nonempty_slice()
100    ///     ]
101    /// );
102    /// ```
103    pub fn nonempty_chunks(&'a self, chunk_size: NonZeroUsize) -> NEChunks<'a, T> {
104        NEChunks {
105            inner: self.inner.chunks(chunk_size.get()),
106        }
107    }
108}
109
110impl<'a, T> IntoNonEmptyIterator for NESlice<'a, T> {
111    type IntoNEIter = Iter<'a, T>;
112
113    fn into_nonempty_iter(self) -> Self::IntoNEIter {
114        Iter {
115            iter: self.inner.iter(),
116        }
117    }
118}
119
120impl<'a, T> IntoNonEmptyIterator for &'a NESlice<'a, T> {
121    type IntoNEIter = Iter<'a, T>;
122
123    fn into_nonempty_iter(self) -> Self::IntoNEIter {
124        self.nonempty_iter()
125    }
126}
127
128impl<'a, T> IntoIterator for NESlice<'a, T> {
129    type Item = &'a T;
130
131    type IntoIter = std::slice::Iter<'a, T>;
132
133    fn into_iter(self) -> Self::IntoIter {
134        self.inner.iter()
135    }
136}
137
138impl<'a, T> IntoIterator for &'a NESlice<'a, T> {
139    type Item = &'a T;
140
141    type IntoIter = std::slice::Iter<'a, T>;
142
143    fn into_iter(self) -> Self::IntoIter {
144        self.iter()
145    }
146}
147
148impl<T> Index<usize> for NESlice<'_, T> {
149    type Output = T;
150
151    fn index(&self, index: usize) -> &Self::Output {
152        &self.inner[index]
153    }
154}
155
156/// A non-empty iterator over the values of an [`NESlice`].
157#[derive(Debug)]
158#[must_use = "non-empty iterators are lazy and do nothing unless consumed"]
159pub struct Iter<'a, T: 'a> {
160    iter: std::slice::Iter<'a, T>,
161}
162
163impl<T> NonEmptyIterator for Iter<'_, T> {}
164
165impl<'a, T> IntoIterator for Iter<'a, T> {
166    type Item = &'a T;
167
168    type IntoIter = std::slice::Iter<'a, T>;
169
170    fn into_iter(self) -> Self::IntoIter {
171        self.iter
172    }
173}
174
175/// A non-empty Iterator of [`NESlice`] chunks.
176#[must_use = "non-empty iterators are lazy and do nothing unless consumed"]
177pub struct NEChunks<'a, T> {
178    pub(crate) inner: Chunks<'a, T>,
179}
180
181type SliceFilter<'a, T> = fn(&'a [T]) -> Option<NESlice<'a, T>>;
182
183impl<T> NonEmptyIterator for NEChunks<'_, T> {}
184
185impl<'a, T> IntoIterator for NEChunks<'a, T> {
186    type Item = NESlice<'a, T>;
187
188    type IntoIter = FilterMap<Chunks<'a, T>, SliceFilter<'a, T>>;
189
190    fn into_iter(self) -> Self::IntoIter {
191        self.inner.filter_map(|x| NESlice::try_from_slice(x))
192    }
193}
194
195impl<T: fmt::Debug> fmt::Debug for NEChunks<'_, T> {
196    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197        self.inner.fmt(f)
198    }
199}
200
201#[cfg(test)]
202mod tests {
203    use std::num::NonZeroUsize;
204
205    use crate::nev;
206    use crate::slice::NEChunks;
207    use crate::NESlice;
208    use crate::NEVec;
209    use crate::NonEmptyIterator;
210
211    #[test]
212    fn test_from_conversion() {
213        let slice = [1, 2, 3, 4, 5];
214        let nonempty_slice = NESlice::try_from_slice(&slice);
215        let nonempty_slice = nonempty_slice.unwrap();
216
217        assert_eq!(nonempty_slice.inner, &[1, 2, 3, 4, 5]);
218    }
219
220    #[test]
221    fn test_iter_syntax() {
222        let slice = [0, 1, 2, 3];
223        let nonempty = NESlice::try_from_slice(&slice);
224        if let Some(nonempty) = nonempty {
225            for n in &nonempty {
226                assert_eq!(*n, *n); // Prove that we're dealing with references.
227            }
228        }
229    }
230
231    #[test]
232    fn test_into_nonempty_iter() {
233        use crate::IntoNonEmptyIterator;
234        use crate::NonEmptyIterator;
235        let slice = [0usize, 1, 2, 3];
236        let nonempty = NESlice::try_from_slice(&slice).unwrap();
237        for (i, n) in nonempty.into_nonempty_iter().enumerate() {
238            assert_eq!(i, *n);
239        }
240    }
241
242    #[test]
243    fn chunks() {
244        let v = nev![1, 2, 3, 4, 5, 6, 7];
245
246        let n = NonZeroUsize::new(3).unwrap();
247        let a: Vec<_> = v.nonempty_chunks(n).collect();
248
249        assert_eq!(
250            a,
251            vec![
252                nev![1, 2, 3].as_nonempty_slice(),
253                nev![4, 5, 6].as_nonempty_slice(),
254                nev![7].as_nonempty_slice()
255            ]
256        );
257
258        let n = NonZeroUsize::new(1).unwrap();
259        let b: Vec<_> = v.nonempty_chunks(n).collect();
260
261        assert_eq!(
262            b,
263            vec![
264                nev![1].as_nonempty_slice(),
265                nev![2].as_nonempty_slice(),
266                nev![3].as_nonempty_slice(),
267                nev![4].as_nonempty_slice(),
268                nev![5].as_nonempty_slice(),
269                nev![6].as_nonempty_slice(),
270                nev![7].as_nonempty_slice(),
271            ]
272        );
273    }
274
275    #[test]
276    fn chunks_len() {
277        let v = nev![1, 2, 3];
278        let n = NonZeroUsize::new(3).unwrap();
279        let c = v.nonempty_chunks(n).count().get();
280        assert_eq!(c, 1);
281
282        let v = nev![1, 2, 3];
283        let n = NonZeroUsize::new(5).unwrap();
284        let c = v.nonempty_chunks(n).count().get();
285        assert_eq!(c, 1);
286
287        let v = nev![1, 2, 3, 4];
288        let n = NonZeroUsize::new(3).unwrap();
289        let c = v.nonempty_chunks(n).count().get();
290        assert_eq!(c, 2);
291    }
292
293    // A test to reproduce index out of range errors
294    // and ensure that the `NEChunks` iterator works
295    // as expected.
296    #[test]
297    fn chunks_into_iter_with_chunk_size_over_len() {
298        let v = nev![1, 2, 3];
299        let n = NonZeroUsize::new(4).unwrap();
300        let c = v.nonempty_chunks(n);
301
302        // Iterating over should not produce any errors.
303        for slice in c {
304            let _: NESlice<'_, i32> = slice;
305        }
306
307        let v = nev![1, 2, 3];
308        let n = NonZeroUsize::new(4).unwrap();
309        let c: NEVec<_> = v.nonempty_chunks(n).collect();
310
311        assert_eq!(1, c.len().get());
312        assert_eq!(&v.as_nonempty_slice(), c.first());
313    }
314
315    // A test to ensure the correctness of the `NEChunks` iterator
316    #[test]
317    fn chunks_into_iter_should_return_elements_exactly_once() {
318        let v = nev![1, 2, 3, 4, 5, 6, 57];
319        let n = NonZeroUsize::new(3).unwrap();
320        let c: NEChunks<'_, i32> = v.nonempty_chunks(n);
321
322        let mut r: Vec<NESlice<i32>> = vec![];
323
324        for slice in c {
325            let _: NESlice<'_, i32> = slice;
326            r.push(slice);
327        }
328
329        assert_eq!(
330            r,
331            vec![
332                nev![1, 2, 3].as_nonempty_slice(),
333                nev![4, 5, 6].as_nonempty_slice(),
334                nev![57].as_nonempty_slice(),
335            ]
336        );
337    }
338
339    // This test covers an edge case non supported by the `chunks` method
340    // when the slice has only one element.
341    #[test]
342    fn chunks_into_iter_edge_case_single_element() {
343        let v = nev![1];
344        let n = NonZeroUsize::new(3).unwrap();
345        let c: NEChunks<'_, i32> = v.nonempty_chunks(n);
346
347        let mut iter = c.into_iter();
348
349        let next = iter.next().unwrap();
350        assert_eq!(1, next.len().get());
351        assert!(iter.next().is_none());
352    }
353}