ctrlgen_impl/
parse_args.rs

1use syn::bracketed;
2use syn::parse::Parse;
3use syn::punctuated::Punctuated;
4use syn::Attribute;
5use syn::Token;
6
7use crate::Params;
8use crate::Proxy;
9
10impl Parse for Proxy {
11    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
12        // if input.peek(Token![struct]) {
13        //     let _kwd: Token![struct] = input.parse()?;
14        //     Ok(Self::Struct(input.parse()?))
15        // } else
16        if input.peek(Token![trait]) {
17            let kwd: Token![trait] = input.parse()?;
18            Ok(Self::Trait(kwd, input.parse()?))
19        // } else if input.peek(Token![impl]) {
20        //     let _kwd: Token![impl] = input.parse()?;
21        //     let generics = input.parse()?;
22        //     let path = input.parse()?;
23        //     Ok(Self::Impl(ProxyImpl { generics, path }))
24        } else {
25            Err(syn::Error::new(
26                input.span(),
27                "Expected `struct`, `trait` or `impl`",
28            ))
29        }
30    }
31}
32
33impl Parse for Params {
34    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
35        let mut enum_attr = Attribute::parse_outer(input)?;
36
37        let visibility: syn::Visibility = input
38            .fork()
39            .parse::<syn::Visibility>()
40            .ok()
41            .and_then(|_| input.parse().ok())
42            .unwrap_or(syn::Visibility::Inherited);
43
44        let _: Token![enum] = input.parse()?;
45
46        let enum_name: syn::Ident = input.parse()?;
47        let mut returnval = None;
48        let mut proxies = Vec::new();
49        let mut context = None;
50
51        while input.peek(Token![,]) {
52            let _comma: Token![,] = input.parse()?;
53            if input.is_empty() {
54                // Allow trailing comma
55                break;
56            }
57            if input.peek(Token![trait]) {
58                proxies.extend(input.parse());
59                continue;
60            }
61
62            let arg: syn::Ident = input.parse()?;
63            match arg.to_string().as_str() {
64                "enum_attr" => {
65                    let content;
66                    enum_attr.push(Attribute {
67                        pound_token: Token![#](input.span()),
68                        style: syn::AttrStyle::Outer,
69                        bracket_token: bracketed!(content in input),
70                        path: content.call(syn::Path::parse_mod_style)?,
71                        tokens: content.parse()?,
72                    })
73                }
74                "returnval" => {
75                    if returnval.is_some() {
76                        return Err(syn::Error::new_spanned(
77                            arg,
78                            "Argument `returnval` specified twice",
79                        ));
80                    }
81                    let _eq: Token![=] = input.parse()?;
82                    returnval = Some(input.parse()?)
83                }
84                "proxy" => {
85                    let contents;
86                    if input.peek(syn::token::Paren) {
87                        let _paren = syn::parenthesized!(contents in input);
88                    } else {
89                        let _paren = syn::braced!(contents in input);
90                    }
91                    let punct: Punctuated<Proxy, Token![;]> =
92                        Punctuated::parse_terminated(&contents)?;
93                    proxies.extend(punct)
94                }
95                "context" => {
96                    if context.is_some() {
97                        return Err(syn::Error::new_spanned(
98                            arg,
99                            "Argument `context` specified twice",
100                        ));
101                    }
102                    let contents;
103                    let _paren = syn::parenthesized!(contents in input);
104
105                    let ident = contents.parse()?;
106                    let _colon: Token![:] = contents.parse()?;
107                    let ty = contents.parse()?;
108
109                    context = Some((ident, ty))
110                }
111                _ => {
112                    return Err(syn::Error::new(
113                        arg.span(),
114                        format!("Unknown argument `{arg}` to ctrlgen"),
115                    ))
116                }
117            };
118        }
119
120        Ok(Self {
121            visibility,
122            enum_name,
123            returnval,
124            proxies,
125            enum_attr,
126            context,
127        })
128    }
129}