Skip to content

Commit 0528783

Browse files
committed
Implement array::Drain using slice::DrainRaw
1 parent b92182a commit 0528783

File tree

1 file changed

+12
-21
lines changed

1 file changed

+12
-21
lines changed

library/core/src/array/drain.rs

+12-21
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use crate::iter::{TrustedLen, UncheckedIterator};
2+
use crate::marker::PhantomData;
23
use crate::mem::ManuallyDrop;
3-
use crate::ptr::drop_in_place;
4-
use crate::slice;
4+
use crate::ptr::NonNull;
5+
use crate::slice::{self, DrainRaw};
56

67
/// A situationally-optimized version of `array.into_iter().for_each(func)`.
78
///
@@ -21,37 +22,29 @@ pub(crate) fn drain_array_with<T, R, const N: usize>(
2122
func: impl for<'a> FnOnce(Drain<'a, T>) -> R,
2223
) -> R {
2324
let mut array = ManuallyDrop::new(array);
24-
// SAFETY: Now that the local won't drop it, it's ok to construct the `Drain` which will.
25-
let drain = Drain(array.iter_mut());
25+
// SAFETY: Now that the local won't drop it, it's ok to construct the `DrainRaw` which will.
26+
// We ensure via the lifetime that it can't be used after the function returns,
27+
// and thus the local `array` will always exist while iterating it.
28+
let raw = unsafe { DrainRaw::from_parts(NonNull::new_unchecked(array.as_mut_ptr()), N) };
29+
let drain = Drain(raw, PhantomData);
2630
func(drain)
2731
}
2832

2933
/// See [`drain_array_with`] -- this is `pub(crate)` only so it's allowed to be
3034
/// mentioned in the signature of that method. (Otherwise it hits `E0446`.)
31-
// INVARIANT: It's ok to drop the remainder of the inner iterator.
32-
pub(crate) struct Drain<'a, T>(slice::IterMut<'a, T>);
33-
34-
impl<T> Drop for Drain<'_, T> {
35-
fn drop(&mut self) {
36-
// SAFETY: By the type invariant, we're allowed to drop all these.
37-
unsafe { drop_in_place(self.0.as_mut_slice()) }
38-
}
39-
}
35+
pub(crate) struct Drain<'a, T>(slice::DrainRaw<T>, PhantomData<&'a mut [T]>);
4036

4137
impl<T> Iterator for Drain<'_, T> {
4238
type Item = T;
4339

4440
#[inline]
4541
fn next(&mut self) -> Option<T> {
46-
let p: *const T = self.0.next()?;
47-
// SAFETY: The iterator was already advanced, so we won't drop this later.
48-
Some(unsafe { p.read() })
42+
self.0.next()
4943
}
5044

5145
#[inline]
5246
fn size_hint(&self) -> (usize, Option<usize>) {
53-
let n = self.len();
54-
(n, Some(n))
47+
self.0.size_hint()
5548
}
5649
}
5750

@@ -69,8 +62,6 @@ impl<T> UncheckedIterator for Drain<'_, T> {
6962
unsafe fn next_unchecked(&mut self) -> T {
7063
// SAFETY: `Drain` is 1:1 with the inner iterator, so if the caller promised
7164
// that there's an element left, the inner iterator has one too.
72-
let p: *const T = unsafe { self.0.next_unchecked() };
73-
// SAFETY: The iterator was already advanced, so we won't drop this later.
74-
unsafe { p.read() }
65+
unsafe { self.0.next_unchecked() }
7566
}
7667
}

0 commit comments

Comments
 (0)