@@ -347,39 +347,68 @@ macro_rules! izip {
347
347
}
348
348
349
349
#[ macro_export]
350
- /// Create an iterator running multiple iterators sequentially .
350
+ /// [Chain][`chain`] zero or more iterators together into one sequence .
351
351
///
352
- /// This is a version of the standard ``.chain()`` that's supporting more than
353
- /// two iterators. `chain!` takes `IntoIterator` arguments.
354
- /// Alternatively, this is an alternative to the standard ``.flatten()`` for a
355
- /// fixed number of iterators of distinct sizes.
352
+ /// The comma-separated arguments must implement [`IntoIterator`].
353
+ /// The final argument may be followed by a trailing comma.
356
354
///
357
- /// **Note:** The result of this macro is in the general case an iterator
358
- /// composed of repeated `.chain()`.
359
- /// The special case of one arguments produce $a.into_iter().
355
+ /// [`chain`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.chain
356
+ /// [`IntoIterator`]: https://doc.rust-lang.org/std/iter/trait.IntoIterator.html
357
+ ///
358
+ /// # Examples
360
359
///
360
+ /// [`iter::empty`]: https://doc.rust-lang.org/std/iter/fn.empty.html
361
361
///
362
+ /// Empty invocations of `chain!` expand to an invocation of [`iter::empty`]:
362
363
/// ```
363
- /// # use itertools::chain;
364
- /// #
365
- /// # fn main() {
364
+ /// # use std::iter;
365
+ /// use itertools::chain;
366
366
///
367
- /// // chain three sequences
368
- /// let chained: Vec<i32> = chain!(0..=3, 4..6, vec![6, 7]).collect();
369
- /// assert_eq!(chained, (0..=7).collect::<Vec<i32>>());
370
- /// # }
367
+ /// let _: iter::Empty<()> = chain!();
368
+ /// let _: iter::Empty<i8> = chain!();
369
+ /// ```
370
+ ///
371
+ /// Invocations of `chain!` with one argument expand to [`arg.into_iter()`][`IntoIterator`]:
372
+ /// ```
373
+ /// use std::{ops::Range, slice};
374
+ /// use itertools::chain;
375
+ /// let _: <Range<_> as IntoIterator>::IntoIter = chain!((2..6),); // trailing comma optional!
376
+ /// let _: <&[_] as IntoIterator>::IntoIter = chain!(&[2, 3, 4]);
377
+ /// ```
378
+ ///
379
+ /// Invocations of `chain!` with multiple arguments [`.into_iter()`][`IntoIterator`] each
380
+ /// argument, and then [`chain`] them together:
381
+ /// ```
382
+ /// use std::{iter::*, ops::Range, slice};
383
+ /// use itertools::{assert_equal, chain};
384
+ ///
385
+ /// // e.g., this:
386
+ /// let with_macro: Chain<Chain<Once<_>, Take<Repeat<_>>>, slice::Iter<_>> =
387
+ /// chain![once(&0), repeat(&1).take(2), &[2, 3, 5],];
388
+ ///
389
+ /// // ...is equivalant to this:
390
+ /// let with_method: Chain<Chain<Once<_>, Take<Repeat<_>>>, slice::Iter<_>> =
391
+ /// once(&0)
392
+ /// .chain(repeat(&1).take(2))
393
+ /// .chain(&[2, 3, 5]);
394
+ ///
395
+ /// assert_equal(with_macro, with_method);
371
396
/// ```
372
397
macro_rules! chain {
373
398
( ) => {
374
399
core:: iter:: empty( )
375
400
} ;
376
- ( $first: expr $( , $rest: expr ) * $( , ) * ) => {
377
- core:: iter:: IntoIterator :: into_iter( $first)
401
+ ( $first: expr $( , $rest: expr ) * $( , ) ?) => {
402
+ {
403
+ let iter = core:: iter:: IntoIterator :: into_iter( $first) ;
378
404
$(
379
- . chain(
380
- core:: iter:: IntoIterator :: into_iter( $rest)
381
- )
405
+ let iter =
406
+ core:: iter:: Iterator :: chain(
407
+ iter,
408
+ core:: iter:: IntoIterator :: into_iter( $rest) ) ;
382
409
) *
410
+ iter
411
+ }
383
412
} ;
384
413
}
385
414
0 commit comments