Repository: rust
Issue: Provide a means of turning iterators into fixed-size arrays
Labels: T-libs-api,C-feature-request,A-iterators,A-array

Now that min_const_generics is approaching there is a great deal of new support for working with fixed-sized arrays, such as `std::array::IntoIter`. But while converting from an array to an iterator is now well-supported, the reverse is lacking:
```rust
let mut a = std::array::IntoIter::new([1,2,3]);
let b: [i32; 3] = a.collect(); // the trait `FromIterator<{integer}>` is not implemented for `[i32; 3]`
```
It is roundaboutly possible to do the conversion by going through Vec:
```rust
let mut a = std::array::IntoIter::new([1,2,3]);
let b: [i32; 3] = a.collect::<Vec<_>>().try_into().unwrap();
```
But that isn't no_std compatible, and even with std there should be no need to allocate here.

The non-allocating way of converting the array presupposes a fair bit of familiarity with the stdlib, unsafe code, and unstable features:
```rust
#![feature(maybe_uninit_uninit_array)]
#![feature(maybe_uninit_array_assume_init)]
let mut array: [MaybeUninit<T>; N] = MaybeUninit::uninit_array();

for i in 0..N {
    array[i] = MaybeUninit::new(iter.next().unwrap());
}

let array = unsafe {
    MaybeUninit::array_assume_init(array)
};
```
...which suggests this is a prime candidate for stdlib inclusion.

The first problem is what the signature should be. There's no way to statically guarantee that an iterator is any given length, so (assuming that you don't want to panic) what is the return type when the iterator might be too short?

1. `-> [T; N]`: straightforward, but you'd have to have `T: Default`, which limits its usefulness. Furthermore this uses in-band signaling to mask what is probably an error (passing in a too-small iterator), which feels user-hostile. This seems little better than panicking.
2. `-> [Option<T>; N]`: the obvious solution to indicate potentially-missing data, but likely annoying to work with in the success case. And sadly [the existing blanket impl](https://doc.rust-lang.org/std/iter/trait.FromIterator.html#impl-FromIterator%3COption%3CA%3E%3E) that ordinarily allows you `.collect` from from a collection of options into an option of a collection can't be leveraged here because you still don't have an impl of `FromIterator<T> for [T; N]`. So if you actually want a `[T; N]` you're left with manually iterating over what was returned, which is to say, you're no better off than having the iterator you started out with!
3. `-> Option<[T; N]>`: the simplest solution that doesn't totally ignore errors. This would be consistent with `std::slice::array_windows` for producing None when a function cannot construct a fixed-size array due to a too-small iterator. However, it unfortunately seems less quite a bit less recoverable in the failure case than the previous approach.
4. `-> Result<[T; N], U>`: same as the previous, though it's possible you could pass something useful back in the error slot. However, as long as the iterator is by-value and unless it's limited to ExactSizeIterators, it might be tricky to pass the data back.
5. `-> ArrayVec<T, N>`: this would be a new type designed to have infallible conversion from `FromIterator`. Actually extracting the fixed-size array would be done through APIs on this type, which avoids some problems in the next section.

IMO approaches 1 and 2 are non-starters.

The second problem is how to perform the conversion.

1. `FromIterator`: the obvious approach, however, it cannot be used with return type 3 from the prior section. This is because of the aforementioned blanket impl for collecting a collection-of-options into an option-of-collections, which conflicts with any attempt to impl `FromIterator<T> for Option<[T; N]>`. I think even specialization can't solve this?
2. `TryFrom`: theoretically you could forgo an impl of `FromIterator<T>` and instead impl `TryFrom<I: IntoIterator<Item=T>>`; hacky, but at least you're still using *some* standard conversion type. Sadly, https://github.com/rust-lang/rust/issues/50133 makes it impossible to actually write this impl; people claim that specialization could theoretically address that, but I don't know enough about the current implementation to know if it's sufficient for this case.
3. Introduce a new `TryFromIterator` trait. This would work, but this also implies a new `TryIntoIterator` trait and `Iterator::try_collect`. Likely the most principled approach.
4. A new `std::array::TryCollect` trait, impl'd for `I: IntoIterator`. Less principled than the prior approach but less machinery for if you happen to think `TryFromIterator` and `TryIntoIterator` wouldn't be broadly useful.
5. A new `std::array::from_iter` function. The simplest and least general approach. Less consistent with `.collect` than the previous approach, but broadly consistent with `std::array::IntoIter` (although that itself is considered a temporary stopgap until `.into_iter` works on arrays). Similarly, could be an inherent associated function impl'd on `[T; N]`.
6. Come up with some wacky const-generics shenanigans that would allow `FromIterator<T> for [T; N]` to Just Work, possibly via introducing a new const-generics aware version of ExactSizeIterator. If this could be done it would unquestionably be the most promising way to proceed, but I don't have the faintest idea where to begin.
7. A new method `Iterator::collect_array` as a hardcoded alternative to collect. Similarly, an Iterator-specific equivalent of `slice::array_chunks` could fill the same role while also being potentially more flexible.

Any other suggestions?