const_for/lib.rs
1//! # An ergonomic for loop for const contexts
2//!
3//! [](https://github.com/JENebel/const_for)
4//! [](http://crates.io/crates/const_for)
5//! [](https://docs.rs/const_for/latest)
6//!
7//! Regular for loops are not allowed in const contexts, because it relies on iterators, which are not available in const.\
8//! This is rather annoying when writing const functions, as you need to write custom for loops using 'loop' or 'while'.
9//!
10//! This crate provides an ergonomic macro implementation of a for loop over a range, that is usable in const and `no_std` contexts.\
11//! The aim is to imitate a regular for loop as closely as possible. It handles break and continue correctly, and the variable is immutable in the body.\
12//! To make the for loop as versatile as possible, it comes with macro variants to handle .rev() and step_by(x), which imitates the respective function calls.
13//! This is necessary, as normally they depend on non-const iterators. But they can be used here with identical syntax.
14//!
15//! The main restriction is that the macro only supports standard, exclusive, ranges, eg. 0..10 and -5..5, but not ..5 or 0..=10.
16//!
17//! ```
18//! # use const_for::*;
19//! let mut a = 0;
20//! const_for!(i in 0..5 => {
21//! a += i
22//! });
23//! assert!(a == 10)
24//! ```
25//!
26//! This is equivalent to the following regular for loop, except it is usable in const context.
27//!
28//! ```
29//! # use const_for::*;
30//! let mut a = 0;
31//! for i in 0..5 {
32//! a += i
33//! }
34//! assert!(a == 10)
35//! ```
36//!
37//! ## Custom step size
38//!
39//! A custom step size can be set:
40//!
41//! ```
42//! # use const_for::*;
43//! let mut v = Vec::new();
44//! const_for!(i in (0..5).step_by(2) => {
45//! v.push(i)
46//! });
47//! assert!(v == vec![0, 2, 4])
48//! ```
49//!
50//! The loop behaves as if the function was called on the range, but it is implemented by a macro.\
51//! It is equivalent to the following non-const loop:
52//!
53//! ```
54//! # use const_for::*;
55//! let mut v = Vec::new();
56//! for i in (0..5).step_by(2) {
57//! v.push(i)
58//! }
59//! assert!(v == vec![0, 2, 4])
60//! ```
61//!
62//! ## Reversed
63//!
64//! Iteration can be reversed:
65//!
66//! ```
67//! # use const_for::*;
68//! let mut v = Vec::new();
69//! const_for!(i in (0..5).rev() => {
70//! v.push(i)
71//! });
72//! assert!(v == vec![4, 3, 2, 1, 0])
73//! ```
74//!
75//! The loop behaves as if the function was called on the range, but it is implemented by a macro.\
76//! It is equivalent to the following non-const loop:
77//!
78//! ```
79//! # use const_for::*;
80//! let mut v = Vec::new();
81//! for i in (0..5).rev() {
82//! v.push(i)
83//! }
84//! assert!(v == vec![4, 3, 2, 1, 0])
85//! ```
86//!
87//! ## Reversed and custom step size
88//!
89//! It is possible to combine rev and step_by, but each can only be appended once. So the following two examples are the only legal combinations.
90//!
91//! ```
92//! # use const_for::*;
93//! // Reverse, then change step size
94//! let mut v = Vec::new();
95//! const_for!(i in (0..10).rev().step_by(4) => {
96//! v.push(i)
97//! });
98//! assert!(v == vec![9, 5, 1]);
99//!
100//! // Change step size, then reverse
101//! let mut v = Vec::new();
102//! const_for!(i in (0..10).step_by(4).rev() => {
103//! v.push(i)
104//! });
105//! assert!(v == vec![8, 4, 0])
106//! ```
107//!
108//! ## Notes
109//!
110//! You can use mutable and wildcard variables as the loop variable, and they act as expected.
111//!
112//! ```
113//! // Mutable variable
114//! # use const_for::*;
115//! let mut v = Vec::new();
116//! const_for!(mut i in (0..4) => {
117//! i *= 2;
118//! v.push(i)
119//! });
120//! assert!(v == vec![0, 2, 4, 6]);
121//!
122//! // Wildcard variable
123//! let mut a = 0;
124//! const_for!(_ in 0..5 =>
125//! a += 1
126//! );
127//! assert!(a == 5)
128//! ```
129//!
130//! The body of the loop can be any statement. This means that the following is legal, even though it is not in a regular for loop.
131//!
132//! ```
133//! # use const_for::*;
134//! let mut a = 0;
135//! const_for!(_ in 0..5 => a += 1);
136//!
137//! unsafe fn unsafe_function() {}
138//! const_for!(_ in 0..5 => unsafe {
139//! unsafe_function()
140//! });
141//! ```
142//!
143//! If the beginning of the range plus the step overflows the integer behaviour is undefined.
144//!
145//! ### Real world example
146//!
147//! Here is an example of how this crate helped make some actual code much nicer and readable.
148//!
149//! The code was taken (and edited a bit for clarity) from the [Cadabra](https://github.com/JENebel/Cadabra/) chess engine.
150//!
151//! Before:
152//!
153//! ```
154//! const fn gen_white_pawn_attacks() -> [u64; 64] {
155//! let mut masks = [0; 64];
156//!
157//! let mut rank: u8 = 0;
158//! while rank < 8 {
159//! let mut file: u8 = 0;
160//! while file < 8 {
161//! let index = (rank*8+file) as usize;
162//! if file != 7 { masks[index] |= (1 << index) >> 7 as u64 }
163//! if file != 0 { masks[index] |= (1 << index) >> 9 as u64 }
164//!
165//! file += 1;
166//! }
167//! rank += 1;
168//! }
169//!
170//! masks
171//! }
172//! ```
173//!
174//! After:
175//!
176//! ```
177//! # use const_for::*;
178//! const fn gen_white_pawn_attacks() -> [u64; 64] {
179//! let mut masks = [0; 64];
180//!
181//! const_for!(rank in 0..8 => {
182//! const_for!(file in 0..8 => {
183//! let index = (rank*8+file) as usize;
184//! if file != 7 { masks[index] |= (1 << index) >> 7 as u64 }
185//! if file != 0 { masks[index] |= (1 << index) >> 9 as u64 }
186//! })
187//! });
188//!
189//! masks
190//! }
191//! ```
192
193#![no_std]
194mod const_for;
195pub use const_for::*;