1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
//! This crate makes it possible to initialise arrays from iterators. //! //! # Examples: //! //! ```rust //! use from_iter::FromIterator; //! //! let iter = (0..).map(|i| i * 2); //! let array = <[i32; 8]>::from_iter(iter); //! assert_eq!(array, [0, 2, 4, 6, 8, 10, 12, 14]); //! ``` //! //! ```rust //! use from_iter::FromIterator; //! //! let first = vec![1, 1, 2, 3, 5, 8, 13, 21, 34].into_iter(); //! let even_fibonaccis = first.filter(|n| n % 2 == 0); //! let array = <[i32; 3]>::from_iter(even_fibonaccis); //! ``` //! //! ```rust //! use from_iter::FromIterator; //! //! let short_iterator = vec![1, 2, 3].into_iter(); //! let long_array = match <[i32; 1000]>::try_from_iter(short_iterator) { //! Ok(long_array) => long_array, //! Err(e) => { //! eprintln!("{}", e); //! return; //! } //! }; //! ``` //! //! Note that the [from_iter](crate::FromIterator::from_iter) method will panic if the iterator //! does not provide enough elements to fill the entire array. To avoid this, consider using the //! [try_from_iter](crate::FromIterator::try_from_iter) method instead. //! //! Both methods will ignore any extra elements in the iterator. //! use std::{error, fmt, mem}; /// This trait contains the [from_iter](crate::FromIterator::from_iter) and /// [try_from_iter](crate::FromIterator::try_from_iter) methods. /// /// Example: /// ```rust /// use from_iter::FromIterator; /// /// let iter = (0..).map(|i| i * 2); /// let array = <[i32; 8]>::from_iter(iter); /// assert_eq!(array, [0, 2, 4, 6, 8, 10, 12, 14]); /// ``` pub trait FromIterator<A>: Sized { /// This method fills an array using the given iterator. Note that it /// will panic if the iterator doesn't contain enough items. fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self; /// This method fills an array using the given iterator. If there aren't /// enough items available, it will return a [FromIteratorError]. fn try_from_iter<T: IntoIterator<Item = A>>(iter: T) -> Result<Self, FromIteratorError>; } /// This represents the error when there aren't enough items available to fill the /// entire array. #[derive(Debug, Clone, PartialEq, Eq)] pub struct FromIteratorError; impl fmt::Display for FromIteratorError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "iterator exhausted unexpectedly") } } impl error::Error for FromIteratorError {} impl<A, const N: usize> FromIterator<A> for [A; N] { fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self { Self::try_from_iter(iter).expect("iterator exhausted unexpectedly") } fn try_from_iter<T: IntoIterator<Item = A>>(iter: T) -> Result<Self, FromIteratorError> { let mut iterator = iter.into_iter(); // use [MaybeUninit::uninit_array] when that method stabilizes let mut array: [mem::MaybeUninit<A>; N] = unsafe { // This `assume_init` call is safe because we are initialising // a bunch of `MaybeUninit`s, which do not require initialisation. mem::MaybeUninit::uninit().assume_init() }; for elem in &mut array[..] { // now fill the array using the iterator *elem = mem::MaybeUninit::new(iterator.next().ok_or(FromIteratorError)?); } let array_ptr = &array as *const _ as *const [A; N]; // use [MaybeUninit::array_assume_init] when that method stabilizes Ok(unsafe { // This requires the pointer to be valid, properly aligned, and correctly // initialised. It would be better to use [std::mem::transmute] here, // but that is not possible because the types depend on the const // parameter `N`. array_ptr.read() }) } } #[cfg(test)] mod tests { use super::FromIterator; #[test] fn it_works() { let iter = (0..).map(|i| i * 2); let arr = <[i32; 8]>::from_iter(iter); assert_eq!(arr, [0, 2, 4, 6, 8, 10, 12, 14]); } #[test] #[allow(unused_imports)] fn no_conflict() { use std::iter::FromIterator; let _arr = <[i32; 8]>::from_iter(0..); } #[test] fn try_from_iter() { let huge_array = <[i32; 1000]>::try_from_iter(0..).unwrap(); assert_eq!(huge_array[0], 0); assert_eq!(huge_array[1], 1); assert_eq!(huge_array[2], 2); assert_eq!(huge_array[999], 999); } #[test] fn try_from_iter_error() { <[i32; 1000]>::try_from_iter(std::iter::once(5)).unwrap_err(); } }