ruint/const_for.rs
1/// Compile time for loops with a `const` variable for testing.
2///
3/// Repeats a block of code with different values assigned to a constant.
4///
5/// ```rust
6/// # use ruint::{const_for, nlimbs, Uint};
7/// const_for!(BITS in [0, 10, 100] {
8/// const LIMBS: usize = nlimbs(BITS);
9/// println!("{:?}", Uint::<BITS, LIMBS>::MAX);
10/// });
11/// ```
12///
13/// is equivalent to
14///
15/// ```rust
16/// # use ruint::{const_for, Uint};
17/// println!("{:?}", Uint::<0, 0>::MAX);
18/// println!("{:?}", Uint::<10, 1>::MAX);
19/// println!("{:?}", Uint::<100, 2>::MAX);
20/// ```
21///
22/// It comes with two built-in lists: `NON_ZERO` which is equivalent to
23///
24/// ```text
25/// [1, 2, 63, 64, 65, 127, 128, 129, 256, 384, 512, 4096]
26/// ```
27///
28/// and `SIZES` which is the same but also has `0` as a value.
29///
30/// In combination with [`proptest!`][proptest::proptest] this allows for
31/// testing over a large range of [`Uint`][crate::Uint] types and values:
32///
33/// ```rust
34/// # use proptest::prelude::*;
35/// # use ruint::{const_for, nlimbs, Uint};
36/// const_for!(BITS in SIZES {
37/// const LIMBS: usize = nlimbs(BITS);
38/// proptest!(|(value: Uint<BITS, LIMBS>)| {
39/// // ... test code
40/// });
41/// });
42/// ```
43#[macro_export]
44macro_rules! const_for {
45 ($C:ident in [ $( $n:literal ),* ] $x:block) => {
46 $({
47 const $C: usize = $n;
48 $x
49 })*
50 };
51 ($C:ident in SIZES $x:block) => {
52 $crate::const_for!($C in [0] $x);
53 $crate::const_for!($C in NON_ZERO $x);
54 };
55 ($C:ident in NON_ZERO $x:block) => {
56 $crate::const_for!($C in [1, 2, 63, 64, 65, 127, 128, 129, 256, 384, 512, 4096] $x);
57 };
58 ($C:ident in BENCH $x:block) => {
59 $crate::const_for!($C in [0, 64, 128, 192, 256, 384, 512, 4096] $x);
60 };
61 ($C:ident in $S:ident if ( $c:expr ) $x:block) => {
62 $crate::const_for!($C in $S {
63 if $c {
64 $x
65 }
66 });
67 };
68}