Crate r4 [−] [src]

Provides a macro that generates an iterable sequence via for comprehensions (AKA list comprehensions).

If you're familiar with Python's list comprehensions or Scala's for comprehensions, this should be familiar. The use of the `yield` keyword is also similar to that of the recent generator syntax RFC.

Examples

Sequences are built out of `for` statements, which may be nested.

```#[macro_use(iterate)] extern crate r4;

let v: Vec<i32> = iterate![for x in 0..5; yield x * 2].collect();
assert_eq!(v, vec![0, 2, 4, 6, 8]);```

Multiple `for` statements are treated like nested loops.

```#[derive(Debug, Eq, PartialEq)]
struct Item { x: i32, y: i32, }

let v: Vec<Item> = iterate![for x in 0..3;
for y in 5..7;
yield Item { x: x, y: y, }]
.collect();

let mut w: Vec<Item> = Vec::new();
for x in 0..3 {
for y in 5..7 {
w.push(Item { x: x, y: y, });
}
}
assert_eq!(v, w);```

Stand-alone values may be `yield`ed.

```let v: Vec<i32> = iterate![yield 0; yield 2; yield 4; yield 6; yield 8].collect();
assert_eq!(v, vec![0, 2, 4, 6, 8]);```

Intermediate variables may be bound with `let`, which may take a pattern.

```let v: Vec<i32> = iterate![for x in 0..6; let y = x * 2; yield x * y].collect();
assert_eq!(v, vec![0, 2, 8, 18, 32, 50]);

struct Item { x: i32, y: i32, }
let v: Vec<i32> = iterate![for x in 0..3;
for y in 5..7;
let item = Item { x: x, y: y, };
let Item { x: a, y: b, } = item;
yield a;
yield b]
.collect();
assert_eq!(v, vec![0, 5, 0, 6, 1, 5, 1, 6, 2, 5, 2, 6]);```

Iteration may be short-circuited via `if`.

```let v: Vec<i32> = iterate![for x in 0..10; if x % 2 == 0; yield x].collect();
assert_eq!(v, vec![0, 2, 4, 6, 8]);```

A pattern-based guard may be employed via `if let`.

```fn process(a: i32) -> Option<i32> {
if a % 2 == 0 {
Some(a)
} else {
None
}
}

let v: Vec<i32> = iterate![for x in 0..10;
if let Some(y) = process(x);
yield y]
.collect();
assert_eq!(v, vec![0, 2, 4, 6, 8]);```

Expressions

See the macro for a full breakdown of expressions it recognizes. In brief, they are:

• `for x in xs`: introduces a new scope that iterates over `xs`, binding the pattern `x` to each of its values.
• `if cond`: short-circuits subsequent expressions if `cond` is not `true`.
• `if let pattern = expr`: introduces a new scope that binds `pattern` to `expr`, short-circuiting subsequent expressions if `pattern` does not match `expr`.
• `let a = b`: introduces a new scope that binds `a` (which may be a pattern) to `b`.
• `yield r`: emits the value of the expression `r`.

Example expansion

This macro invocation:

```#[macro_use(iterate)] extern crate r4;
let items = iterate![for x in 0..10;
let y = x + 1;
if y % 2 == 0;
let z = y + 3;
for x_prime in z..(z + 3);
yield x_prime];```

is expanded like so:

```extern crate r4;
let items = {
(0..10).flat_map(move |x| {
let y = x + 1;
r4::FlatIter::new(if y % 2 == 0 {
Some({ let z = y + 3;
(z..(z + 3)).flat_map(move |x_prime| {
::std::iter::once(x_prime)
})
})
} else {
None
})
})
};```

You can see in the example expansion above that the closures which `iterate!` creates move variables that they refer to out of their surrounding environment. This is done for lack of a better mechanism for ensuring that the iterator created by `iterate!` doesn't outlive values referred to by the closures it generates. This makes it possible for an `iterate!`-derived macro to own its data, as in:

```fn generate_values() -> Box<Iterator<Item=u32>> {
let xs = vec![1, 2, 3, 4];
Box::new(iterate![for x in 0..10; if xs.contains(&x); yield 2 * x])
}```

As a result, if you refer to a non-`Copy` value from within an `iterate!` macro, you will no longer be able to use that value.

```fn generate_values() -> Box<Iterator<Item=u32>> {
let xs = vec![1, 2, 3, 4];
let i = iterate![for x in 0..10; if xs.contains(&x); yield 2 * x];
// We already moved `xs` into the iterator above, so we can't use it again.
println!("xs are: {:?}", xs);  // Compilation error.
Box::new(i)
}```

This behavior can be circumvented by creating a borrow yourself, although this will restrict the lifetime of the iterator to that of the borrow.

```let xs = vec![1, 2, 3, 4];
let borrow = &xs;
// The iterators `i` and `j` are both limited to the lifetime of `borrow`,
// but they can share use of its data.
let i = iterate![for x in 0..10; if borrow.contains(&x); yield 2 * x];
let j = iterate![for x in 2..20; if borrow.contains(&x); yield 2 * x];
let v: Vec<i32> = i.chain(j).collect();
assert_eq!(v, vec![2, 4, 6, 8, 4, 6, 8]);```

Macros

 iterate Produces an iterator over values `yield`ed in a sequence of semicolon-separated expressions.

Structs

 FlatIter Flat-maps an Option where I: Iterator into the underlying iterator. You probably don't need to use this type directly. It is used internally by the `iterate!` macro.