#![doc = include_str!("../README.md")]
#![feature(raw_slice_split)]
use std::marker::PhantomData;
pub trait Divide<T> {
fn divide(&self, n: usize) -> Portion<'_, T>;
fn divide_mut(&mut self, n: usize) -> PortionMut<'_, T>;
}
impl<T> Divide<T> for [T] {
fn divide(&self, n: usize) -> Portion<'_, T> {
assert!(n != 0, "cannot divide into zero portions");
Portion::new(self, n)
}
fn divide_mut(&mut self, n: usize) -> PortionMut<'_, T> {
assert!(n != 0, "cannot divide into zero portions");
PortionMut::new(self, n)
}
}
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct Portion<'a, T: 'a> {
v: &'a [T],
n: usize,
}
impl<'a, T: 'a> Portion<'a, T> {
#[inline]
pub fn new(slice: &'a [T], n: usize) -> Self {
Self { v: slice, n }
}
}
impl<'a, T> Iterator for Portion<'a, T> {
type Item = &'a [T];
#[inline]
fn next(&mut self) -> Option<&'a [T]> {
if self.n == 0 {
None
} else {
let portionsz = self.v.len().div_ceil(self.n);
self.n -= 1;
let (fst, snd) = self.v.split_at(portionsz);
self.v = snd;
Some(fst)
}
}
}
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct PortionMut<'a, T: 'a> {
v: *mut [T],
n: usize,
_marker: PhantomData<&'a mut T>,
}
impl<'a, T: 'a> PortionMut<'a, T> {
#[inline]
pub fn new(slice: &'a mut [T], n: usize) -> Self {
Self {
v: slice,
n,
_marker: PhantomData,
}
}
}
impl<'a, T> Iterator for PortionMut<'a, T> {
type Item = &'a mut [T];
#[inline]
fn next(&mut self) -> Option<&'a mut [T]> {
if self.n == 0 {
None
} else {
let portionsz = self.v.len().div_ceil(self.n);
self.n -= 1;
let (fst, snd) = unsafe { self.v.split_at_mut(portionsz) };
self.v = snd;
Some(unsafe { &mut *fst })
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn divide_no_remainder() {
let slice = ['a', 'b', 'c', 'd', 'e', 'f'];
let mut iter = slice.divide(3);
assert_eq!(iter.next(), Some(&['a', 'b'][..]));
assert_eq!(iter.next(), Some(&['c', 'd'][..]));
assert_eq!(iter.next(), Some(&['e', 'f'][..]));
assert_eq!(iter.next(), None);
}
#[test]
fn divide_with_reminder() {
let slice = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'];
let mut iter = slice.divide(4);
assert_eq!(iter.next(), Some(&['a', 'b', 'c'][..]));
assert_eq!(iter.next(), Some(&['d', 'e'][..]));
assert_eq!(iter.next(), Some(&['f', 'g'][..]));
assert_eq!(iter.next(), Some(&['h', 'i'][..]));
assert_eq!(iter.next(), None);
}
#[test]
fn divide_smaller_size() {
let slice = ['a', 'b'];
let mut iter = slice.divide(3);
assert_eq!(iter.next(), Some(&['a'][..]));
assert_eq!(iter.next(), Some(&['b'][..]));
assert_eq!(iter.next(), Some(&[][..]));
assert_eq!(iter.next(), None);
}
#[test]
fn divide_empty_slice() {
let slice: [char; 0] = [];
let mut iter = slice.divide(3);
assert_eq!(iter.next(), Some(&[][..]));
assert_eq!(iter.next(), Some(&[][..]));
assert_eq!(iter.next(), Some(&[][..]));
assert_eq!(iter.next(), None);
}
#[test]
#[should_panic]
fn divide_by_zero() {
let slice = ['a', 'b'];
let _ = slice.divide(0);
}
#[test]
fn divide_mut_no_remainder() {
let mut slice = [1, 2, 3, 4, 5, 6];
slice.divide_mut(3).for_each(|e| e[0] += 1);
let mut iter = slice.divide_mut(3);
assert_eq!(iter.next(), Some(&mut [2, 2][..]));
assert_eq!(iter.next(), Some(&mut [4, 4][..]));
assert_eq!(iter.next(), Some(&mut [6, 6][..]));
assert_eq!(iter.next(), None);
}
#[test]
fn divide_mut_with_remainder() {
let mut slice = [1, 2, 3, 4, 5];
slice.divide_mut(3).for_each(|e| e[0] += 1);
let mut iter = slice.divide_mut(3);
assert_eq!(iter.next(), Some(&mut [2, 2][..]));
assert_eq!(iter.next(), Some(&mut [4, 4][..]));
assert_eq!(iter.next(), Some(&mut [6][..]));
assert_eq!(iter.next(), None);
}
#[test]
fn divide_mut_smaller_size() {
let mut slice = [1, 2];
slice.divide_mut(3).for_each(|e| if e.len() > 0 { e[0] += 1 });
let mut iter = slice.divide_mut(3);
assert_eq!(iter.next(), Some(&mut [2][..]));
assert_eq!(iter.next(), Some(&mut [3][..]));
assert_eq!(iter.next(), Some(&mut [][..]));
assert_eq!(iter.next(), None);
}
#[test]
fn divide_mut_empty() {
let mut slice: [char; 0] = [];
let mut iter = slice.divide_mut(3);
assert_eq!(iter.next(), Some(&mut [][..]));
assert_eq!(iter.next(), Some(&mut [][..]));
assert_eq!(iter.next(), Some(&mut [][..]));
assert_eq!(iter.next(), None);
}
}