diff --git a/src/lib.rs b/src/lib.rs index 04c5865..d779a86 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -91,6 +91,7 @@ mod from_fn; mod iter; mod sizes; mod traits; +mod zip; pub use crate::{iter::TryFromIteratorError, traits::*}; pub use typenum; @@ -229,6 +230,15 @@ where self.as_mut().iter_mut() } + /// Returns an array of the same size as `self`, with function `f` applied to each element in + /// order. + pub fn map(self, f: F) -> Array + where + F: FnMut(T) -> O, + { + self.into_iter().map(f).collect() + } + /// Concatenates `self` with `other`. #[inline] pub fn concat(self, other: Array) -> Array> diff --git a/src/zip.rs b/src/zip.rs new file mode 100644 index 0000000..8180036 --- /dev/null +++ b/src/zip.rs @@ -0,0 +1,49 @@ +//! Functional programming with [`Array`]s. +// This is modeled after `generic-array::functional` +// see: + +use crate::{Array, ArraySize}; + +impl Array +where + U: ArraySize, +{ + /// Combines two `Array` instances and iterates through both of them, initialization a new + /// `Array` with the result of the zipped mapping function. + /// + /// If the mapping function panics, any already initialized elements in the new array will + /// be dropped, AND any unused elements in the source arrays will also be dropped. + #[inline(always)] + pub fn zip(self, rhs: Array, f: F) -> Array + where + U: ArraySize, + F: FnMut(T, Rhs) -> O, + { + Zipper { + inner: self.into_iter(), + rhs: rhs.into_iter(), + f, + } + .collect() + } +} + +struct Zipper { + inner: I, + rhs: R, + f: F, +} + +impl Iterator for Zipper +where + I: Iterator, + R: Iterator, + F: FnMut(T, RT) -> O, +{ + type Item = O; + + #[inline(always)] + fn next(&mut self) -> Option { + Some((self.f)(self.inner.next()?, self.rhs.next()?)) + } +} diff --git a/tests/mod.rs b/tests/mod.rs index 68aaffd..7d19dfd 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -139,3 +139,18 @@ fn maybe_uninit() { let array = unsafe { uninit_array.assume_init() }; assert_eq!(array.as_slice(), EXAMPLE_SLICE); } + +#[test] +fn test_functional_map() { + let base = Array::::from([1, 2, 3, 4]); + let expected = Array::::from([2, 3, 4, 5]); + assert_eq!(base.map(|item| item + 1), expected); +} + +#[test] +fn test_functional_zip() { + let base = Array::::from([1, 2, 3, 4]); + let with = Array::::from([2, 3, 4, 5]); + let expected = Array::::from([2, 6, 12, 20]); + assert_eq!(base.zip(with, |item, rhs| item * rhs), expected); +}