1use proc_macro2::Span;
2use syn::{
3 parse::{Error, Parse, ParseStream, Result},
4 token::Question,
5 ItemFn, Token,
6};
7
8pub struct AsyncItem(pub ItemFn);
9
10impl 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
23pub struct RecursionArgs {
24 pub send_bound: bool,
25 pub sync_bound: bool,
26}
27
28/// Custom keywords for parser
29mod kw {
30 syn::custom_keyword!(Send);
31 syn::custom_keyword!(Sync);
32}
33
34#[derive(Debug, PartialEq, Eq)]
35enum Arg {
36 NotSend,
37 Sync,
38}
39
40impl 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
49impl 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
62impl 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