Skip to content

Commit 50dbccc

Browse files
committed
Implement TrustedRandomAccess for vec::Drain
1 parent 4a46acd commit 50dbccc

File tree

1 file changed

+29
-1
lines changed

1 file changed

+29
-1
lines changed

library/alloc/src/vec/drain.rs

+29-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::alloc::{Allocator, Global};
22
use core::fmt;
3-
use core::iter::{FusedIterator, TrustedLen};
3+
use core::iter::{FusedIterator, TrustedLen, TrustedRandomAccessNoCoerce};
44
use core::mem::{self};
55
use core::ptr::{self, NonNull};
66
use core::slice::{self};
@@ -89,6 +89,19 @@ impl<T, A: Allocator> Iterator for Drain<'_, T, A> {
8989
fn size_hint(&self) -> (usize, Option<usize>) {
9090
self.iter.size_hint()
9191
}
92+
93+
#[doc(hidden)]
94+
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T
95+
where
96+
Self: TrustedRandomAccessNoCoerce,
97+
{
98+
// SAFETY: `TrustedRandomAccessNoCoerce` requires that `idx` is in bounds and that
99+
// each `idx` is only accessed once. Forwarding to the slice iterator's
100+
// implementation is thus safe, and reading the value is safe because
101+
// `Self: TrustedRandomAccessNoCoerce` implies `T: Copy` so the `Drop` impl below
102+
// won't cause each item to be dropped twice.
103+
unsafe { ptr::read(self.iter.__iterator_get_unchecked(idx) as *const _) }
104+
}
92105
}
93106

94107
#[stable(feature = "drain", since = "1.6.0")]
@@ -153,5 +166,20 @@ impl<T, A: Allocator> ExactSizeIterator for Drain<'_, T, A> {
153166
// so the required properties are all preserved.
154167
unsafe impl<T, A: Allocator> TrustedLen for Drain<'_, T, A> {}
155168

169+
#[doc(hidden)]
170+
#[unstable(feature = "trusted_random_access", issue = "none")]
171+
// SAFETY: `Drain` forwards to the underlying slice iterator, which implements `TrustedRandomAccessNoCoerce`,
172+
// and then reads the items instead of just returning a reference. As `TrustedRandomAccessNoCoerce`
173+
// requires each index to be accessed only once, this is safe to do here.
174+
//
175+
// TrustedRandomAccess (without NoCoerce) must not be implemented because
176+
// subtypes/supertypes of `T` might not be `NonDrop`
177+
unsafe impl<T, A: Allocator> TrustedRandomAccessNoCoerce for Drain<'_, T, A>
178+
where
179+
T: super::into_iter::NonDrop,
180+
{
181+
const MAY_HAVE_SIDE_EFFECT: bool = false;
182+
}
183+
156184
#[stable(feature = "fused", since = "1.26.0")]
157185
impl<T, A: Allocator> FusedIterator for Drain<'_, T, A> {}

0 commit comments

Comments
 (0)