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
/*
* SPDX-FileCopyrightText: 2023 Tommaso Fontana
* SPDX-FileCopyrightText: 2023 Sebastiano Vigna
*
* SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later OR MIT
*/
#![doc = include_str!("../README.md")]
extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn::{
parse::{Parse, ParseStream, Result},
parse_macro_input,
token::In,
Block, Expr, Pat,
};
struct ForLenderInfo {
pub pat: Box<Pat>,
pub _in_token: In,
pub expr: Box<Expr>,
pub body: Block,
}
impl Parse for ForLenderInfo {
fn parse(input: ParseStream) -> Result<Self> {
Ok(ForLenderInfo {
pat: Box::new(Pat::parse_multi(input)?),
_in_token: input.parse()?,
expr: input.parse()?,
body: input.parse()?,
})
}
}
/**
Syntax sugar for iterating over a `Lender`.
This function-like macro expands a syntax of the form
```[ignore]
for_!(PATTERN in EXPR BLOCK);
```
where `PATTERN` is a valid pattern for a `for` loop, `EXPR` is an expression that
implements [`IntoLender`](https://docs.rs/lender/latest/lender/trait.IntoLender.html) and `BLOCK` is a block of code, into a `while let` loop that
iterates over a `Lender` obtained from the [`IntoLender`](https://docs.rs/lender/latest/lender/trait.IntoLender.html):
```[ignore]
let mut ___ඞඞඞlenderඞඞඞ___ = (EXPR).into_lender();
while let Some(PATTERN) = ___ඞඞඞlenderඞඞඞ___.next() BLOCK
```
For example, the following code
```[ignore]
for_!(x in from_into_iter(0..10) {
println!("{}", x);
});
```
iterates over the integers [0. .10), printing them,
using a [`Lender`](https://docs.rs/lender/latest/lender/trait.Lender.html) obtained by
adapting an `IntoIterator` (in this case, a `Range`).
For an example of a more complex usage, see the following code, which iterates over
the elements of an `enum`, but only on the first two variants:
```[ignore]
#[derive(Debug)]
enum Three {
A,
B,
C,
}
#[test]
pub fn test_bar() {
for_!(x @ (Three::A | Three::B) in from_into_iter([Three::A, Three::B, Three::C]) {
dbg!(x);
});
}
```
*/
#[proc_macro]
pub fn for_(input: TokenStream) -> TokenStream {
let ForLenderInfo {
pat,
_in_token,
expr,
body,
} = parse_macro_input!(input as ForLenderInfo);
quote! {{
let mut ___ඞඞඞlenderඞඞඞ___ = (#expr).into_lender();
while let Some( #pat ) = ___ඞඞඞlenderඞඞඞ___.next() #body
}}
.into()
}