Skip to content

Commit 4a0dbad

Browse files
committed
spec next chunk for trustedlen
1 parent d3f16d2 commit 4a0dbad

File tree

1 file changed

+34
-3
lines changed

1 file changed

+34
-3
lines changed

library/core/src/array/mod.rs

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::convert::Infallible;
1111
use crate::error::Error;
1212
use crate::hash::{self, Hash};
1313
use crate::intrinsics::transmute_unchecked;
14-
use crate::iter::{UncheckedIterator, repeat_n};
14+
use crate::iter::{TrustedLen, UncheckedIterator, repeat_n};
1515
use crate::marker::Destruct;
1616
use crate::mem::{self, ManuallyDrop, MaybeUninit};
1717
use crate::ops::{
@@ -964,6 +964,12 @@ impl<T: [const] Destruct> const Drop for Guard<'_, T> {
964964
}
965965
}
966966

967+
pub(crate) fn iter_next_chunk<T, const N: usize>(
968+
iter: &mut impl Iterator<Item = T>,
969+
) -> Result<[T; N], IntoIter<T, N>> {
970+
iter.spec_next_chunk()
971+
}
972+
#[inline]
967973
/// Pulls `N` items from `iter` and returns them as an array. If the iterator
968974
/// yields fewer than `N` items, `Err` is returned containing an iterator over
969975
/// the already yielded items.
@@ -976,8 +982,7 @@ impl<T: [const] Destruct> const Drop for Guard<'_, T> {
976982
/// dropped.
977983
///
978984
/// Used for [`Iterator::next_chunk`].
979-
#[inline]
980-
pub(crate) fn iter_next_chunk<T, const N: usize>(
985+
fn generic_iter_next_chunk<T, const N: usize>(
981986
iter: &mut impl Iterator<Item = T>,
982987
) -> Result<[T; N], IntoIter<T, N>> {
983988
let mut array = [const { MaybeUninit::uninit() }; N];
@@ -994,6 +999,32 @@ pub(crate) fn iter_next_chunk<T, const N: usize>(
994999
}
9951000
}
9961001

1002+
pub(crate) trait SpecNextChunk<T, const N: usize>: Iterator<Item = T> {
1003+
fn spec_next_chunk(&mut self) -> Result<[T; N], IntoIter<T, N>>;
1004+
}
1005+
impl<I: Iterator<Item = T>, T, const N: usize> SpecNextChunk<T, N> for I {
1006+
default fn spec_next_chunk(&mut self) -> Result<[T; N], IntoIter<T, N>> {
1007+
generic_iter_next_chunk(self)
1008+
}
1009+
}
1010+
1011+
impl<I: Iterator<Item = T> + TrustedLen, T, const N: usize> SpecNextChunk<T, N> for I {
1012+
fn spec_next_chunk(&mut self) -> Result<[T; N], IntoIter<T, N>> {
1013+
if self.size_hint().0 < N {
1014+
let mut array = [const { MaybeUninit::uninit() }; N];
1015+
let initialized =
1016+
// SAFETY: Has to error out; trusted len means that
1017+
// SAFETY: there may only be less than N elements
1018+
unsafe { iter_next_chunk_erased(&mut array, self).unwrap_err_unchecked() };
1019+
// SAFETY: Only the first `initialized` elements were populated
1020+
return Err(unsafe { IntoIter::new_unchecked(array, 0..initialized) });
1021+
} else {
1022+
// SAFETY: must be at least N elements; safe to unwrap N elements.
1023+
return Ok(from_fn(|_| unsafe { self.next().unwrap_unchecked() }));
1024+
}
1025+
}
1026+
}
1027+
9971028
/// Version of [`iter_next_chunk`] using a passed-in slice in order to avoid
9981029
/// needing to monomorphize for every array length.
9991030
///

0 commit comments

Comments
 (0)