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