diff --git a/src/lib.rs b/src/lib.rs index ed419b6..3b44847 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,7 @@ //! allowing for conditionals and nested comprehensions. //! //! # Python Syntax -//! ``` +//! ```python //! squares = [x*x for x in range(10)] //! //! even_squares = [x*x for x in range(10) if x % 2 == 0] @@ -17,13 +17,13 @@ //! ``` //! #[macro_use(c)] //! extern crate cute; -//! +//! # fn main() { // needed to include macro //! let squares = c![x*x, for x in 0..10]; //! //! let even_squares = c![x*x, for x in 0..10, if x % 2 == 0]; //! //! let squares_hashmap = c!{key => key*key, for key in 0..10}; -//! +//! # } //! ``` //! //! `c!`'s has the comprehension's parts, comma-separated. @@ -33,54 +33,99 @@ //! Simple comprehension //! //! ``` -//! let v = [1,2,3,4]; +//! # #[macro_use(c)] +//! # extern crate cute; +//! # // otherwise its implicitly put in a function, so you can't `use` +//! # fn main() { +//! let v = vec![1,2,3,4]; //! let v_squared = c![x*x, for x in v]; -//! +//! # } //! ``` //! Conditional filtering //! //! ``` +//! # #[macro_use(c)] +//! # extern crate cute; +//! # fn main() { //! let squares = c![x*x, for x in 0..10, if x % 2 == 0]; //! assert_eq!(squares, vec![0, 4, 16, 36, 64]); +//! # } +//! ``` +//! +//! Comprehensions over tuples +//! +//! ``` +//! # #[macro_use(c)] +//! # extern crate cute; +//! # fn main() { +//! let v1 = vec![1, 2, 3]; +//! let v2 = vec![10, 11, 12]; +//! let sums = c![x+y, for (x,y) in v1.iter().zip(v2)]; +//! assert_eq!(sums, vec![11, 13, 15]); +//! # } //! ``` //! //! Nested Comprehensions //! //! ``` +//! # #[macro_use(c)] +//! # extern crate cute; +//! # fn main() { //! let nested = vec![vec![1,2,3], vec![4,5,6], vec![7,8,9]]; //! let flat: Vec = c![x, for x in y, for y in nested]; //! assert_eq!(flat, vec![1, 2, 3, 4, 5, 6, 7, 8, 9]); +//! # } //! ``` //! //! ``` +//! # #[macro_use(c)] +//! # extern crate cute; +//! # fn main() { //! let nested = vec![vec![1,2,3], vec![4,5,6], vec![7,8,9]]; //! let even_flat: Vec = c![x, for x in y, for y in nested, if x % 2 == 0]; //! assert_eq!(even_flat, vec![2, 4, 6, 8]); +//! # } //! ``` //! //! Comprehensions over Iterators //! //! ``` +//! # #[macro_use(c)] +//! # extern crate cute; +//! # fn main() { //! let vec: Vec = vec![-4, -2, 0, 2, 4]; //! let output: Vec = c![x*2, for x in vec.iter()]; //! assert_eq!(output, vec![-8, -4, 0, 4, 8]); +//! # } //! ``` //! //! ``` +//! # #[macro_use(c)] +//! # extern crate cute; +//! # fn main() { //! let vec: Vec = vec![-4, -2, 0, 2, 4]; //! let output: Vec = c![x, for x in vec.iter(), if *x >= 0i32]; //! assert_eq!(output, vec![0, 2, 4]); +//! # } //! ``` //! + //! Function Application //! //! ``` +//! # #[macro_use(c)] +//! # extern crate cute; +//! # fn main() { //! let vec: Vec = vec![-4, -2, 0, 2, 4]; //! let output: Vec = c![x.abs(), for x in vec.iter()]; //! assert_eq!(output, vec![4, 2, 0, 2, 4]); +//! # } //! ``` //! //! ``` +//! # #[macro_use(c)] +//! # extern crate cute; +//! # fn main() { //! fn square(x:i32) -> i32 { //! x*x //! } @@ -88,11 +133,16 @@ //! let vec: Vec = vec![-4, -2, 0, 2, 4]; //! let squares: Vec = c![square(x), for x in vec]; //! assert_eq!(squares, vec![16, 4, 0, 4, 16]); +//! # } //! ``` //! //! Hashmap Comprehensions //! //! ``` +//! # #[macro_use(c)] +//! # extern crate cute; +//! # use std::collections::HashMap; +//! # fn main() { //! let v = vec!["one", "two", "three"]; //! let map = c!{key => key.to_uppercase(), for key in v}; //! @@ -102,9 +152,14 @@ //! expected.insert("three", String::from("THREE")); //! //! assert_eq!(map, expected); +//! # } //! ``` //! //! ``` +//! # #[macro_use(c)] +//! # extern crate cute; +//! # use std::collections::HashMap; +//! # fn main() { //! let v: Vec<(&str, i32)> = vec![("one", 1), ("two", 2), ("three", 3)]; //! let map = c!{key => val, for (key, val) in v}; //! @@ -114,9 +169,14 @@ //! expected.insert("three", 3); //! //! assert_eq!(map, expected); +//! # } //! ``` //! //! ``` +//! # #[macro_use(c)] +//! # extern crate cute; +//! # use std::collections::HashMap; +//! # fn main() { //! // conditional hashmap comprehension //! let v: Vec<(&str, i32)> = vec![("one", 1), ("two", 2), ("three", 3)]; //! let map = c! {key => val, for (key, val) in v, if val == 1 || val == 2}; @@ -126,35 +186,42 @@ //! expected.insert("two", 2); //! //! assert_eq!(map, expected); +//! # } //! ``` //! //! ``` +//! # #[macro_use(c)] +//! # extern crate cute; +//! # use std::collections::HashMap; +//! # fn main() { //! // conditional hashmap comprehension from an Iterator //! let map = c! {*key => key*key, for key in vec![1,2].iter(), if *key % 2 == 0}; //! let mut e: HashMap = HashMap::new(); //! e.insert(2, 4); //! //! assert_eq!(map, e); +//! # } //! ``` + #[macro_export] macro_rules! c { - ($exp:expr, for $i:ident in $iter:expr) => ( + ($exp:expr, for $p:pat in $iter:expr) => ( { let mut r = vec![]; - for $i in $iter { + for $p in $iter { r.push($exp); } r } ); - ($exp:expr, for $i:ident in $iter:expr, if $cond:expr) => ( + ($exp:expr, for $p:pat in $iter:expr, if $cond:expr) => ( { let mut r = vec![]; - for $i in $iter { + for $p in $iter { if $cond { r.push($exp.clone()); } @@ -163,11 +230,11 @@ macro_rules! c { } ); - ($exp:expr, for $i:ident in $iter:expr, for $i2:ident in $iter2:expr) => ( + ($exp:expr, for $p:pat in $iter:expr, for $p2:pat in $iter2:expr) => ( { let mut r = vec![]; - for $i2 in $iter2 { - for $i in $iter { + for $p2 in $iter2 { + for $p in $iter { r.push($exp); } } @@ -175,11 +242,11 @@ macro_rules! c { } ); - ($exp:expr, for $i:ident in $iter:expr, for $i2:ident in $iter2:expr, if $cond:expr) => ( + ($exp:expr, for $p:pat in $iter:expr, for $p2:pat in $iter2:expr, if $cond:expr) => ( { let mut r = vec![]; - for $i2 in $iter2 { - for $i in $iter { + for $p2 in $iter2 { + for $p in $iter { if $cond{ r.push($exp); } @@ -189,12 +256,12 @@ macro_rules! c { } ); - ($exp:expr, for $i:ident in $iter:expr, for $i2:ident in $iter2:expr, for $i3:ident in $iter3:expr, if $cond:expr) => ( + ($exp:expr, for $p:pat in $iter:expr, for $p2:pat in $iter2:expr, for $p3:pat in $iter3:expr, if $cond:expr) => ( { let mut r = vec![]; - for $i in $iter { - for $i2 in $iter2 { - for $i3 in $iter3 { + for $p in $iter { + for $p2 in $iter2 { + for $p3 in $iter3 { if $cond { r.push($exp); } @@ -205,12 +272,12 @@ macro_rules! c { } ); - ($exp:expr, for $i:ident in $iter:expr, for $i2:ident in $iter2:expr, for $i3:ident in $iter3:expr) => ( + ($exp:expr, for $p:pat in $iter:expr, for $p2:pat in $iter2:expr, for $p3:pat in $iter3:expr) => ( { let mut r = vec![]; - for $i in $iter { - for $i2 in $iter2 { - for $i3 in $iter3 { + for $p in $iter { + for $p2 in $iter2 { + for $p3 in $iter3 { r.push($exp); } } @@ -277,12 +344,24 @@ mod tests { assert_eq!(squares, vec![0, 1, 4, 9, 16, 25, 36, 49, 64, 81]); } + #[test] + fn tuple_comprehension() { + let pairs = c![(x,y), for (x, y) in (0..3).zip(100..103)]; + assert_eq!(pairs, vec![(0, 100), (1, 101), (2, 102)]); + } + #[test] fn filter_comprehension() { let squares = c![x*x, for x in 0..10, if x % 2 == 0]; assert_eq!(squares, vec![0, 4, 16, 36, 64]); } + #[test] + fn filter_tuple_comprehension() { + let matches = c![x, for (x,y) in vec![0,1,2].iter().zip(vec![0,3,2]), if x == &y]; + assert_eq!(matches, vec![0, 2]); + } + #[test] fn simple_nested_comprehension() { let nested = vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]];