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