cascade/
lib.rs

1/// A macro for chaining together statements that act on an initial expression.
2/// # Usage
3/// Cascading allows you to run multiple statements on a struct generated by an expression without having
4/// to repeatedly type it out. This can be very convinient for modifying multiple properties simultaneously,
5/// or running a long series of individual methods on a struct.
6///
7/// When writing a cascade, the first line specifies the expression that will be operated upon.
8/// All following lines modify the struct created by the expression in some way.
9/// The most common operator is the `..` member operator, which is borrowed from Dart's syntax.
10/// It's a convinient shorthand for accessing a member or method of the struct. For example:
11/// ```
12/// use cascade::cascade;
13///
14/// let old_vector = vec!(1, 2, 3);
15/// let new_vector = cascade! {
16///   old_vector;
17///   ..push(4);
18///   ..push(5);
19///   ..push(6);
20/// };
21/// ```
22///
23/// Remember, you can't move the struct, because it gets returned at the end of the cascade. In other words,
24/// you can't run a method on a struct with the `..` operator if the method takes `self` or
25/// `mut self`. But `&self` or `&mut self` works fine.
26///
27/// You can also put statements without a `..` in a cascade macro:
28/// ```
29/// use cascade::cascade;
30/// use std::collections::HashMap;
31///
32/// let hash_map = cascade! {
33///   HashMap::new();
34///   ..insert("foo", "bar");
35///   println!("Look! You can put statements in a cascade!");
36///   for i in 0..3 {
37///     println!("You can put loops in here too! Make sure to put a semicolon at the end!");
38///   };
39/// };
40/// ```
41///
42/// If you need to reference the expression inside a cascade, you can name it using `let`:
43/// ```
44/// use cascade::cascade;
45///
46/// let vector = cascade! {
47///   let v = Vec::new();
48///   ..push(1);
49///   println!("The vector now has {} element(s).", v.len());
50///   ..push(2);
51/// };
52/// ```
53/// This will print `The vector now has 1 element(s).`
54///
55/// Once again, trying to move this value will throw an error.
56///
57/// Finally, you can also use the member operator (`..`) to set or change members of the cascaded struct:
58/// ```
59/// use cascade::cascade;
60/// struct A {
61///   pub b: u32,
62///   pub c: u32
63/// }
64///
65/// let a = cascade! {
66///   A { b: 0, c: 0 };
67///   ..b = 5;
68///   ..c += 1;
69/// };
70/// ```
71///
72/// More examples of the cascade macro can be found in the examples folder on the Github repository.
73#[macro_export]
74macro_rules! cascade {
75    (let _ : $t:ty = $e: expr; $($tail: tt)*) => {
76        cascade!(let __tmp: $t = $e; $($tail)*)
77    };
78    (let $i:ident : $t:ty = $e: expr; $($tail: tt)*) => {
79        {
80            let mut $i: $t = $e;
81            cascade!(@line $i, $($tail)*)
82        }
83    };
84    (let $i:ident = $e: expr; $($tail: tt)*) => {
85      {
86        let mut $i = $e;
87        cascade!(@line $i, $($tail)*)
88      }
89    };
90    ($e: expr; $($tail: tt)*) => {
91        cascade!(let __tmp = $e; $($tail)*)
92    };
93    (@line $i: ident, .. $v: ident = $e: expr; $($tail: tt)*) => {
94        {
95            $i.$v = $e;
96            $crate::cascade!(@line $i, $($tail)*)
97        }
98    };
99    (@line $i:ident, .. $v:ident += $e:expr; $($tail:tt)*) => {
100        {
101            $i.$v += $e;
102            $crate::cascade!(@line $i, $($tail)*)
103        }
104    };
105    (@line $i:ident, .. $v:ident -= $e:expr; $($tail:tt)*) => {
106        {
107            $i.$v -= $e;
108            $crate::cascade!(@line $i, $($tail)*)
109        }
110    };
111    (@line $i:ident, .. $v:ident *= $e:expr; $($tail:tt)*) => {
112        {
113            $i.$v *= $e;
114            $crate::cascade!(@line $i, $($tail)*)
115        }
116    };
117    (@line $i:ident, .. $($q: ident ($($e: expr),*)).+; $($tail: tt)*) => {
118        {
119            $i.$($q($($e),*)).+;
120            $crate::cascade!(@line $i, $($tail)*)
121        }
122    };
123    (@line $i:ident, .. $($q: ident ($($e: expr),*)).+?; $($tail: tt)*) => {
124        {
125            $i.$($q($($e),*)).+?;
126            $crate::cascade!(@line $i, $($tail)*)
127        }
128    };
129    (@line $i:ident, { $($t:tt)* }; $($tail: tt)*) => {
130        {
131            { $crate::cascade!(@line $i, $($t)*); }
132            $crate::cascade!(@line $i, $($tail)*)
133        }
134    };
135    (@line $i:ident, $s: stmt; $($tail: tt)*) => {
136        {
137            $s
138            cascade!(@line $i, $($tail)*)
139        }
140    };
141    (@line $i:ident, { $($t:tt)* }) => {
142        { $crate::cascade!(@line $i, $($t)*) }
143    };
144    (@line $i:ident, .. $($q: ident ($($e: expr),*)).+) => {
145        $i.$($q($($e),*)).+
146    };
147    (@line $i:ident, $e:expr) => {
148        $e
149    };
150    (@line $i:ident,) => {
151        $i
152    };
153    () => {}
154}