random_number_macro_impl/
lib.rs

1use proc_macro::TokenStream;
2use proc_macro_hack::proc_macro_hack;
3use quote::quote;
4use syn::{
5    parse::{Parse, ParseStream},
6    parse_macro_input, Expr, RangeLimits, Token,
7};
8
9struct RandomBuilder {
10    min:       Option<Box<Expr>>,
11    max:       Option<Box<Expr>>,
12    rng:       Option<Box<Expr>>,
13    exclusive: bool,
14    cmp:       bool,
15}
16
17impl Parse for RandomBuilder {
18    fn parse(input: ParseStream) -> Result<Self, syn::Error> {
19        if input.is_empty() {
20            Ok(RandomBuilder {
21                min:       None,
22                max:       None,
23                rng:       None,
24                exclusive: false,
25                cmp:       false,
26            })
27        } else {
28            let expr: Expr = input.parse()?;
29
30            if let Expr::Range(range) = expr {
31                let exclusive = match range.limits {
32                    RangeLimits::HalfOpen(_) => true,
33                    RangeLimits::Closed(_) => false,
34                };
35
36                let min = range.start;
37                let max = range.end;
38
39                if input.is_empty() {
40                    Ok(RandomBuilder {
41                        min,
42                        max,
43                        rng: None,
44                        exclusive,
45                        cmp: false,
46                    })
47                } else {
48                    input.parse::<Token!(,)>()?;
49
50                    let expr: Expr = input.parse()?;
51
52                    Ok(RandomBuilder {
53                        min,
54                        max,
55                        rng: Some(Box::new(expr)),
56                        exclusive,
57                        cmp: false,
58                    })
59                }
60            } else if input.lookahead1().peek(Token!(,)) {
61                input.parse::<Token!(,)>()?;
62
63                let expr2: Expr = input.parse()?;
64
65                if input.is_empty() {
66                    Ok(RandomBuilder {
67                        min:       Some(Box::from(expr)),
68                        max:       Some(Box::from(expr2)),
69                        rng:       None,
70                        exclusive: false,
71                        cmp:       true,
72                    })
73                } else {
74                    input.parse::<Token!(,)>()?;
75
76                    let expr3: Expr = input.parse()?;
77
78                    Ok(RandomBuilder {
79                        min:       Some(Box::from(expr)),
80                        max:       Some(Box::from(expr2)),
81                        rng:       Some(Box::new(expr3)),
82                        exclusive: false,
83                        cmp:       true,
84                    })
85                }
86            } else {
87                Ok(RandomBuilder {
88                    min:       None,
89                    max:       None,
90                    rng:       Some(Box::new(expr)),
91                    exclusive: false,
92                    cmp:       false,
93                })
94            }
95        }
96    }
97}
98
99#[proc_macro_hack]
100pub fn random(input: TokenStream) -> TokenStream {
101    let rb = parse_macro_input!(input as RandomBuilder);
102
103    let random = match rb.min.as_ref() {
104        Some(min) => match rb.max.as_ref() {
105            Some(max) => {
106                if rb.exclusive {
107                    match rb.rng.as_ref() {
108                        Some(rng) => {
109                            quote! {
110                                $crate::random_exclusively_with_rng(#min, #max, &mut #rng)
111                            }
112                        },
113                        None => {
114                            quote! {
115                                $crate::random_exclusively(#min, #max)
116                            }
117                        },
118                    }
119                } else if rb.cmp {
120                    match rb.rng.as_ref() {
121                        Some(rng) => {
122                            quote! {
123                                $crate::random_inclusively_cmp_with_rng(#min, #max, &mut #rng)
124                            }
125                        },
126                        None => {
127                            quote! {
128                                $crate::random_inclusively_cmp(#min, #max)
129                            }
130                        },
131                    }
132                } else {
133                    match rb.rng.as_ref() {
134                        Some(rng) => {
135                            quote! {
136                                $crate::random_inclusively_with_rng(#min, #max, &mut #rng)
137                            }
138                        },
139                        None => {
140                            quote! {
141                                $crate::random_inclusively(#min, #max)
142                            }
143                        },
144                    }
145                }
146            },
147            None => match rb.rng.as_ref() {
148                Some(rng) => {
149                    quote! {
150                        $crate::random_at_least_with_rng(#min, &mut #rng)
151                    }
152                },
153                None => {
154                    quote! {
155                        $crate::random_at_least(#min)
156                    }
157                },
158            },
159        },
160        None => match rb.max.as_ref() {
161            Some(max) => {
162                if rb.exclusive {
163                    match rb.rng.as_ref() {
164                        Some(rng) => {
165                            quote! {
166                                $crate::random_at_most_exclusively_with_rng(#max, &mut #rng)
167                            }
168                        },
169                        None => {
170                            quote! {
171                                $crate::random_at_most_exclusively(#max)
172                            }
173                        },
174                    }
175                } else {
176                    match rb.rng.as_ref() {
177                        Some(rng) => {
178                            quote! {
179                                $crate::random_at_most_with_rng(#max, &mut #rng)
180                            }
181                        },
182                        None => {
183                            quote! {
184                                $crate::random_at_most(#max)
185                            }
186                        },
187                    }
188                }
189            },
190            None => match rb.rng.as_ref() {
191                Some(rng) => {
192                    quote! {
193                        $crate::random_with_rng(&mut #rng)
194                    }
195                },
196                None => {
197                    quote! {
198                        $crate::random()
199                    }
200                },
201            },
202        },
203    };
204
205    random.into()
206}
207
208// TODO -----------------------------
209
210struct RandomFillBuilder {
211    out: Box<Expr>,
212    rb:  RandomBuilder,
213}
214
215impl Parse for RandomFillBuilder {
216    fn parse(input: ParseStream) -> Result<Self, syn::Error> {
217        let expr: Expr = input.parse()?;
218
219        let out = Box::from(expr);
220
221        if input.lookahead1().peek(Token!(,)) {
222            input.parse::<Token!(,)>()?;
223        }
224
225        let rb: RandomBuilder = input.parse()?;
226
227        Ok(RandomFillBuilder {
228            out,
229            rb,
230        })
231    }
232}
233
234#[proc_macro_hack::proc_macro_hack]
235pub fn random_fill(input: TokenStream) -> TokenStream {
236    let rfb = parse_macro_input!(input as RandomFillBuilder);
237
238    let out = rfb.out;
239
240    let rb = rfb.rb;
241
242    let random_fill = match rb.min.as_ref() {
243        Some(min) => match rb.max.as_ref() {
244            Some(max) => {
245                if rb.exclusive {
246                    match rb.rng.as_ref() {
247                        Some(rng) => {
248                            quote! {
249                                $crate::random_fill_exclusively_with_rng(#out.as_mut(), #min, #max, &mut #rng)
250                            }
251                        },
252                        None => {
253                            quote! {
254                                $crate::random_fill_exclusively(#out.as_mut(), #min, #max)
255                            }
256                        },
257                    }
258                } else if rb.cmp {
259                    match rb.rng.as_ref() {
260                        Some(rng) => {
261                            quote! {
262                                $crate::random_fill_inclusively_cmp_with_rng(#out.as_mut(), #min, #max, &mut #rng)
263                            }
264                        },
265                        None => {
266                            quote! {
267                                $crate::random_fill_inclusively_cmp(#out.as_mut(), #min, #max)
268                            }
269                        },
270                    }
271                } else {
272                    match rb.rng.as_ref() {
273                        Some(rng) => {
274                            quote! {
275                                $crate::random_fill_inclusively_with_rng(#out.as_mut(), #min, #max, &mut #rng)
276                            }
277                        },
278                        None => {
279                            quote! {
280                                $crate::random_fill_inclusively(#out.as_mut(), #min, #max)
281                            }
282                        },
283                    }
284                }
285            },
286            None => match rb.rng.as_ref() {
287                Some(rng) => {
288                    quote! {
289                        $crate::random_fill_at_least_with_rng(#out.as_mut(), #min, &mut #rng)
290                    }
291                },
292                None => {
293                    quote! {
294                        $crate::random_fill_at_least(#out.as_mut(), #min)
295                    }
296                },
297            },
298        },
299        None => match rb.max.as_ref() {
300            Some(max) => {
301                if rb.exclusive {
302                    match rb.rng.as_ref() {
303                        Some(rng) => {
304                            quote! {
305                                $crate::random_fill_at_most_exclusively_with_rng(#out.as_mut(), #max, &mut #rng)
306                            }
307                        },
308                        None => {
309                            quote! {
310                                $crate::random_fill_at_most_exclusively(#out.as_mut(), #max)
311                            }
312                        },
313                    }
314                } else {
315                    match rb.rng.as_ref() {
316                        Some(rng) => {
317                            quote! {
318                                $crate::random_fill_at_most_with_rng(#out.as_mut(), #max, &mut #rng)
319                            }
320                        },
321                        None => {
322                            quote! {
323                                $crate::random_fill_at_most(#out.as_mut(), #max)
324                            }
325                        },
326                    }
327                }
328            },
329            None => match rb.rng.as_ref() {
330                Some(rng) => {
331                    quote! {
332                        $crate::random_fill_with_rng(#out.as_mut(), &mut #rng)
333                    }
334                },
335                None => {
336                    quote! {
337                        $crate::random_fill(#out.as_mut())
338                    }
339                },
340            },
341        },
342    };
343
344    random_fill.into()
345}