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}