Skip to content

Commit 2676f9c

Browse files
committed
implement TrustedLen for StepBy
1 parent 5dac6b3 commit 2676f9c

File tree

3 files changed

+24
-9
lines changed

3 files changed

+24
-9
lines changed

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

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::convert::TryFrom;
22
use crate::{
33
intrinsics,
4-
iter::{from_fn, TrustedLen},
4+
iter::{from_fn, TrustedLen, TrustedRandomAccess},
55
ops::{Range, Try},
66
};
77

@@ -128,6 +128,14 @@ where
128128
#[stable(feature = "iterator_step_by", since = "1.28.0")]
129129
impl<I> ExactSizeIterator for StepBy<I> where I: ExactSizeIterator {}
130130

131+
// SAFETY: This adapter is shortening. TrustedLen requires the upper bound to be calculated correctly.
132+
// These requirements can only be satisfied when the upper bound of the inner iterator's upper
133+
// bound is never `None`. I: TrustedRandomAccess happens to provide this guarantee while
134+
// I: TrustedLen would not.
135+
// This also covers the Range specializations since the ranges also implement TRA
136+
#[unstable(feature = "trusted_len", issue = "37572")]
137+
unsafe impl<I> TrustedLen for StepBy<I> where I: Iterator + TrustedRandomAccess {}
138+
131139
trait SpecRangeSetup<T> {
132140
fn setup(inner: T, step: usize) -> T;
133141
}
@@ -484,12 +492,6 @@ macro_rules! spec_int_ranges {
484492
acc
485493
}
486494
}
487-
488-
/// Safety: This macro is only applied to ranges over types <= usize
489-
/// which means the inner length is guaranteed to fit into a usize and so
490-
/// the outer length calculation won't encounter clamped values
491-
#[unstable(feature = "trusted_len", issue = "37572")]
492-
unsafe impl TrustedLen for StepBy<Range<$t>> {}
493495
)*)
494496
}
495497

library/core/tests/iter/adapters/step_by.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,8 @@ fn test_iterator_step_by_size_hint() {
220220
assert_eq!(it.len(), 3);
221221

222222
// Cannot be TrustedLen as a step greater than one makes an iterator
223-
// with (usize::MAX, None) no longer meet the safety requirements
223+
// with (usize::MAX, None) no longer meet the safety requirements.
224+
// Exception: The inner iterator is known to have a len() <= usize::MAX
224225
trait TrustedLenCheck {
225226
fn test(self) -> bool;
226227
}
@@ -235,7 +236,9 @@ fn test_iterator_step_by_size_hint() {
235236
}
236237
}
237238
assert!(TrustedLenCheck::test(a.iter()));
238-
assert!(!TrustedLenCheck::test(a.iter().step_by(1)));
239+
assert!(TrustedLenCheck::test(a.iter().step_by(1)));
240+
assert!(TrustedLenCheck::test(a.iter().chain(a.iter())));
241+
assert!(!TrustedLenCheck::test(a.iter().chain(a.iter()).step_by(1)));
239242
}
240243

241244
#[test]

library/core/tests/iter/range.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,16 @@ fn test_range_inclusive_size_hint() {
458458
assert_eq!((imin..=imax + 1).size_hint(), (usize::MAX, None));
459459
}
460460

461+
#[test]
462+
fn test_range_trusted_random_access() {
463+
let mut range = 0..10;
464+
unsafe {
465+
assert_eq!(range.next(), Some(0));
466+
assert_eq!(range.__iterator_get_unchecked(0), 1);
467+
assert_eq!(range.__iterator_get_unchecked(1), 2);
468+
}
469+
}
470+
461471
#[test]
462472
fn test_double_ended_range() {
463473
assert_eq!((11..14).rev().collect::<Vec<_>>(), [13, 12, 11]);

0 commit comments

Comments
 (0)