File tree Expand file tree Collapse file tree 2 files changed +50
-8
lines changed Expand file tree Collapse file tree 2 files changed +50
-8
lines changed Original file line number Diff line number Diff line change @@ -33,21 +33,32 @@ where
3333 #[ inline]
3434 fn next ( & mut self ) -> Option < I :: Item > {
3535 if unlikely ( self . n > 0 ) {
36- self . iter . nth ( crate :: mem:: take ( & mut self . n ) - 1 ) ?;
36+ self . iter . nth ( crate :: mem:: take ( & mut self . n ) )
37+ } else {
38+ self . iter . next ( )
3739 }
38- self . iter . next ( )
3940 }
4041
4142 #[ inline]
4243 fn nth ( & mut self , n : usize ) -> Option < I :: Item > {
43- // Can't just add n + self.n due to overflow.
4444 if self . n > 0 {
45- let to_skip = self . n ;
46- self . n = 0 ;
47- // nth(n) skips n+1
48- self . iter . nth ( to_skip - 1 ) ?;
45+ let skip: usize = crate :: mem:: take ( & mut self . n ) ;
46+ // Checked add to handle overflow case.
47+ let n = match skip. checked_add ( n) {
48+ Some ( nth) => nth,
49+ None => {
50+ // In case of overflow, load skip value, before loading `n`.
51+ // Because the amount of elements to iterate is beyond `usize::MAX`, this
52+ // is split into two `nth` calls where the `skip` `nth` call is discarded.
53+ self . iter . nth ( skip - 1 ) ?;
54+ n
55+ }
56+ } ;
57+ // Load nth element including skip.
58+ self . iter . nth ( n)
59+ } else {
60+ self . iter . nth ( n)
4961 }
50- self . iter . nth ( n)
5162 }
5263
5364 #[ inline]
Original file line number Diff line number Diff line change @@ -201,3 +201,34 @@ fn test_skip_non_fused() {
201201 // advance it further. `Unfuse` tests that this doesn't happen by panicking in that scenario.
202202 let _ = non_fused. skip ( 20 ) . next ( ) ;
203203}
204+
205+ #[ test]
206+ fn test_skip_non_fused_nth_overflow ( ) {
207+ let non_fused = Unfuse :: new ( 0 ..10 ) ;
208+
209+ // Ensures that calling skip and `nth` where the sum would overflow does not fail for non-fused
210+ // iterators.
211+ let _ = non_fused. skip ( 20 ) . nth ( usize:: MAX ) ;
212+ }
213+
214+ #[ test]
215+ fn test_skip_overflow_wrapping ( ) {
216+ // Test to ensure even on overflowing on `skip+nth` the correct amount of elements are yielded.
217+ struct WrappingIterator ( usize ) ;
218+
219+ impl Iterator for WrappingIterator {
220+ type Item = usize ;
221+
222+ fn next ( & mut self ) -> core:: option:: Option < Self :: Item > {
223+ <Self as Iterator >:: nth ( self , 0 )
224+ }
225+
226+ fn nth ( & mut self , nth : usize ) -> core:: option:: Option < Self :: Item > {
227+ self . 0 = self . 0 . wrapping_add ( nth. wrapping_add ( 1 ) ) ;
228+ Some ( self . 0 )
229+ }
230+ }
231+
232+ let wrap = WrappingIterator ( 0 ) ;
233+ assert_eq ! ( wrap. skip( 20 ) . nth( usize :: MAX ) , Some ( 20 ) ) ;
234+ }
You can’t perform that action at this time.
0 commit comments