Collect to slice
This is an enhancement suggestion. Beside the current collect() to collection like Vec, Hash, etc, and the future collect to array:
https://github.com/rust-lang/rust/pull/69985
I find it useful to also collect to a slice when I don't know at compile-time the exact length of the resulting array, but I know an upper bound of its length.
I have adapted the following code from this crate: https://github.com/kchmck/collect_slice https://crates.io/crates/collect_slice
trait CollectSlice<'a>: Iterator {
fn inner(&mut self, slice: &'a mut [Self::Item]) -> &'a [Self::Item];
fn inner_mut(&mut self, slice: &'a mut [Self::Item]) -> &'a mut [Self::Item];
fn collect_slice(&mut self, slice: &'a mut [Self::Item]) -> &'a [Self::Item] {
let result = self.inner(slice);
assert!(self.next().is_none());
result
}
fn collect_slice_mut(&mut self, slice: &'a mut [Self::Item]) -> &'a mut [Self::Item] {
let result = self.inner_mut(slice);
assert!(self.next().is_none());
result
}
}
impl<I: ?Sized> CollectSlice<'a> for I where I: Iterator {
fn inner(&mut self, slice: &'a mut [Self::Item]) -> &'a [Self::Item] {
let count = slice.iter_mut().zip(self).fold(0, |count, (dest, item)| {
*dest = item;
count + 1
});
&slice[.. count]
}
fn inner_mut(&mut self, slice: &'a mut [Self::Item]) -> &'a mut [Self::Item] {
let count = slice.iter_mut().zip(self).fold(0, |count, (dest, item)| {
*dest = item;
count + 1
});
&mut slice[.. count]
}
}
This code should be improved and simplified. And as in Issue #69985 we could return a Result<> instead, and remove the asserts.
I think I'm a little uncertain about passing in
&mut [T]since that seems prone to "but I don't want to initialize my Ts" -- we'd probably want something like&mut [MaybeUninit<T>]though that raises questions as well.Mark Rousskov at 2020-04-21 16:16:55
I think I'm a little uncertain about passing in
&mut [T]since that seems prone to "but I don't want to initialize my Ts" -- we'd probably want something like&mut [MaybeUninit<T>]though that raises questions as well.Mark Rousskov at 2020-04-21 16:19:38
I have found collect_slice useful, but I am still unsure if it's worth having in the std lib (while I am sure I want #69985, useful mostly for small arrays) because its usage is not very clean:
let primes = &mut [0; 1000]; let primes = (2_u32 .. 1000) .filter(|&b| is_prime(b)) .collect_slice(primes);That is equivalent to:
let primes = &mut [0; 1000]; let mut index = 0; for b in 2_u32 .. 1000 { if is_prime(b) { primes[index] = b; index += 1; } } let primes = &[.. index];In all my usage cases I don't use collect_slice in the middle of an iterators chain because of memory ownership issues, so I use it only at the end of iterators chains like in the above example, and only when the number of items is high enough and I don't know it at compile-time.
leonardo-m at 2020-04-21 16:39:48