|
1 | | -use crate::fmt; |
2 | 1 | use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; |
| 2 | +use crate::mem::{ManuallyDrop, MaybeUninit}; |
3 | 3 | use crate::ops::{ControlFlow, Try}; |
| 4 | +use crate::{array, fmt}; |
4 | 5 |
|
5 | 6 | /// An iterator that uses `f` to both filter and map elements from `iter`. |
6 | 7 | /// |
|
61 | 62 | self.iter.find_map(&mut self.f) |
62 | 63 | } |
63 | 64 |
|
| 65 | + #[inline] |
| 66 | + fn next_chunk<const N: usize>( |
| 67 | + &mut self, |
| 68 | + ) -> Result<[Self::Item; N], array::IntoIter<Self::Item, N>> { |
| 69 | + let mut array: [MaybeUninit<Self::Item>; N] = MaybeUninit::uninit_array(); |
| 70 | + |
| 71 | + struct Guard<'a, T> { |
| 72 | + array: &'a mut [MaybeUninit<T>], |
| 73 | + initialized: usize, |
| 74 | + } |
| 75 | + |
| 76 | + impl<T> Drop for Guard<'_, T> { |
| 77 | + #[inline] |
| 78 | + fn drop(&mut self) { |
| 79 | + if const { crate::mem::needs_drop::<T>() } { |
| 80 | + // SAFETY: self.initialized is always <= N, which also is the length of the array. |
| 81 | + unsafe { |
| 82 | + core::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut( |
| 83 | + self.array.get_unchecked_mut(..self.initialized), |
| 84 | + )); |
| 85 | + } |
| 86 | + } |
| 87 | + } |
| 88 | + } |
| 89 | + |
| 90 | + let mut guard = Guard { array: &mut array, initialized: 0 }; |
| 91 | + |
| 92 | + let result = self.iter.try_for_each(|element| { |
| 93 | + let idx = guard.initialized; |
| 94 | + let val = (self.f)(element); |
| 95 | + guard.initialized = idx + val.is_some() as usize; |
| 96 | + |
| 97 | + // SAFETY: Loop conditions ensure the index is in bounds. |
| 98 | + |
| 99 | + unsafe { |
| 100 | + let opt_payload_at = core::intrinsics::option_payload_ptr(&val); |
| 101 | + let dst = guard.array.as_mut_ptr().add(idx); |
| 102 | + crate::ptr::copy_nonoverlapping(opt_payload_at.cast(), dst, 1); |
| 103 | + crate::mem::forget(val); |
| 104 | + }; |
| 105 | + |
| 106 | + if guard.initialized < N { ControlFlow::Continue(()) } else { ControlFlow::Break(()) } |
| 107 | + }); |
| 108 | + |
| 109 | + let guard = ManuallyDrop::new(guard); |
| 110 | + |
| 111 | + match result { |
| 112 | + ControlFlow::Break(()) => { |
| 113 | + // SAFETY: The loop above is only explicitly broken when the array has been fully initialized |
| 114 | + Ok(unsafe { MaybeUninit::array_assume_init(array) }) |
| 115 | + } |
| 116 | + ControlFlow::Continue(()) => { |
| 117 | + let initialized = guard.initialized; |
| 118 | + // SAFETY: The range is in bounds since the loop breaks when reaching N elements. |
| 119 | + Err(unsafe { array::IntoIter::new_unchecked(array, 0..initialized) }) |
| 120 | + } |
| 121 | + } |
| 122 | + } |
| 123 | + |
64 | 124 | #[inline] |
65 | 125 | fn size_hint(&self) -> (usize, Option<usize>) { |
66 | 126 | let (_, upper) = self.iter.size_hint(); |
|
0 commit comments