op_proc/
lib.rs

1use proc_macro::TokenStream;
2use quote::quote;
3use syn::parse::{Parse, ParseStream};
4use syn::{parse_macro_input, Block, Ident, LitInt, Token};
5
6
7struct RepeatInput {
8    n: LitInt,
9    _comma0: Token![,],
10    ident: Ident,
11    _comma1: Token![,],
12    block: Box<Block>,
13}
14
15impl Parse for RepeatInput {
16    fn parse(input: ParseStream) -> syn::Result<Self> {
17        Ok(RepeatInput {
18            n: input.parse()?,
19            _comma0: input.parse()?,
20            ident: input.parse()?,
21            _comma1: input.parse()?,
22            block: input.parse()?,
23        })
24    }
25}
26
27/// This macro generates an array with repeated blocks of code.
28/// 
29/// # Arguments
30/// 
31/// * `n` - The number of times to repeat the block.
32/// * `ident` - The identifier to use within the block.
33/// * `block` - The block of code to repeat.
34/// 
35/// # Example
36/// 
37/// ```rust
38/// use op_proc::array;
39/// let arr = [4, 5, 6, 7, 8];
40/// let narr = array!(3, i, {
41///    arr[i + 1] + 1
42/// });
43/// assert_eq!(narr, [6, 7, 8]);
44/// ```
45/// 
46/// This will expand to:
47/// 
48/// ```rust,ignore
49/// [
50///     {
51///         let i = 0;
52///         arr[i + 1] + 1
53///     },
54///     {
55///         let i = 1;
56///         arr[i + 1] + 1
57///     },
58///     {
59///         let i = 2;
60///         arr[i + 1] + 1
61///     }
62/// ]
63/// ```
64#[proc_macro]
65pub fn array(input: TokenStream) -> TokenStream {
66    let RepeatInput {
67        n, ident, block, ..
68    } = parse_macro_input!(input as RepeatInput);
69    let count = n.base10_parse::<usize>().expect("N must be an integer");
70
71    let blocks = expand(count, ident, block);
72    let output = quote! {
73         [#(#blocks),*]
74    };
75
76    output.into()
77}
78/// This macro generates a tuple with repeated blocks of code.
79/// 
80/// # Arguments
81/// 
82/// * `n` - The number of times to repeat the block.
83/// * `ident` - The identifier to use within the block.
84/// * `block` - The block of code to repeat.
85/// 
86/// # Example
87/// 
88/// ```rust
89/// use op_proc::tuple;
90/// let arr = [4, 5, 6, 7, 8];
91/// let ntuple = tuple!(3, i, {
92///    arr[i + 1] + 1
93/// });
94/// assert_eq!(ntuple, (6, 7, 8));
95/// ```
96/// 
97/// This will expand to:
98/// 
99/// ```rust,ignore
100/// (
101///     {
102///         let i = 0;
103///         arr[i + 1] + 1
104///     },
105///     {
106///         let i = 1;
107///         arr[i + 1] + 1
108///     },
109///     {
110///         let i = 2;
111///         arr[i + 1] + 1
112///     }
113/// )
114/// ```
115#[proc_macro]
116pub fn tuple(input: TokenStream) -> TokenStream {
117    let RepeatInput {
118        n, ident, block, ..
119    } = parse_macro_input!(input as RepeatInput);
120    let count = n.base10_parse::<usize>().expect("N must be an integer");
121
122    let blocks = expand(count, ident, block);
123    let output = quote! {
124        ( #(#blocks),* )
125    };
126
127    output.into()
128}
129
130fn expand(count: usize, ident: Ident, block: Box<Block>) -> Vec<proc_macro2::TokenStream> {
131    let mut blocks = Vec::new();
132    for i in 0..count {
133        blocks.push(quote! {
134            {
135                #[allow(unused)]
136                let #ident = #i;
137                #[allow(unused_braces)]
138                #block
139            }
140        });
141    }
142    blocks
143}