Skip to content

Commit 451a3b1

Browse files
committed
implement TrustedRandomAccess and TrustedLen for Skip
1 parent a2a7caa commit 451a3b1

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,6 +1,10 @@
11
use crate::intrinsics::unlikely;
2+
use crate::iter::adapters::zip::try_get_unchecked;
23
use crate::iter::TrustedFused;
3-
use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable};
4+
use crate::iter::{
5+
adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen, TrustedRandomAccess,
6+
TrustedRandomAccessNoCoerce,
7+
};
48
use crate::num::NonZeroUsize;
59
use crate::ops::{ControlFlow, Try};
610

@@ -152,6 +156,32 @@ where
152156

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

157187
#[stable(feature = "rust1", since = "1.0.0")]
@@ -237,3 +267,23 @@ unsafe impl<I: InPlaceIterable> InPlaceIterable for Skip<I> {
237267
const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
238268
const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
239269
}
270+
271+
#[doc(hidden)]
272+
#[unstable(feature = "trusted_random_access", issue = "none")]
273+
unsafe impl<I> TrustedRandomAccess for Skip<I> where I: TrustedRandomAccess {}
274+
275+
#[doc(hidden)]
276+
#[unstable(feature = "trusted_random_access", issue = "none")]
277+
unsafe impl<I> TrustedRandomAccessNoCoerce for Skip<I>
278+
where
279+
I: TrustedRandomAccessNoCoerce,
280+
{
281+
const MAY_HAVE_SIDE_EFFECT: bool = I::MAY_HAVE_SIDE_EFFECT;
282+
}
283+
284+
// SAFETY: This adapter is shortening. TrustedLen requires the upper bound to be calculated correctly.
285+
// These requirements can only be satisfied when the upper bound of the inner iterator's upper
286+
// bound is never `None`. I: TrustedRandomAccess happens to provide this guarantee while
287+
// I: TrustedLen would not.
288+
#[unstable(feature = "trusted_len", issue = "37572")]
289+
unsafe impl<I> TrustedLen for Skip<I> where I: Iterator + TrustedRandomAccess {}

0 commit comments

Comments
 (0)