From d8817fba074c8cf9bfc9760ba1967cf58db66fd8 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Thu, 11 Jan 2024 10:49:30 -0700 Subject: [PATCH] [WIP] Add `Array::try_from_iter` Adds a fallible equivalent to `FromIterator` which returns `TryFromIteratorError` if the number of items in the iterator does not match the size of the array. --- src/iter.rs | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 62 +---------------------------------- tests/mod.rs | 18 +++++++++++ 3 files changed, 110 insertions(+), 61 deletions(-) create mode 100644 src/iter.rs diff --git a/src/iter.rs b/src/iter.rs new file mode 100644 index 0000000..686a93a --- /dev/null +++ b/src/iter.rs @@ -0,0 +1,91 @@ +//! Support for constructing arrays using a provided iterator function and other iterator-related +//! functionality. + +use crate::{Array, ArraySize}; +use core::slice::{Iter, IterMut}; + +/// Couldn't construct an array from an iterator because the number of items in the iterator +/// didn't match the array size. +#[derive(Clone, Copy, Debug)] +pub struct TryFromIteratorError; + +impl Array +where + U: ArraySize, +{ + /// Construct an array from the given iterator, returning [`TryFromIteratorError`] in the event + /// that the number of items in the iterator does not match the array size. + pub fn try_from_iter>(iter: I) -> Result { + let mut iter = iter.into_iter(); + let ret = Self::try_from_fn(|_| iter.next().ok_or(TryFromIteratorError))?; + + match iter.next() { + None => Ok(ret), + Some(_) => Err(TryFromIteratorError), + } + } +} + +impl FromIterator for Array +where + U: ArraySize, +{ + fn from_iter>(iter: I) -> Self { + let mut iter = iter.into_iter(); + let ret = Self::from_fn(|_| { + iter.next() + .expect("iterator should have enough items to fill array") + }); + + assert!( + iter.next().is_none(), + "too many items in iterator to fit in array" + ); + + ret + } +} + +impl IntoIterator for Array +where + U: ArraySize, +{ + type Item = T; + type IntoIter = as IntoIterator>::IntoIter; + + /// Creates a consuming iterator, that is, one that moves each value out of the array (from + /// start to end). + /// + /// The array cannot be used after calling this unless `T` implements `Copy`, so the whole + /// array is copied. + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + +impl<'a, T, U> IntoIterator for &'a Array +where + U: ArraySize, +{ + type Item = &'a T; + type IntoIter = Iter<'a, T>; + + #[inline] + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +impl<'a, T, U> IntoIterator for &'a mut Array +where + U: ArraySize, +{ + type Item = &'a mut T; + type IntoIter = IterMut<'a, T>; + + #[inline] + fn into_iter(self) -> IterMut<'a, T> { + self.iter_mut() + } +} diff --git a/src/lib.rs b/src/lib.rs index 535de86..6a3c450 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,6 +24,7 @@ )] mod from_fn; +mod iter; mod sizes; pub use crate::from_fn::FromFn; @@ -432,25 +433,6 @@ where } } -impl FromIterator for Array -where - U: ArraySize, -{ - fn from_iter>(iter: I) -> Self { - let mut iter = iter.into_iter(); - let ret = Self::from_fn(|_| { - iter.next() - .expect("iterator should have enough items to fill array") - }); - - assert!( - iter.next().is_none(), - "too many items in iterator to fit in array" - ); - ret - } -} - impl Hash for Array where T: Hash, @@ -486,48 +468,6 @@ where } } -impl IntoIterator for Array -where - U: ArraySize, -{ - type Item = T; - type IntoIter = as IntoIterator>::IntoIter; - - /// Creates a consuming iterator, that is, one that moves each value out of - /// the array (from start to end). The array cannot be used after calling - /// this unless `T` implements `Copy`, so the whole array is copied. - #[inline] - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -impl<'a, T, U> IntoIterator for &'a Array -where - U: ArraySize, -{ - type Item = &'a T; - type IntoIter = Iter<'a, T>; - - #[inline] - fn into_iter(self) -> Iter<'a, T> { - self.iter() - } -} - -impl<'a, T, U> IntoIterator for &'a mut Array -where - U: ArraySize, -{ - type Item = &'a mut T; - type IntoIter = IterMut<'a, T>; - - #[inline] - fn into_iter(self) -> IterMut<'a, T> { - self.iter_mut() - } -} - impl PartialEq for Array where T: PartialEq, diff --git a/tests/mod.rs b/tests/mod.rs index 0073b52..d27de1d 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -108,3 +108,21 @@ fn from_iterator_too_short() { fn from_iterator_too_long() { let _array: Array = EXAMPLE_SLICE.iter().copied().collect(); } + +#[test] +fn try_from_iterator_correct_size() { + let array = Array::::try_from_iter(EXAMPLE_SLICE.iter().copied()).unwrap(); + assert_eq!(array.as_slice(), EXAMPLE_SLICE); +} + +#[test] +fn try_from_iterator_too_short() { + let result = Array::::try_from_iter(EXAMPLE_SLICE.iter().copied()); + assert!(result.is_err()); +} + +#[test] +fn try_from_iterator_too_long() { + let result = Array::::try_from_iter(EXAMPLE_SLICE.iter().copied()); + assert!(result.is_err()); +}