nonempty_collections/
slice.rs

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