#![cfg_attr(
feature = "coroutines",
feature(coroutines, coroutine_trait, stmt_expr_attributes)
)]
#[cfg(feature = "coroutines")]
#[doc(hidden)]
pub mod iterator_comprehension {
#[doc(hidden)]
pub struct CoroutineIterator<C: ::std::ops::Coroutine + ::std::marker::Unpin> {
coroutine: C,
}
impl<C: ::std::ops::Coroutine + ::std::marker::Unpin> CoroutineIterator<C> {
pub fn new(coroutine: C) -> CoroutineIterator<C> {
CoroutineIterator { coroutine }
}
}
impl<C: ::std::ops::Coroutine + ::std::marker::Unpin> Iterator for CoroutineIterator<C> {
type Item = C::Yield;
fn next(&mut self) -> Option<Self::Item> {
use ::std::ops::CoroutineState;
match ::std::pin::Pin::new(&mut self.coroutine).resume(()) {
CoroutineState::Yielded(y) => Some(y),
_ => None,
}
}
}
#[cfg_attr(
feature = "coroutines",
doc = r##"
```rust
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
#[macro_use]
extern crate mapcomp;
# fn main() {
let numbers = [8, 3, 5, 7];
let mut powers_of_two = iterc!(1 << x; for x in &numbers);
assert_eq!(Some(256), powers_of_two.next());
assert_eq!(Some(8), powers_of_two.next());
assert_eq!(Some(32), powers_of_two.next());
assert_eq!(Some(128), powers_of_two.next());
assert_eq!(None, powers_of_two.next());
# }
```
Since it only creates an iterator and not a fully populated container, the
comprehension can be created over an unbounded or infinite iterator.
```rust
# #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
# #[macro_use] extern crate mapcomp;
# fn main() {
let mut odd_squares = iterc!(x * x; for x in 1..; if x % 2 == 1);
assert_eq!(Some(1), odd_squares.next());
assert_eq!(Some(9), odd_squares.next());
assert_eq!(Some(25), odd_squares.next());
assert_eq!(Some(49), odd_squares.next());
# }
```
"##
)]
#[macro_export]
macro_rules! iterc {
(@__ $exp:expr; for $item:pat in $iter:expr; if $cond:expr) => (
for $item in $iter {
if $cond {
yield $exp;
}
}
);
(@__ $exp:expr; for $item:pat in $iter:expr) => (
for $item in $iter {
yield $exp;
}
);
(@__ $exp:expr; for $item:pat in $iter:expr; if $cond:expr; $($tail:tt)+) => (
for $item in $iter {
if $cond {
iterc!(@__ $exp; $($tail)+)
}
}
);
(@__ $exp:expr; for $item:pat in $iter:expr; $($tail:tt)+) => (
for $item in $iter {
iterc!(@__ $exp; $($tail)+)
}
);
($exp:expr; $($tail:tt)+) => ({
let mut coroutine = #[coroutine] || {
iterc!(@__ $exp; $($tail)+)
};
::mapcomp::iterator_comprehension::CoroutineIterator::new(coroutine)
});
}
}
#[macro_export]
macro_rules! vecc {
(@__ $acc:ident, $exp:expr; for $item:pat in $iter:expr; if $cond:expr) => (
for $item in $iter {
if $cond {
$acc.push($exp);
}
}
);
(@__ $acc:ident, $exp:expr; for $item:pat in $iter:expr) => (
for $item in $iter {
$acc.push($exp);
}
);
(@__ $acc:ident, $exp:expr; for $item:pat in $iter:expr; if $cond:expr; $($tail:tt)+) => (
for $item in $iter {
if $cond {
vecc![@__ $acc, $exp; $($tail)+];
}
}
);
(@__ $acc:ident, $exp:expr; for $item:pat in $iter:expr; $($tail:tt)+) => (
for $item in $iter {
vecc![@__ $acc, $exp; $($tail)+];
}
);
($exp:expr; $($tail:tt)+) => ({
let mut ret = ::std::vec::Vec::new();
vecc![@__ ret, $exp; $($tail)+];
ret
});
}
#[macro_export]
macro_rules! hashsetc {
(@__ $acc:ident, $exp:expr; for $item:pat in $iter:expr; if $cond:expr) => (
for $item in $iter {
if $cond {
$acc.insert($exp);
}
}
);
(@__ $acc:ident, $exp:expr; for $item:pat in $iter:expr) => (
for $item in $iter {
$acc.insert($exp);
}
);
(@__ $acc:ident, $exp:expr; for $item:pat in $iter:expr; if $cond:expr; $($tail:tt)+) => (
for $item in $iter {
if $cond {
hashsetc!{@__ $acc, $exp; $($tail)+};
}
}
);
(@__ $acc:ident, $exp:expr; for $item:pat in $iter:expr; $($tail:tt)+) => (
for $item in $iter {
hashsetc!{@__ $acc, $exp; $($tail)+};
}
);
($exp:expr; $($tail:tt)+) => ({
let mut ret = ::std::collections::HashSet::new();
hashsetc!{@__ ret, $exp; $($tail)+};
ret
});
}
#[macro_export]
macro_rules! hashmapc {
(@__ $acc:ident, $key:expr => $val:expr; for $item:pat in $iter:expr; if $cond:expr) => (
for $item in $iter {
if $cond {
$acc.insert($key, $val);
}
}
);
(@__ $acc:ident, $key:expr => $val:expr; for $item:pat in $iter:expr) => (
for $item in $iter {
$acc.insert($key, $val);
}
);
(@__ $acc:ident, $key:expr => $val:expr; for $item:pat in $iter:expr; if $cond:expr; $($tail:tt)+) => (
for $item in $iter {
if $cond {
hashmapc!{@__ $acc, $key => $val; $($tail)+};
}
}
);
(@__ $acc:ident, $key:expr => $val:expr; for $item:pat in $iter:expr; $($tail:tt)+) => (
for $item in $iter {
hashmapc!{@__ $acc, $key => $val; $($tail)+};
}
);
($key:expr => $val:expr; $($tail:tt)+) => ({
let mut ret = ::std::collections::HashMap::new();
hashmapc!{@__ ret, $key => $val; $($tail)+};
ret
});
}
#[macro_export]
macro_rules! btreesetc {
(@__ $acc:ident, $exp:expr; for $item:pat in $iter:expr; if $cond:expr) => (
for $item in $iter {
if $cond {
$acc.insert($exp);
}
}
);
(@__ $acc:ident, $exp:expr; for $item:pat in $iter:expr) => (
for $item in $iter {
$acc.insert($exp);
}
);
(@__ $acc:ident, $exp:expr; for $item:pat in $iter:expr; if $cond:expr; $($tail:tt)+) => (
for $item in $iter {
if $cond {
btreesetc!{@__ $acc, $exp; $($tail)+};
}
}
);
(@__ $acc:ident, $exp:expr; for $item:pat in $iter:expr; $($tail:tt)+) => (
for $item in $iter {
btreesetc!{@__ $acc, $exp; $($tail)+};
}
);
($exp:expr; $($tail:tt)+) => ({
let mut ret = ::std::collections::BTreeSet::new();
btreesetc!{@__ ret, $exp; $($tail)+};
ret
});
}
#[macro_export]
macro_rules! btreemapc {
(@__ $acc:ident, $key:expr => $val:expr; for $item:pat in $iter:expr; if $cond:expr) => (
for $item in $iter {
if $cond {
$acc.insert($key, $val);
}
}
);
(@__ $acc:ident, $key:expr => $val:expr; for $item:pat in $iter:expr) => (
for $item in $iter {
$acc.insert($key, $val);
}
);
(@__ $acc:ident, $key:expr => $val:expr; for $item:pat in $iter:expr; if $cond:expr; $($tail:tt)+) => (
for $item in $iter {
if $cond {
btreemapc!{@__ $acc, $key => $val; $($tail)+};
}
}
);
(@__ $acc:ident, $key:expr => $val:expr; for $item:pat in $iter:expr; $($tail:tt)+) => (
for $item in $iter {
btreemapc!{@__ $acc, $key => $val; $($tail)+};
}
);
($key:expr => $val:expr; $($tail:tt)+) => ({
let mut ret = ::std::collections::BTreeMap::new();
btreemapc!{@__ ret, $key => $val; $($tail)+};
ret
});
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
let _v = vecc![x * x; for x in 1..10; if x % 2 == 0];
}
}