|
1 | 1 | use crate::iter::{DoubleEndedIterator, FusedIterator, Iterator, TrustedLen};
|
2 | 2 | use crate::num::NonZeroUsize;
|
| 3 | +use crate::mem; |
3 | 4 | use crate::ops::Try;
|
4 | 5 |
|
5 | 6 | /// An iterator that links two iterators together, in a chain.
|
|
48 | 49 |
|
49 | 50 | #[inline]
|
50 | 51 | fn next(&mut self) -> Option<A::Item> {
|
51 |
| - and_then_or_clear(&mut self.a, Iterator::next).or_else(|| self.b.as_mut()?.next()) |
| 52 | + SpecChain::next(self) |
52 | 53 | }
|
53 | 54 |
|
54 | 55 | #[inline]
|
@@ -303,3 +304,41 @@ fn and_then_or_clear<T, U>(opt: &mut Option<T>, f: impl FnOnce(&mut T) -> Option
|
303 | 304 | }
|
304 | 305 | x
|
305 | 306 | }
|
| 307 | + |
| 308 | +#[rustc_unsafe_specialization_marker] |
| 309 | +trait SymmetricalArms {} |
| 310 | + |
| 311 | +impl<A> SymmetricalArms for Chain<A, A> {} |
| 312 | + |
| 313 | +trait SpecChain: Iterator { |
| 314 | + fn next(&mut self) -> Option<Self::Item>; |
| 315 | +} |
| 316 | + |
| 317 | +impl<A, B> SpecChain for Chain<A, B> |
| 318 | +where |
| 319 | + A: Iterator, |
| 320 | + B: Iterator<Item = A::Item>, |
| 321 | +{ |
| 322 | + #[inline] |
| 323 | + default fn next(&mut self) -> Option<A::Item> { |
| 324 | + and_then_or_clear(&mut self.a, Iterator::next).or_else(|| self.b.as_mut()?.next()) |
| 325 | + } |
| 326 | +} |
| 327 | + |
| 328 | +impl<A, B> SpecChain for Chain<A, B> |
| 329 | +where |
| 330 | + A: Iterator, |
| 331 | + B: Iterator<Item = A::Item>, |
| 332 | + Self: SymmetricalArms, |
| 333 | +{ |
| 334 | + #[inline] |
| 335 | + fn next(&mut self) -> Option<A::Item> { |
| 336 | + let mut result = and_then_or_clear(&mut self.a, Iterator::next); |
| 337 | + if result.is_none() { |
| 338 | + // SAFETY: SymmetricalArms guarantees that A and B are the same type. |
| 339 | + unsafe { mem::swap(&mut self.a, &mut *(&mut self.b as *mut _ as *mut Option<A>)) }; |
| 340 | + result = and_then_or_clear(&mut self.a, Iterator::next); |
| 341 | + } |
| 342 | + result |
| 343 | + } |
| 344 | +} |
0 commit comments