diff --git a/Cargo.lock b/Cargo.lock index e5143c4..36b520e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1054,6 +1054,8 @@ dependencies = [ [[package]] name = "toad-array" version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "684a00a1501494fb37b8af23bfdf7b5f0a19ef71963abdf5e19eb4afb505f55a" dependencies = [ "tinyvec", "toad-len 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1061,9 +1063,7 @@ dependencies = [ [[package]] name = "toad-array" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "684a00a1501494fb37b8af23bfdf7b5f0a19ef71963abdf5e19eb4afb505f55a" +version = "0.6.0" dependencies = [ "tinyvec", "toad-len 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1114,7 +1114,7 @@ dependencies = [ "no-std-net", "tinyvec", "toad 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)", - "toad-array 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "toad-array 0.5.0", "toad-len 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "toad-msg 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", "toad-stem 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/toad-array/src/lib.rs b/toad-array/src/lib.rs index fb8e3cc..a3ca047 100644 --- a/toad-array/src/lib.rs +++ b/toad-array/src/lib.rs @@ -28,6 +28,7 @@ #[cfg(feature = "alloc")] extern crate alloc as std_alloc; +use core::marker::PhantomData; use core::ops::{Deref, DerefMut}; use core::slice::SliceIndex; @@ -35,6 +36,82 @@ use core::slice::SliceIndex; use std_alloc::vec::Vec; use toad_len::Len; +/// An iterator over immutable references to items `T` in collection `I` +#[derive(Debug)] +pub struct IndexedIter<'a, I, T> { + collection: &'a I, + index: usize, + len: usize, + _t: PhantomData, +} + +impl<'a, I, T> Iterator for IndexedIter<'a, I, T> + where I: Indexed, + T: 'a +{ + type Item = I::Ref<'a>; + + fn next(&mut self) -> Option { + if self.index >= self.len { + None + } else { + let el = self.collection.get(self.index).unwrap(); + self.index += 1; + Some(el) + } + } + + fn size_hint(&self) -> (usize, Option) { + (self.len, Some(self.len)) + } +} +impl<'a, I, T> ExactSizeIterator for IndexedIter<'a, I, T> + where I: Indexed, + T: 'a +{ +} + +/// An iterator over mutable references to items `T` in collection `I` +#[derive(Debug)] +pub struct IndexedIterMut<'a, I, T> { + collection: &'a mut I, + index: usize, + len: usize, + _t: PhantomData, +} + +impl<'a, I, T> Iterator for IndexedIterMut<'a, I, T> + where I: Indexed, + T: 'a +{ + type Item = I::RefMut<'a>; + + #[allow(unsafe_code)] + fn next(&mut self) -> Option { + if self.index >= self.len { + None + } else { + // SAFETY: + // We can safely split the `self.collection` mutable borrow because + // we narrow it to a single element, and we will never issue + // multiple mutable references to the same element. + let i: &'a mut I = unsafe { (self.collection as *mut I).as_mut().unwrap() }; + let el = i.get_mut(self.index).unwrap(); + self.index += 1; + Some(el) + } + } + + fn size_hint(&self) -> (usize, Option) { + (self.len, Some(self.len)) + } +} +impl<'a, I, T> ExactSizeIterator for IndexedIterMut<'a, I, T> + where I: Indexed, + T: 'a +{ +} + /// Operations on ordered indexed collections pub trait Indexed where Self: Len @@ -52,6 +129,68 @@ pub trait Indexed where Self: 'a, T: 'a; + /// Iterate over the elements in the collection + /// + /// ``` + /// use core::ops::Deref; + /// + /// use tinyvec::{array_vec, ArrayVec}; + /// use toad_array::Indexed; + /// + /// let v: Vec = vec![1, 2, 3, 4]; + /// let av: ArrayVec<[usize; 16]> = array_vec![1, 2, 3, 4]; + /// + /// fn foo(i: &I) + /// where I: Indexed + /// { + /// assert_eq!(i.iter().map(|n| *n.deref()).sum::(), 10) + /// } + /// + /// foo(&v); + /// foo(&av); + /// ``` + fn iter<'a>(&'a self) -> IndexedIter<'a, Self, T> + where Self: Sized + { + IndexedIter { collection: self, + index: 0, + len: self.len(), + _t: PhantomData } + } + + /// Iterate mutably over the elements in the collection + /// + /// ``` + /// use core::ops::{Deref, DerefMut}; + /// + /// use tinyvec::{array_vec, ArrayVec}; + /// use toad_array::Indexed; + /// + /// let mut v: Vec = vec![1, 2, 3, 4]; + /// let mut av: ArrayVec<[usize; 16]> = array_vec![1, 2, 3, 4]; + /// + /// fn foo(i: &mut I) + /// where I: Indexed + /// { + /// i.iter_mut().for_each(|mut n| *n.deref_mut() = 0); + /// assert!(i.iter() + /// .map(|n| *n.deref()) + /// .eq(vec![0usize, 0, 0, 0].into_iter())); + /// } + /// + /// foo(&mut v); + /// foo(&mut av); + /// ``` + fn iter_mut<'a>(&'a mut self) -> IndexedIterMut<'a, Self, T> + where Self: Sized + { + let len = self.len(); + IndexedIterMut { collection: self, + index: 0, + len, + _t: PhantomData } + } + /// Get an immutable reference to element at `ix` fn get<'a>(&'a self, ix: usize) -> Option>;