|
1 | 1 | use crate::alloc::{Allocator, Global};
|
2 | 2 | use core::fmt;
|
3 |
| -use core::iter::{FusedIterator, TrustedLen}; |
| 3 | +use core::iter::{FusedIterator, TrustedLen, TrustedRandomAccess}; |
4 | 4 | use core::mem::{self};
|
5 | 5 | use core::ptr::{self, NonNull};
|
6 | 6 | use core::slice::{self};
|
@@ -89,6 +89,19 @@ impl<T, A: Allocator> Iterator for Drain<'_, T, A> {
|
89 | 89 | fn size_hint(&self) -> (usize, Option<usize>) {
|
90 | 90 | self.iter.size_hint()
|
91 | 91 | }
|
| 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 | + } |
92 | 105 | }
|
93 | 106 |
|
94 | 107 | #[stable(feature = "drain", since = "1.6.0")]
|
@@ -153,5 +166,22 @@ impl<T, A: Allocator> ExactSizeIterator for Drain<'_, T, A> {
|
153 | 166 | // so the required properties are all preserved.
|
154 | 167 | unsafe impl<T, A: Allocator> TrustedLen for Drain<'_, T, A> {}
|
155 | 168 |
|
| 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 | + |
156 | 186 | #[stable(feature = "fused", since = "1.26.0")]
|
157 | 187 | impl<T, A: Allocator> FusedIterator for Drain<'_, T, A> {}
|
0 commit comments