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
135
136
137

#[macro_export]
/// Array zip macro: lock step function application across several arrays and
/// producers.
///
/// This is a shorthand for [`Zip`](struct.Zip.html).
///
/// This example:
///
/// ```rust,ignore
/// azip!(mut a, b, c in { *a = b + c })
/// ```
///
/// Is equivalent to:
///
/// ```rust,ignore
/// Zip::from(&mut a).and(&b).and(&c).apply(|a, &b, &c| {
///     *a = b + c;
/// });
///
/// ```
///
/// Explanation of the shorthand for captures:
///
/// + `mut a`: the producer is `&mut a` and the variable pattern is `mut a`.
/// + `b`: the producer is `&b` and the variable pattern is `&b` (same for `c`).
///
/// The syntax is `azip!(` *[* `index` *pattern* `,`*] capture [*`,` *capture [*`,` *...] ]* `in {` *expression* `})`
/// where the captures are a sequence of pattern-like items that indicate which
/// arrays are used for the zip. The *expression* is evaluated elementwise,
/// with the value of an element from each producer in their respective variable.
///
/// More capture rules:
///
/// + `ref c`: the producer is `&c` and the variable pattern is `c`.
/// + `mut a (expr)`: the producer is `expr` and the variable pattern is `mut a`.
/// + `b (expr)`: the producer is `expr` and the variable pattern is `&b`.
/// + `ref c (expr)`: the producer is `expr` and the variable pattern is `c`.
///
/// Special rule:
///
/// + `index i`: Use `Zip::indexed` instead. `i` is a pattern -- it can be
///    a single variable name or something else that pattern matches the index.
///    This rule must be the first if it is used, and it must be followed by
///    at least one other rule.
///
/// **Panics** if any of the arrays are not of the same shape.
///
/// ## Examples
///
/// ```rust
/// #[macro_use(azip)]
/// extern crate ndarray;
///
/// use ndarray::Array2;
///
/// type M = Array2<f32>;
///
/// fn main() {
///     let mut a = M::zeros((16, 16));
///     let mut b = M::zeros(a.dim());
///     let mut c = M::zeros(a.dim());
///
///     // set up values in b, c
///     b.fill(1.);
///     for ((i, j), elt) in c.indexed_iter_mut() {
///         *elt = (i + 10 * j) as f32;
///     }
///
///     // Compute a simple ternary operation:
///     // elementwise addition of b and c, stored in a
///
///     azip!(mut a, b, c in { *a = b + c });
///
///     assert_eq!(a, &b + &c);
///
///     // Example of azip!() with index
///
///     azip!(index (i, j), b, c in {
///         a[[i, j]] = b - c;
///     });
///
///     assert_eq!(a, &b - &c);
/// }
/// ```
macro_rules! azip {
    // Build Zip Rule (index)
    (@parse [index => $a:expr, $($aa:expr,)*] $t1:tt in $t2:tt) => {
        azip!(@finish ($crate::Zip::indexed($a)) [$($aa,)*] $t1 in $t2)
    };
    // Build Zip Rule (no index)
    (@parse [$a:expr, $($aa:expr,)*] $t1:tt in $t2:tt) => {
        azip!(@finish ($crate::Zip::from($a)) [$($aa,)*] $t1 in $t2)
    };
    // Build Finish Rule (both)
    (@finish ($z:expr) [$($aa:expr,)*] [$($p:pat,)+] in { $($t:tt)*}) => {
        #[allow(unused_mut)]
        ($z)
            $(
                .and($aa)
            )*
            .apply(|$($p),+| {
                $($t)*
            })
    };
    // parsing stack: [expressions] [patterns] (one per operand)
    // index uses empty [] -- must be first
    (@parse [] [] index $i:pat, $($t:tt)*) => {
        azip!(@parse [index =>] [$i,] $($t)*);
    };
    (@parse [$($exprs:tt)*] [$($pats:tt)*] mut $x:ident ($e:expr) $($t:tt)*) => {
        azip!(@parse [$($exprs)* $e,] [$($pats)* mut $x,] $($t)*);
    };
    (@parse [$($exprs:tt)*] [$($pats:tt)*] mut $x:ident $($t:tt)*) => {
        azip!(@parse [$($exprs)* &mut $x,] [$($pats)* mut $x,] $($t)*);
    };
    (@parse [$($exprs:tt)*] [$($pats:tt)*] , $($t:tt)*) => {
        azip!(@parse [$($exprs)*] [$($pats)*] $($t)*);
    };
    (@parse [$($exprs:tt)*] [$($pats:tt)*] ref $x:ident ($e:expr) $($t:tt)*) => {
        azip!(@parse [$($exprs)* $e,] [$($pats)* $x,] $($t)*);
    };
    (@parse [$($exprs:tt)*] [$($pats:tt)*] ref $x:ident $($t:tt)*) => {
        azip!(@parse [$($exprs)* &$x,] [$($pats)* $x,] $($t)*);
    };
    (@parse [$($exprs:tt)*] [$($pats:tt)*] $x:ident ($e:expr) $($t:tt)*) => {
        azip!(@parse [$($exprs)* $e,] [$($pats)* &$x,] $($t)*);
    };
    (@parse [$($exprs:tt)*] [$($pats:tt)*] $x:ident $($t:tt)*) => {
        azip!(@parse [$($exprs)* &$x,] [$($pats)* &$x,] $($t)*);
    };
    (@parse [$($exprs:tt)*] [$($pats:tt)*] $($t:tt)*) => { };
    ($($t:tt)*) => {
        azip!(@parse [] [] $($t)*);
    }
}