1use 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#[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 #[must_use]
29 pub const fn first(&self) -> &T {
30 &self.inner[0]
31 }
32
33 #[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 #[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 #[deprecated(note = "A NESlice is never empty.")]
58 #[must_use]
59 pub const fn is_empty(&self) -> bool {
60 false
61 }
62
63 pub fn iter(&self) -> std::slice::Iter<'_, T> {
67 self.inner.iter()
68 }
69
70 pub fn nonempty_iter(&self) -> Iter<'_, T> {
72 Iter {
73 iter: self.inner.iter(),
74 }
75 }
76
77 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#[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#[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); }
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 #[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 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 #[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 #[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}