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