use crate::{storage::DimensionalStorage, Dimensional};
use num_traits::Num;
pub struct DimensionalIter<'a, T, S, const N: usize>
where
T: Num + Copy,
S: DimensionalStorage<T, N>,
{
dimensional: &'a Dimensional<T, S, N>,
current_index: [usize; N],
remaining: usize,
}
impl<'a, T, S, const N: usize> Iterator for DimensionalIter<'a, T, S, N>
where
T: Num + Copy,
S: DimensionalStorage<T, N>,
{
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
if self.remaining == 0 {
return None;
}
let result = &self.dimensional[self.current_index];
for i in (0..N).rev() {
self.current_index[i] += 1;
if self.current_index[i] < self.dimensional.shape()[i] {
break;
}
self.current_index[i] = 0;
}
self.remaining -= 1;
Some(result)
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining, Some(self.remaining))
}
}
impl<'a, T, S, const N: usize> ExactSizeIterator for DimensionalIter<'a, T, S, N>
where
T: Num + Copy,
S: DimensionalStorage<T, N>,
{
}
pub struct DimensionalIterMut<'a, T, S, const N: usize>
where
T: Num + Copy,
S: DimensionalStorage<T, N>,
{
dimensional: &'a mut Dimensional<T, S, N>,
current_index: [usize; N],
remaining: usize,
}
impl<'a, T, S, const N: usize> Iterator for DimensionalIterMut<'a, T, S, N>
where
T: Num + Copy,
S: DimensionalStorage<T, N>,
{
type Item = &'a mut T;
fn next(&mut self) -> Option<Self::Item> {
if self.remaining == 0 {
return None;
}
let index = self.current_index;
for i in (0..N).rev() {
self.current_index[i] += 1;
if self.current_index[i] < self.dimensional.shape()[i] {
break;
}
self.current_index[i] = 0;
}
self.remaining -= 1;
let linear_index = Dimensional::<T, S, N>::ravel_index(&index, &self.dimensional.shape());
unsafe { Some(&mut *(&mut self.dimensional.as_mut_slice()[linear_index] as *mut T)) }
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining, Some(self.remaining))
}
}
impl<T, S, const N: usize> Dimensional<T, S, N>
where
T: Num + Copy,
S: DimensionalStorage<T, N>,
{
pub fn iter(&self) -> DimensionalIter<T, S, N> {
DimensionalIter {
dimensional: self,
current_index: [0; N],
remaining: self.len(),
}
}
pub fn iter_mut(&mut self) -> DimensionalIterMut<T, S, N> {
let len = self.len();
DimensionalIterMut {
dimensional: self,
current_index: [0; N],
remaining: len,
}
}
}
impl<'a, T, S, const N: usize> IntoIterator for &'a Dimensional<T, S, N>
where
T: Num + Copy,
S: DimensionalStorage<T, N>,
{
type Item = &'a T;
type IntoIter = DimensionalIter<'a, T, S, N>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, T, S, const N: usize> IntoIterator for &'a mut Dimensional<T, S, N>
where
T: Num + Copy,
S: DimensionalStorage<T, N>,
{
type Item = &'a mut T;
type IntoIter = DimensionalIterMut<'a, T, S, N>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
#[cfg(test)]
mod tests {
use crate::{matrix, storage::LinearArrayStorage, Dimensional};
#[test]
fn test_iter_mut_borrow() {
let mut m = matrix![[1, 2], [3, 4]];
let mut iter = m.iter_mut();
assert_eq!(iter.next(), Some(&mut 1));
assert_eq!(iter.next(), Some(&mut 2));
assert_eq!(iter.next(), Some(&mut 3));
assert_eq!(iter.next(), Some(&mut 4));
assert_eq!(iter.next(), None);
}
}