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
//! A crate that provides a MBE to simulate the 'lists by understanding' of python in Rust almost like a zero-cost abstraction.

/// The macro takes an expression to use in a for loop, a pattern for this, a collection and a optional boolean expression, all of them separated with commas.
/// 
/// # Examples
///  
/// Because here we used a boolean the default code never reaches.
/// ```
/// let vec = vec![1, 2, 3];
/// #[allow(unreachable_code)] // needed here to prevent warnings
/// let vec = py_list![*i += 10, i, vec,*i != 2];
/// 
/// assert_eq!(vec, vec![11, 2, 13]);
/// ```
#[macro_export]
macro_rules! py_list {
    ($exp:expr, $variable:pat, $collection:ident $(, $boolean_exp:expr )? ) => {
        loop {
            $(
                for $variable in $collection.iter_mut() {
                    if $boolean_exp {
                        $exp
                    }
                }

                break $collection;
            )?

            for $variable in $collection.iter_mut() {
                $exp
            }

            break $collection;
        }
    };
}

#[cfg(test)]
mod test {
    #[test]
    fn with_bool() {
        let mut vec = vec![1, 2, 3];
        #[allow(unreachable_code)]
        let vec = py_list![*i += 10, i, vec, *i != 2];

        assert_eq!(vec, vec![11, 2, 13]);
    }

    #[test]
    fn without_bool() {
        let mut vec = vec![1, 2, 3];
        let vec: Vec<u8> = py_list![*i += 10, i, vec];

        assert_eq!(vec, vec![11, 12, 13]);
    }

    #[test]
    fn maps() {
        use std::collections::HashMap;

        let mut map = HashMap::new();
        map.insert("foo", 1);
        let map = py_list![*v += 1, (_, v), map];

        let mut map2 = HashMap::new();
        map2.insert("foo", 2);
        assert_eq!(map2, map);
    }
}