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 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
//! A C-style `for` loop in macro form. //! //! This takes the form `cfor!(initialiser; condition; step { body })`. //! //! - `initialiser` is a statement evaluated before any iterations of //! the loop. Any variables declared here are scoped to the `cfor!` //! invocation, that is, only usable inside `condition`, `step` and //! `body`. //! - `condition` is an boolean expression evaluated at the start of //! each iteration. If it evaluates to `false` iteration will stop. //! - `step` is an arbitrary expression which is executed at the end //! of each iteration (including if `continue` is called), before //! `condition` is checked. //! //! //! The initialiser and condition can be empty like C, but the step //! cannot unlike C. A `for` loop with no step is identical to a //! `while` loop. //! //! [*Source & issue tracker*](https://github.com/huonw/cfor/) //! //! # When should I use it? //! //! *Only* when `cfor!` is clearer than the more declarative built-in //! [iterators](http://doc.rust-lang.org/master/std/iter/), [their //! adaptors](http://doc.rust-lang.org/master/std/iter/trait.Iterator.html) //! and the `for` loop. For example, the built-in iterator //! functionality is more self-contained so there is less risk of //! accidentally writing `i` in a condition when `j` was meant (I //! personally get bitten by this semiregularly when writing nested //! "2D" loops in C). //! //! Furthermore, the adaptor methods linked above allow [one to //! write](http://huonw.github.io/2014/06/10/knn-rust.html) concise, //! performant, reusable "functional" code in a way that is not //! possible to achieve using C-style iteration. //! //! # How to use it? //! //! Add the repository as a normal cargo dependency, and include into //! your crate with `#[phase(plugin)]`. (See examples below.) //! //! ```toml //! [dependencies.cfor] //! cfor = "1.0" //! ``` //! //! # Examples //! //! ## Simple //! //! A non-additive condition is not handled extremely naturally by //! `std::iter`, but is straight-forward to handle directly. //! //! ```rust //! #[macro_use] extern crate cfor; //! //! fn main() { //! cfor!{let mut x = 1; x < 0x1000; x *= 2; { //! println!("power of 2: {}", x); //! }} //! } //! ``` //! //! ## Intrabody condition //! //! If a condition requires some extra computation to be checked (or //! if there is some code that should always be evaluated, even if the //! condition will be `false` for a given iteration), the condition in //! the `cfor` header can be omitted. //! //! ```rust //! #[macro_use] extern crate cfor; //! //! fn main() { //! cfor!{let mut x = 1; ; x *= 2; { //! // ... setup ... //! println!("handling power of 2: {}", x); //! //! if x < 0x1000 { break } //! //! // ... further handling ... //! println!("handling power of 2: {}", x); //! }} //! } //! ``` //! //! ## Out-of-loop initialisation //! //! Sometimes one may wish to have access to a variable outside the //! loop after it finishes so it has to be declared outside the loop, //! or one may be iterating over some presupplied/-computed value so //! there is no meaningful additional initialisation possible. The //! initialisation expression can be safely omitted in this case. //! //! ```rust //! #[macro_use] extern crate cfor; //! //! extern crate rand; //! //! fn main() { //! let mut x = 1u16; //! //! cfor!{; x < 0x1000; x *= 2; { //! println!("power of 2: {}", x); //! //! // sometimes quit early //! if x > rand::random() { break } //! }} //! //! println!("actually stopped at {}", x); //! } //! ``` //! //! # Handling `continue` //! //! (Or, "why is the macro so complicated?") //! //! Special effort is made to ensure that `continue` acts correctly, a //! naive macro defined as follows will cause `continue` to also skip //! evaluating `step`, likely leading to undesirable behaviour like //! infinite loops. //! //! ```rust //! # // avoid our crate being inserted automatically, which gets in //! # // the way of the feature above. //! # #[macro_use] extern crate cfor; //! // WARNING: this is broken. //! macro_rules! bad_cfor { //! ($init: stmt; $cond: expr; $step: expr; $body: block) => { //! { //! $init; //! while $cond { //! $body; //! //! $step; //! } //! } //! } //! } //! //! fn main() { //! let mut true_counter = 0; //! //! bad_cfor!{let mut i = 0; i < 10; i += 1; { //! //! // manually avoid the infinite loop //! if true_counter >= 50 { break } //! true_counter += 1; //! //! println!("i = {}", i); //! // try to skip just i == 4 //! if i == 4 { //! // but this skips the i += 1 leaving us //! // on i == 4 forever. //! continue //! } //! // ...more code... //! }} //! } //! ``` //! //! This is invoked in the same manner as `cfor!`, but, if `$body` //! contains a `continue`, the `$step` at the end of the loop body //! will never be evaluated. //! //! # Handling multiple initializations and steps //! //! Like C loops, `cfor!` supports specfying multiple initializations and steps seperated by a comma. //! //! ```rust //! #[macro_use] extern crate cfor; //! //! fn main() { //! cfor!{let mut x = 0, let mut y = x; x <= 10 && y <= 100; x += 1, y += 10; { //! println!("x: {}, y: {}", x, y); //! }} //! } //! ``` /// A C-style `for` loop in macro form. /// /// See crates docs for more information. #[macro_export] macro_rules! cfor { // for (; ...; ...) { ... } (; $($rest: tt)*) => { cfor!((); $($rest)*) }; // for ($init; ; ...) { ... } ($($init: stmt),+; ; $($rest: tt)*) => { // avoid the `while true` lint cfor!($($init),+; !false; $($rest)*) }; // for ($init; $cond; ) { ... } ($($init: stmt),+; $cond: expr; ; $body: block) => { cfor!{$($init),+; $cond; (); $body} }; // for ($init; $cond; $step) { $body } ($($init: stmt),+; $cond: expr; $($step: expr),+; $body: block) => { { $($init;)+ while $cond { let mut _first = true; let mut _continue = false; // this loop runs once, allowing us to use `break` and // `continue` as `goto` to skip forward to the // condition. // // the booleans above are very transparent to the // optimiser, since they are modified exactly once, // with nice control flow, and this this optimises to // be similar to C for loop. loop { // if we *don't* hit this, there was a `break` in // the body (otherwise the loop fell-through or // was `continue`d.) if !_first { _continue = true; break } _first = false; $body } if !_continue { // the `if` wasn't hit, so we should propagate the // `break`. break } $($step;)+ } } }; }