Skip to content

Commit b3fcb75

Browse files
committed
Implement TrustedRandomAccess for vec::Drain
1 parent 2706ae1 commit b3fcb75

File tree

1 file changed

+31
-1
lines changed

1 file changed

+31
-1
lines changed

library/alloc/src/vec/drain.rs

+31-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, TrustedRandomAccess};
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: TrustedRandomAccess,
97+
{
98+
// SAFETY: `TrustedRandomAccess` 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: TrustedRandomAccess` 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,22 @@ 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 `TrustedRandomAccess`,
172+
// and then reads the items instead of just returning a reference. As `TrustedRandomAccess`
173+
// requires each index to be accessed only once, this is safe to do here.
174+
//
175+
// T: Copy as approximation for !Drop since get_unchecked does not advance self.iter
176+
// and as a result the `Drop` impl above would otherwise cause items to be dropped twice.
177+
unsafe impl<T, A: Allocator> TrustedRandomAccess for Drain<'_, T, A>
178+
where
179+
T: Copy,
180+
{
181+
fn may_have_side_effect() -> bool {
182+
false
183+
}
184+
}
185+
156186
#[stable(feature = "fused", since = "1.26.0")]
157187
impl<T, A: Allocator> FusedIterator for Drain<'_, T, A> {}

0 commit comments

Comments
 (0)