Skip to content

Commit

Permalink
[WIP] Add Array::try_from_iter
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
tarcieri committed Jan 11, 2024
1 parent 1e56a38 commit d8817fb
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 61 deletions.
91 changes: 91 additions & 0 deletions src/iter.rs
Original file line number Diff line number Diff line change
@@ -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<T, U> Array<T, U>
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<I: IntoIterator<Item = T>>(iter: I) -> Result<Self, TryFromIteratorError> {
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<T, U> FromIterator<T> for Array<T, U>
where
U: ArraySize,
{
fn from_iter<I: IntoIterator<Item = T>>(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<T, U> IntoIterator for Array<T, U>
where
U: ArraySize,
{
type Item = T;
type IntoIter = <U::ArrayType<T> 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<T, U>
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<T, U>
where
U: ArraySize,
{
type Item = &'a mut T;
type IntoIter = IterMut<'a, T>;

#[inline]
fn into_iter(self) -> IterMut<'a, T> {
self.iter_mut()
}
}
62 changes: 1 addition & 61 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
)]

mod from_fn;
mod iter;
mod sizes;

pub use crate::from_fn::FromFn;
Expand Down Expand Up @@ -432,25 +433,6 @@ where
}
}

impl<T, U> FromIterator<T> for Array<T, U>
where
U: ArraySize,
{
fn from_iter<I: IntoIterator<Item = T>>(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<T, U> Hash for Array<T, U>
where
T: Hash,
Expand Down Expand Up @@ -486,48 +468,6 @@ where
}
}

impl<T, U> IntoIterator for Array<T, U>
where
U: ArraySize,
{
type Item = T;
type IntoIter = <U::ArrayType<T> 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<T, U>
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<T, U>
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<T, U> PartialEq for Array<T, U>
where
T: PartialEq,
Expand Down
18 changes: 18 additions & 0 deletions tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,21 @@ fn from_iterator_too_short() {
fn from_iterator_too_long() {
let _array: Array<u8, U5> = EXAMPLE_SLICE.iter().copied().collect();
}

#[test]
fn try_from_iterator_correct_size() {
let array = Array::<u8, U6>::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::<u8, U7>::try_from_iter(EXAMPLE_SLICE.iter().copied());
assert!(result.is_err());
}

#[test]
fn try_from_iterator_too_long() {
let result = Array::<u8, U5>::try_from_iter(EXAMPLE_SLICE.iter().copied());
assert!(result.is_err());
}

0 comments on commit d8817fb

Please sign in to comment.