Skip to content

Commit a2a7caa

Browse files
committed
implement TrustedLen for StepBy
1 parent e927184 commit a2a7caa

File tree

3 files changed

+24
-9
lines changed

3 files changed

+24
-9
lines changed

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

+9-7
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

@@ -124,6 +124,14 @@ where
124124
#[stable(feature = "iterator_step_by", since = "1.28.0")]
125125
impl<I> ExactSizeIterator for StepBy<I> where I: ExactSizeIterator {}
126126

127+
// SAFETY: This adapter is shortening. TrustedLen requires the upper bound to be calculated correctly.
128+
// These requirements can only be satisfied when the upper bound of the inner iterator's upper
129+
// bound is never `None`. I: TrustedRandomAccess happens to provide this guarantee while
130+
// I: TrustedLen would not.
131+
// This also covers the Range specializations since the ranges also implement TRA
132+
#[unstable(feature = "trusted_len", issue = "37572")]
133+
unsafe impl<I> TrustedLen for StepBy<I> where I: Iterator + TrustedRandomAccess {}
134+
127135
trait SpecRangeSetup<T> {
128136
fn setup(inner: T, step: usize) -> T;
129137
}
@@ -480,12 +488,6 @@ macro_rules! spec_int_ranges {
480488
acc
481489
}
482490
}
483-
484-
/// Safety: This macro is only applied to ranges over types <= usize
485-
/// which means the inner length is guaranteed to fit into a usize and so
486-
/// the outer length calculation won't encounter clamped values
487-
#[unstable(feature = "trusted_len", issue = "37572")]
488-
unsafe impl TrustedLen for StepBy<Range<$t>> {}
489491
)*)
490492
}
491493

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

+5-2
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

+10
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,16 @@ fn test_range_inclusive_size_hint() {
474474
assert_eq!((imin..=imax + 1).size_hint(), (usize::MAX, None));
475475
}
476476

477+
#[test]
478+
fn test_range_trusted_random_access() {
479+
let mut range = 0..10;
480+
unsafe {
481+
assert_eq!(range.next(), Some(0));
482+
assert_eq!(range.__iterator_get_unchecked(0), 1);
483+
assert_eq!(range.__iterator_get_unchecked(1), 2);
484+
}
485+
}
486+
477487
#[test]
478488
fn test_double_ended_range() {
479489
assert_eq!((11..14).rev().collect::<Vec<_>>(), [13, 12, 11]);

0 commit comments

Comments
 (0)