use crate::{mark_initialized, uninit_buf};
pub struct ArrayFromIter<T, const N: usize>(pub Option<[T; N]>);
impl<T, const N: usize> FromIterator<T> for ArrayFromIter<T, N> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
let mut buffer = uninit_buf::<T, N>();
let mut iter = iter.into_iter();
let mut buf_iter = buffer.iter_mut();
loop {
let item = iter.next();
let slot = buf_iter.next();
match (item, slot) {
(Some(item), Some(slot)) => slot.write(item),
(Some(_), None) => return Self(None),
(None, Some(_)) => return Self(None),
(None, None) => return Self(Some(unsafe { mark_initialized(buffer) })),
};
}
}
}
#[cfg(test)]
mod tests {
use crate::testing::vec_strategy;
use proptest::{prop_assert, prop_assert_eq};
use test_strategy::proptest;
use super::*;
#[test]
fn can_collect_array_from_iter() {
let iter = [1, 2, 3].into_iter();
let ArrayFromIter(array) = iter.collect();
assert_eq!(array.unwrap(), [1, 2, 3]);
}
#[test]
fn fails_if_incorrect_number_of_elements() {
let iter = [1, 2, 3].into_iter();
let ArrayFromIter::<_, 4>(array) = iter.collect();
assert!(array.is_none());
let iter = [1, 2, 3].into_iter();
let ArrayFromIter::<_, 2>(array) = iter.collect();
assert!(array.is_none());
}
const LEN: usize = 100;
const SHORT_LEN: usize = LEN - 1;
const LONG_LEN: usize = LEN + 1;
#[proptest]
#[cfg_attr(miri, ignore)]
fn undersized_proptest(#[strategy(vec_strategy(LEN))] vec: Vec<String>) {
let ArrayFromIter::<String, SHORT_LEN>(array) = vec.into_iter().collect();
prop_assert!(array.is_none());
}
#[proptest]
#[cfg_attr(miri, ignore)]
fn oversized_proptest(#[strategy(vec_strategy(LEN))] vec: Vec<String>) {
let ArrayFromIter::<String, LONG_LEN>(array) = vec.into_iter().collect();
prop_assert!(array.is_none());
}
#[proptest]
#[cfg_attr(miri, ignore)]
fn just_right_proptest(#[strategy(vec_strategy(LEN))] vec: Vec<String>) {
let expected: [String; LEN] = vec.clone().try_into().unwrap();
let ArrayFromIter(array) = vec.into_iter().collect();
prop_assert_eq!(array.unwrap(), expected);
}
}