use crate::iter::{IntoIteratorProxy, IntoNonEmptyIterator, NonEmptyIterator};
use std::iter::{Chain, Once, Skip};
use std::num::NonZeroUsize;
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct NESlice<'a, T> {
pub head: &'a T,
pub tail: &'a [T],
}
impl<'a, T> NESlice<'a, T> {
pub fn new(head: &'a T, tail: &'a [T]) -> Self {
Self { head, tail }
}
pub const fn first(&self) -> &T {
self.head
}
pub fn from_slice(slice: &'a [T]) -> Option<Self> {
slice.split_first().map(|(head, tail)| Self { head, tail })
}
pub fn len(&self) -> NonZeroUsize {
NonZeroUsize::MIN.saturating_add(self.tail.len())
}
pub fn is_empty(&self) -> bool {
false
}
pub fn iter(&self) -> Iter<'_, T> {
Iter {
head: self.head,
iter: std::iter::once(self.head).chain(self.tail.iter()),
}
}
pub fn nonempty_chunks(&'a self, chunk_size: NonZeroUsize) -> NEChunks<'a, T> {
NEChunks {
window: chunk_size,
head: self.head,
tail: self.tail,
index: 0,
}
}
}
impl<'a, T> IntoNonEmptyIterator for NESlice<'a, T> {
type Item = &'a T;
type IntoIter = Iter<'a, T>;
fn into_nonempty_iter(self) -> Self::IntoIter {
Iter {
head: self.head,
iter: std::iter::once(self.head).chain(self.tail.iter()),
}
}
}
#[derive(Debug)]
pub struct Iter<'a, T: 'a> {
head: &'a T,
iter: Chain<Once<&'a T>, std::slice::Iter<'a, T>>,
}
impl<'a, T> NonEmptyIterator for Iter<'a, T> {
type Item = &'a T;
type IntoIter = Skip<Chain<Once<&'a T>, std::slice::Iter<'a, T>>>;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
fn first(self) -> (Self::Item, Self::IntoIter) {
(self.head, self.iter.skip(1))
}
}
impl<'a, T> IntoIterator for Iter<'a, T> {
type Item = &'a T;
type IntoIter = Chain<Once<&'a T>, std::slice::Iter<'a, T>>;
fn into_iter(self) -> Self::IntoIter {
self.iter
}
}
pub struct NEChunks<'a, T> {
pub(crate) window: NonZeroUsize,
pub(crate) head: &'a T,
pub(crate) tail: &'a [T],
pub(crate) index: usize,
}
type SliceFilter<'a, T> = fn(&'a [T]) -> Option<NESlice<'a, T>>;
impl<'a, T> NonEmptyIterator for NEChunks<'a, T> {
type Item = NESlice<'a, T>;
type IntoIter = std::iter::FilterMap<std::slice::Chunks<'a, T>, SliceFilter<'a, T>>;
fn next(&mut self) -> Option<Self::Item> {
if self.index == 0 {
let end = self.window.get() - 1;
let slice = NESlice {
head: self.head,
tail: &self.tail[0..end],
};
self.index = end;
Some(slice)
} else if self.index >= self.tail.len() {
None
} else {
let end = self.index + self.window.get();
let slc: &'a [T] = &self.tail[self.index..end];
match slc {
[] => None,
[head, tail @ ..] => {
let slice = NESlice { head, tail };
self.index = end;
Some(slice)
}
}
}
}
fn first(self) -> (Self::Item, Self::IntoIter) {
let end = self.window.get() - 1;
let slice = NESlice {
head: self.head,
tail: &self.tail[0..end],
};
let tail: &'a [T] = &self.tail[end..];
let rest = tail
.chunks(self.window.get())
.filter_map(NESlice::from_slice as SliceFilter<'a, T>);
(slice, rest)
}
}
impl<'a, T> IntoIterator for NEChunks<'a, T> {
type Item = NESlice<'a, T>;
type IntoIter = IntoIteratorProxy<NEChunks<'a, T>>;
fn into_iter(self) -> Self::IntoIter {
IntoIteratorProxy { iter: self }
}
}
#[cfg(test)]
mod tests {
use std::num::NonZeroUsize;
use crate::{nev, NESlice, NonEmptyIterator};
#[test]
fn test_from_conversion() {
let slice = [1, 2, 3, 4, 5];
let nonempty_slice = NESlice::from_slice(&slice);
let nonempty_slice = nonempty_slice.unwrap();
assert_eq!(nonempty_slice.head, &1);
assert_eq!(nonempty_slice.tail, &[2, 3, 4, 5]);
}
#[test]
fn test_iter_syntax() {
let slice = [0, 1, 2, 3];
let nonempty = NESlice::from_slice(&slice);
for n in &nonempty {
assert_eq!(*n, *n); }
}
#[test]
fn test_into_nonempty_iter() {
use crate::{IntoNonEmptyIterator, NonEmptyIterator};
let slice = [0, 1, 2, 3];
let nonempty = NESlice::new(&slice[0], &slice[1..]);
for (i, n) in nonempty.into_nonempty_iter().enumerate() {
assert_eq!(i as i32, *n);
}
}
#[test]
fn chunks() {
let v = nev![1, 2, 3, 4, 5, 6, 7];
let n = NonZeroUsize::new(3).unwrap();
let a: Vec<_> = v.nonempty_chunks(n).collect();
assert_eq!(
a,
vec![
nev![1, 2, 3].as_nonempty_slice(),
nev![4, 5, 6].as_nonempty_slice(),
nev![7].as_nonempty_slice()
]
);
let n = NonZeroUsize::new(1).unwrap();
let b: Vec<_> = v.nonempty_chunks(n).collect();
assert_eq!(
b,
vec![
nev![1].as_nonempty_slice(),
nev![2].as_nonempty_slice(),
nev![3].as_nonempty_slice(),
nev![4].as_nonempty_slice(),
nev![5].as_nonempty_slice(),
nev![6].as_nonempty_slice(),
nev![7].as_nonempty_slice(),
]
);
}
#[test]
fn chunks_len() {
let v = nev![1, 2, 3];
let n = NonZeroUsize::new(3).unwrap();
let c = v.nonempty_chunks(n).count().get();
assert_eq!(c, 1);
let v = nev![1, 2, 3, 4];
let n = NonZeroUsize::new(3).unwrap();
let c = v.nonempty_chunks(n).count().get();
assert_eq!(c, 2);
}
#[test]
fn chunks_into_iter() {
let v = nev![1, 2, 3];
let n = NonZeroUsize::new(3).unwrap();
let c = v.nonempty_chunks(n);
for slice in c {
let _: NESlice<'_, i32> = slice;
}
}
}