1use 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#[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 #[must_use]
37 pub const fn first(&self) -> &T {
38 &self.inner[0]
39 }
40
41 #[must_use]
50 #[allow(clippy::missing_panics_doc)] pub const fn last(&self) -> &T {
52 self.inner.last().unwrap()
53 }
54
55 #[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 #[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 #[deprecated(note = "A NESlice is never empty.")]
80 #[must_use]
81 pub const fn is_empty(&self) -> bool {
82 false
83 }
84
85 pub fn iter(&self) -> std::slice::Iter<'_, T> {
89 self.inner.iter()
90 }
91
92 pub fn nonempty_iter(&self) -> Iter<'_, T> {
94 Iter {
95 iter: self.inner.iter(),
96 }
97 }
98
99 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#[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#[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); }
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 #[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 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 #[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 #[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}