Can anyone tell me how the hell this function works (mod.rs - source)? What are we returning?
In this function, I understand MaybeUninit
, Guard
and other low-level parts. I partially understand how the Try
trait works and completely broke my head trying to understand R: Residual<[T; N]>
, Result<R::TryType, IntoIter<T, N>>
, Ok(Try::from_output(output))
. Complete function code:
/// Pulls `N` items from `iter` and returns them as an array. If the iterator
/// yields fewer than `N` items, `Err` is returned containing an iterator over
/// the already yielded items.
///
/// Since the iterator is passed as a mutable reference and this function calls
/// `next` at most `N` times, the iterator can still be used afterwards to
/// retrieve the remaining items.
///
/// If `iter.next()` panicks, all items already yielded by the iterator are
/// dropped.
#[inline]
fn try_collect_into_array<I, T, R, const N: usize>(
iter: &mut I,
) -> Result<R::TryType, IntoIter<T, N>>
where
I: Iterator,
I::Item: Try<Output = T, Residual = R>,
R: Residual<[T; N]>,
{
if N == 0 {
// SAFETY: An empty array is always inhabited and has no validity invariants.
return Ok(Try::from_output(unsafe { mem::zeroed() }));
}
let mut array = MaybeUninit::uninit_array::<N>();
let mut guard = Guard { array_mut: &mut array, initialized: 0 };
for _ in 0..N {
match iter.next() {
Some(item_rslt) => {
let item = match item_rslt.branch() {
ControlFlow::Break(r) => {
return Ok(FromResidual::from_residual(r));
}
ControlFlow::Continue(elem) => elem,
};
// SAFETY: `guard.initialized` starts at 0, which means push can be called
// at most N times, which this loop does.
unsafe {
guard.push_unchecked(item);
}
}
None => {
let alive = 0..guard.initialized;
mem::forget(guard);
// SAFETY: `array` was initialized with exactly `initialized`
// number of elements.
return Err(unsafe { IntoIter::new_unchecked(array, alive) });
}
}
}
mem::forget(guard);
// SAFETY: All elements of the array were populated in the loop above.
let output = unsafe { array.transpose().assume_init() };
Ok(Try::from_output(output))
}