Skip to content

Commit 1a950fa

Browse files
committed
implement TrustedRandomAccess and TrustedLen for Skip
1 parent 2676f9c commit 1a950fa

File tree

1 file changed

+51
-1
lines changed
  • library/core/src/iter/adapters

1 file changed

+51
-1
lines changed

library/core/src/iter/adapters/skip.rs

+51-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
use crate::intrinsics::unlikely;
2-
use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable};
2+
use crate::iter::adapters::zip::try_get_unchecked;
3+
use crate::iter::{
4+
adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen, TrustedRandomAccess,
5+
TrustedRandomAccessNoCoerce,
6+
};
37
use crate::num::NonZeroUsize;
48
use crate::ops::{ControlFlow, Try};
59

@@ -151,6 +155,32 @@ where
151155

152156
NonZeroUsize::new(n).map_or(Ok(()), Err)
153157
}
158+
159+
#[doc(hidden)]
160+
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
161+
where
162+
Self: TrustedRandomAccessNoCoerce,
163+
{
164+
// SAFETY: the caller must uphold the contract for
165+
// `Iterator::__iterator_get_unchecked`.
166+
//
167+
// Dropping the skipped prefix when index 0 is passed is safe
168+
// since
169+
// * the caller passing index 0 means that the inner iterator has more items than `self.n`
170+
// * TRA contract requires that get_unchecked will only be called once
171+
// (unless elements are copyable)
172+
// * it does not conflict with in-place iteration since index 0 must be accessed
173+
// before something is written into the storage used by the prefix
174+
unsafe {
175+
if Self::MAY_HAVE_SIDE_EFFECT && idx == 0 {
176+
for skipped_idx in 0..self.n {
177+
drop(try_get_unchecked(&mut self.iter, skipped_idx));
178+
}
179+
}
180+
181+
try_get_unchecked(&mut self.iter, idx + self.n)
182+
}
183+
}
154184
}
155185

156186
#[stable(feature = "rust1", since = "1.0.0")]
@@ -230,3 +260,23 @@ where
230260

231261
#[unstable(issue = "none", feature = "inplace_iteration")]
232262
unsafe impl<I: InPlaceIterable> InPlaceIterable for Skip<I> {}
263+
264+
#[doc(hidden)]
265+
#[unstable(feature = "trusted_random_access", issue = "none")]
266+
unsafe impl<I> TrustedRandomAccess for Skip<I> where I: TrustedRandomAccess {}
267+
268+
#[doc(hidden)]
269+
#[unstable(feature = "trusted_random_access", issue = "none")]
270+
unsafe impl<I> TrustedRandomAccessNoCoerce for Skip<I>
271+
where
272+
I: TrustedRandomAccessNoCoerce,
273+
{
274+
const MAY_HAVE_SIDE_EFFECT: bool = I::MAY_HAVE_SIDE_EFFECT;
275+
}
276+
277+
// SAFETY: This adapter is shortening. TrustedLen requires the upper bound to be calculated correctly.
278+
// These requirements can only be satisfied when the upper bound of the inner iterator's upper
279+
// bound is never `None`. I: TrustedRandomAccess happens to provide this guarantee while
280+
// I: TrustedLen would not.
281+
#[unstable(feature = "trusted_len", issue = "37572")]
282+
unsafe impl<I> TrustedLen for Skip<I> where I: Iterator + TrustedRandomAccess {}

0 commit comments

Comments
 (0)