Skip to content

Commit 07d1a4a

Browse files
committed
move around
1 parent 044511d commit 07d1a4a

File tree

2 files changed

+47
-109
lines changed

2 files changed

+47
-109
lines changed

library/core/src/array/drain.rs

Lines changed: 45 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,57 @@
11
#![allow(dead_code)]
2-
use crate::iter::{TrustedLen, UncheckedIterator};
2+
use crate::marker::Destruct;
33
use crate::mem::ManuallyDrop;
4-
use crate::ptr::drop_in_place;
5-
use crate::slice;
64

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,
2811
}
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)
3922
}
4023
}
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() })
5635
}
5736
}
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+
}
6349
}
6450
}
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 }
7656
}
7757
}

library/core/src/array/mod.rs

Lines changed: 2 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use crate::hash::{self, Hash};
1313
use crate::intrinsics::transmute_unchecked;
1414
use crate::iter::{UncheckedIterator, repeat_n};
1515
use crate::marker::Destruct;
16-
use crate::mem::{self, ManuallyDrop, MaybeUninit};
16+
use crate::mem::{self, MaybeUninit};
1717
use crate::ops::{
1818
ChangeOutputType, ControlFlow, FromResidual, Index, IndexMut, NeverShortCircuit, Residual, Try,
1919
};
@@ -593,50 +593,8 @@ impl<T, const N: usize> [T; N] {
593593
R::Output: [const] Destruct,
594594
<R::Residual as Residual<[R::Output; N]>>::TryType: [const] Try,
595595
{
596-
#[rustc_const_unstable(feature = "array_try_map", issue = "79711")]
597-
struct Guardian<'a, T, U, const N: usize, F: FnMut(T) -> U> {
598-
array: ManuallyDrop<[T; N]>,
599-
moved: usize,
600-
f: &'a mut F,
601-
}
602-
#[rustc_const_unstable(feature = "array_try_map", issue = "79711")]
603-
impl<T, U, const N: usize, F> const FnOnce<(usize,)> for &mut Guardian<'_, T, U, N, F>
604-
where
605-
F: [const] FnMut(T) -> U,
606-
{
607-
type Output = U;
608-
609-
extern "rust-call" fn call_once(mut self, args: (usize,)) -> Self::Output {
610-
self.call_mut(args)
611-
}
612-
}
613-
#[rustc_const_unstable(feature = "array_try_map", issue = "79711")]
614-
impl<T, U, const N: usize, F> const FnMut<(usize,)> for &mut Guardian<'_, T, U, N, F>
615-
where
616-
F: [const] FnMut(T) -> U,
617-
{
618-
extern "rust-call" fn call_mut(&mut self, (x,): (usize,)) -> Self::Output {
619-
// SAFETY: increment moved before moving. if `f` panics, we drop the rest.
620-
self.moved += 1;
621-
// SAFETY: caller guarantees never called with number >= N
622-
(self.f)(unsafe { self.array.as_ptr().add(x).read() })
623-
}
624-
}
625-
#[rustc_const_unstable(feature = "array_try_map", issue = "79711")]
626-
impl<T: [const] Destruct, U, const N: usize, F: FnMut(T) -> U> const Drop
627-
for Guardian<'_, T, U, N, F>
628-
{
629-
fn drop(&mut self) {
630-
let mut n = self.moved;
631-
while n != N {
632-
// SAFETY: moved must always be < N
633-
unsafe { self.array.as_mut_ptr().add(n).drop_in_place() };
634-
n += 1;
635-
}
636-
}
637-
}
638-
let mut f = Guardian { array: ManuallyDrop::new(self), moved: 0, f: &mut f };
639596
// SAFETY: try_from_fn calls `f` with 0..N.
597+
let mut f = unsafe { drain::Drain::new(self, &mut f) };
640598
let out = try_from_fn(&mut f);
641599
mem::forget(f); // it doesnt like being remembered
642600
out

0 commit comments

Comments
 (0)