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}