1 | use proc_macro2::Span;
|
2 | use syn::{
|
3 | parse::{Error, Parse, ParseStream, Result},
|
4 | token::Question,
|
5 | ItemFn, Token,
|
6 | };
|
7 |
|
8 | pub struct AsyncItem(pub ItemFn);
|
9 |
|
10 | impl Parse for AsyncItem {
|
11 | fn parse(input: ParseStream) -> Result<Self> {
|
12 | let item: ItemFn = input.parse()?;
|
13 |
|
14 | // Check that this is an async function
|
15 | if item.sig.asyncness.is_none() {
|
16 | return Err(Error::new(Span::call_site(), message:"expected an async function" ));
|
17 | }
|
18 |
|
19 | Ok(AsyncItem(item))
|
20 | }
|
21 | }
|
22 |
|
23 | pub struct RecursionArgs {
|
24 | pub send_bound: bool,
|
25 | pub sync_bound: bool,
|
26 | }
|
27 |
|
28 | /// Custom keywords for parser
|
29 | mod kw {
|
30 | syn::custom_keyword!(Send);
|
31 | syn::custom_keyword!(Sync);
|
32 | }
|
33 |
|
34 | #[derive (Debug, PartialEq, Eq)]
|
35 | enum Arg {
|
36 | NotSend,
|
37 | Sync,
|
38 | }
|
39 |
|
40 | impl std::fmt::Display for Arg {
|
41 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
42 | match self {
|
43 | Self::NotSend => write!(f, "?Send" ),
|
44 | Self::Sync => write!(f, "Sync" ),
|
45 | }
|
46 | }
|
47 | }
|
48 |
|
49 | impl Parse for Arg {
|
50 | fn parse(input: ParseStream) -> Result<Self> {
|
51 | if input.peek(Token![?]) {
|
52 | input.parse::<Question>()?;
|
53 | input.parse::<kw::Send>()?;
|
54 | Ok(Arg::NotSend)
|
55 | } else {
|
56 | input.parse::<kw::Sync>()?;
|
57 | Ok(Arg::Sync)
|
58 | }
|
59 | }
|
60 | }
|
61 |
|
62 | impl Parse for RecursionArgs {
|
63 | fn parse(input: ParseStream) -> Result<Self> {
|
64 | let mut send_bound: bool = true;
|
65 | let mut sync_bound: bool = false;
|
66 |
|
67 | let args_parsed: Vec<Arg> =
|
68 | syn::punctuated::Punctuated::<Arg, syn::Token![,]>::parse_terminated(input)
|
69 | .map_err(|e| input.error(format!("failed to parse macro arguments: {e}" )))?
|
70 | .into_iter()
|
71 | .collect();
|
72 |
|
73 | // Avoid sloppy input
|
74 | if args_parsed.len() > 2 {
|
75 | return Err(Error::new(Span::call_site(), "received too many arguments" ));
|
76 | } else if args_parsed.len() == 2 && args_parsed[0] == args_parsed[1] {
|
77 | return Err(Error::new(
|
78 | Span::call_site(),
|
79 | format!("received duplicate argument: ` {}`" , args_parsed[0]),
|
80 | ));
|
81 | }
|
82 |
|
83 | for arg in args_parsed {
|
84 | match arg {
|
85 | Arg::NotSend => send_bound = false,
|
86 | Arg::Sync => sync_bound = true,
|
87 | }
|
88 | }
|
89 |
|
90 | Ok(Self {
|
91 | send_bound,
|
92 | sync_bound,
|
93 | })
|
94 | }
|
95 | }
|
96 | |