|
1 | 1 | #![allow(dead_code)] |
2 | | -use crate::iter::{TrustedLen, UncheckedIterator}; |
| 2 | +use crate::marker::Destruct; |
3 | 3 | use crate::mem::ManuallyDrop; |
4 | | -use crate::ptr::drop_in_place; |
5 | | -use crate::slice; |
6 | 4 |
|
7 | | -/// A situationally-optimized version of `array.into_iter().for_each(func)`. |
8 | | -/// |
9 | | -/// [`crate::array::IntoIter`]s are great when you need an owned iterator, but |
10 | | -/// storing the entire array *inside* the iterator like that can sometimes |
11 | | -/// pessimize code. Notable, it can be more bytes than you really want to move |
12 | | -/// around, and because the array accesses index into it SRoA has a harder time |
13 | | -/// optimizing away the type than it does iterators that just hold a couple pointers. |
14 | | -/// |
15 | | -/// Thus this function exists, which gives a way to get *moved* access to the |
16 | | -/// elements of an array using a small iterator -- no bigger than a slice iterator. |
17 | | -/// |
18 | | -/// The function-taking-a-closure structure makes it safe, as it keeps callers |
19 | | -/// from looking at already-dropped elements. |
20 | | -pub(crate) fn drain_array_with<T, R, const N: usize>( |
21 | | - array: [T; N], |
22 | | - func: impl for<'a> FnOnce(Drain<'a, T>) -> R, |
23 | | -) -> R { |
24 | | - let mut array = ManuallyDrop::new(array); |
25 | | - // SAFETY: Now that the local won't drop it, it's ok to construct the `Drain` which will. |
26 | | - let drain = Drain(array.iter_mut()); |
27 | | - func(drain) |
| 5 | +#[rustc_const_unstable(feature = "array_try_map", issue = "79711")] |
| 6 | +#[unstable(feature = "array_try_map", issue = "79711")] |
| 7 | +pub(super) struct Drain<'a, T, U, const N: usize, F: FnMut(T) -> U> { |
| 8 | + array: ManuallyDrop<[T; N]>, |
| 9 | + moved: usize, |
| 10 | + f: &'a mut F, |
28 | 11 | } |
29 | | - |
30 | | -/// See [`drain_array_with`] -- this is `pub(crate)` only so it's allowed to be |
31 | | -/// mentioned in the signature of that method. (Otherwise it hits `E0446`.) |
32 | | -// INVARIANT: It's ok to drop the remainder of the inner iterator. |
33 | | -pub(crate) struct Drain<'a, T>(slice::IterMut<'a, T>); |
34 | | - |
35 | | -impl<T> Drop for Drain<'_, T> { |
36 | | - fn drop(&mut self) { |
37 | | - // SAFETY: By the type invariant, we're allowed to drop all these. |
38 | | - unsafe { drop_in_place(self.0.as_mut_slice()) } |
| 12 | +#[rustc_const_unstable(feature = "array_try_map", issue = "79711")] |
| 13 | +#[unstable(feature = "array_try_map", issue = "79711")] |
| 14 | +impl<T, U, const N: usize, F> const FnOnce<(usize,)> for &mut Drain<'_, T, U, N, F> |
| 15 | +where |
| 16 | + F: [const] FnMut(T) -> U, |
| 17 | +{ |
| 18 | + type Output = U; |
| 19 | + |
| 20 | + extern "rust-call" fn call_once(mut self, args: (usize,)) -> Self::Output { |
| 21 | + self.call_mut(args) |
39 | 22 | } |
40 | 23 | } |
41 | | - |
42 | | -impl<T> Iterator for Drain<'_, T> { |
43 | | - type Item = T; |
44 | | - |
45 | | - #[inline] |
46 | | - fn next(&mut self) -> Option<T> { |
47 | | - let p: *const T = self.0.next()?; |
48 | | - // SAFETY: The iterator was already advanced, so we won't drop this later. |
49 | | - Some(unsafe { p.read() }) |
50 | | - } |
51 | | - |
52 | | - #[inline] |
53 | | - fn size_hint(&self) -> (usize, Option<usize>) { |
54 | | - let n = self.len(); |
55 | | - (n, Some(n)) |
| 24 | +#[rustc_const_unstable(feature = "array_try_map", issue = "79711")] |
| 25 | +#[unstable(feature = "array_try_map", issue = "79711")] |
| 26 | +impl<T, U, const N: usize, F> const FnMut<(usize,)> for &mut Drain<'_, T, U, N, F> |
| 27 | +where |
| 28 | + F: [const] FnMut(T) -> U, |
| 29 | +{ |
| 30 | + extern "rust-call" fn call_mut(&mut self, (x,): (usize,)) -> Self::Output { |
| 31 | + // SAFETY: increment moved before moving. if `f` panics, we drop the rest. |
| 32 | + self.moved += 1; |
| 33 | + // SAFETY: caller guarantees never called with number >= N |
| 34 | + (self.f)(unsafe { self.array.as_ptr().add(x).read() }) |
56 | 35 | } |
57 | 36 | } |
58 | | - |
59 | | -impl<T> ExactSizeIterator for Drain<'_, T> { |
60 | | - #[inline] |
61 | | - fn len(&self) -> usize { |
62 | | - self.0.len() |
| 37 | +#[rustc_const_unstable(feature = "array_try_map", issue = "79711")] |
| 38 | +#[unstable(feature = "array_try_map", issue = "79711")] |
| 39 | +impl<T: [const] Destruct, U, const N: usize, F: FnMut(T) -> U> const Drop |
| 40 | + for Drain<'_, T, U, N, F> |
| 41 | +{ |
| 42 | + fn drop(&mut self) { |
| 43 | + let mut n = self.moved; |
| 44 | + while n != N { |
| 45 | + // SAFETY: moved must always be < N |
| 46 | + unsafe { self.array.as_mut_ptr().add(n).drop_in_place() }; |
| 47 | + n += 1; |
| 48 | + } |
63 | 49 | } |
64 | 50 | } |
65 | | - |
66 | | -// SAFETY: This is a 1:1 wrapper for a slice iterator, which is also `TrustedLen`. |
67 | | -unsafe impl<T> TrustedLen for Drain<'_, T> {} |
68 | | - |
69 | | -impl<T> UncheckedIterator for Drain<'_, T> { |
70 | | - unsafe fn next_unchecked(&mut self) -> T { |
71 | | - // SAFETY: `Drain` is 1:1 with the inner iterator, so if the caller promised |
72 | | - // that there's an element left, the inner iterator has one too. |
73 | | - let p: *const T = unsafe { self.0.next_unchecked() }; |
74 | | - // SAFETY: The iterator was already advanced, so we won't drop this later. |
75 | | - unsafe { p.read() } |
| 51 | +impl<'a, T, U, const N: usize, F: FnMut(T) -> U> Drain<'a, T, U, N, F> { |
| 52 | + /// SAFETY: must be called without indexing out of bounds. |
| 53 | + // FIXME: this is a hack for `let guard = Guard(array); |i| f(guard[i])`. |
| 54 | + pub(super) const unsafe fn new(array: [T; N], f: &'a mut F) -> Self { |
| 55 | + Self { array: ManuallyDrop::new(array), moved: 0, f } |
76 | 56 | } |
77 | 57 | } |
0 commit comments