1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//! ForEach trait and for_each! macro allow you to use iterator inside iteration
//! loop, which is not posible when using for-in loop.
//!
//! # Examples
//! ```
//! # extern crate foreach;
//! # use foreach::ForEach;
//! # fn main() {
//! let mut iter = 0..999;
//! iter.foreach(|item, iter| {
//!     println!("item: {}", item);
//!     println!("next: {:?}", iter.next());
//! });
//! # }
//! ```
//!
//! ```
//! # extern crate foreach;
//! # use foreach::ForEach;
//! use foreach::Continue::*;
//! # fn main() {
//! let mut iter = 0..999;
//! iter.foreach(|item, iter| {
//!     println!("item: {}", item);
//!     println!("next: {:?}", iter.next());
//!     if item > 10 {
//!         return Break;
//!     } else {
//!         return ().into();
//!     }
//! });
//! # }
//! ```
//!
//! ```
//! # #[macro_use] extern crate foreach;
//! # fn main() {
//! let mut iter = 0..999;
//! for_each!(item in iter {
//!     println!("item: {}", item);
//!     println!("next: {:?}", iter.next());
//!     if item > 10 {
//!         break;
//!     }
//! });
//! # }
//! ```

use std::iter::Iterator;

pub enum Continue {
    /// This is default value, it does not change anything.
    Continue,
    /// If this variant is returned, iteration ends.
    Break,
}

impl Default for Continue {
    fn default() -> Continue {
        Continue::Continue
    }
}

impl From<()> for Continue {
    /// Converts `()` to `Continue::Continue`
    fn from(_: ()) -> Continue {
        Continue::Continue
    }
}

/// Trait to simplify usage of iterator inside iteration loop.
///
/// This trait is implemented for all iterators by default.
pub trait ForEach: Iterator {
    /// Iterates over all items and executes given closure.
    ///
    /// This allows you to use iterator inside iteration loop, which is not
    /// posible when using for-in loop.
    ///
    /// See [crate-level docs](./index.html) for examples
    fn foreach<O, F>(&mut self, f: F)
    where
        O: Into<Continue>,
        F: FnMut(Self::Item, &mut Self) -> O;
}

impl<T: Iterator> ForEach for T {
    fn foreach<O, F>(&mut self, mut f: F)
    where
        O: Into<Continue>,
        F: FnMut(Self::Item, &mut Self) -> O,
    {
        loop {
            let item = self.next();
            if let Some(item) = item {
                match f(item, self).into() {
                    Continue::Break => break,
                    _ => (),
                }
            } else {
                break;
            }
        }
    }
}

/// This macro allows you to use iterator inside iteration loop, which is not
/// posible when using for-in loop.
/// See [crate-level docs](./index.html) for examples
#[macro_export]
macro_rules! for_each {
    ($pat:pat in $iter:ident $code:block) => {
        loop {
            use std::iter::Iterator;
            let __for_each_item = Iterator::next(&mut $iter);
            if let Some($pat) = __for_each_item {
                $code
            } else {
                break;
            }
        }
    };
    ($item:ident in $iter:ident $code:block) => {
        loop {
            use std::iter::Iterator;
            let $item = Iterator::next(&mut $iter);
            if let Some($item) = $item {
                $code
            } else {
                break;
            }
        }
    };
}