1use proc_macro2::{Ident, TokenStream};
17use quote::ToTokens;
18use syn::ext::IdentExt;
19use syn::parse::{Parse, ParseBuffer, Result};
20use syn::punctuated::Punctuated;
21use syn::{Lit, Path};
22
23use crate::{ArgValue, Error};
24
25pub struct MetaArgList {
29 pub list: Punctuated<MetaArg, Token![,]>,
31}
32
33impl Parse for MetaArgList {
34 fn parse(input: &ParseBuffer) -> Result<Self> {
35 let content;
36 parenthesized!(content in input);
37 let list = Punctuated::parse_terminated(&content)?;
38 Ok(MetaArgList { list })
39 }
40}
41
42impl ToTokens for MetaArgList {
43 fn to_tokens(&self, tokens: &mut TokenStream) { (quote! { ( list ) }).to_tokens(tokens); }
44}
45
46pub enum MetaArg {
50 Literal(Lit),
52
53 Path(Path),
55
56 NameValue(MetaArgNameValue),
59}
60
61impl Parse for MetaArg {
62 fn parse(input: &ParseBuffer) -> Result<Self> {
63 if input.peek2(Token![=]) {
64 input.parse().map(MetaArg::NameValue)
65 } else if input.peek(Ident::peek_any) ||
66 input.peek(Token![::]) && input.peek3(Ident::peek_any)
67 {
68 input.parse().map(MetaArg::Path)
69 } else {
70 input.parse().map(MetaArg::Literal)
71 }
72 }
73}
74
75impl ToTokens for MetaArg {
76 fn to_tokens(&self, tokens: &mut TokenStream) {
77 match self {
78 MetaArg::Literal(lit) => lit.to_tokens(tokens),
79 MetaArg::Path(path) => path.to_tokens(tokens),
80 MetaArg::NameValue(meta) => meta.to_tokens(tokens),
81 }
82 }
83}
84
85pub struct MetaArgNameValue {
90 pub name: Ident,
92 pub eq_token: Token![=],
94 pub value: ArgValue,
96}
97
98impl Parse for MetaArgNameValue {
99 fn parse(input: &ParseBuffer) -> Result<Self> {
100 let path: Path = input.parse()?;
101 Ok(MetaArgNameValue {
102 name: path.get_ident().ok_or(Error::ArgNameMustBeIdent)?.clone(),
103 eq_token: input.parse()?,
104 value: input.parse()?,
105 })
106 }
107}
108
109impl ToTokens for MetaArgNameValue {
110 fn to_tokens(&self, tokens: &mut TokenStream) {
111 self.name.to_tokens(tokens);
112 self.eq_token.to_tokens(tokens);
113 self.value.to_tokens(tokens);
114 }
115}
116
117impl Parse for ArgValue {
118 fn parse(input: &ParseBuffer) -> Result<Self> {
119 if input.peek(Lit) {
120 input.parse().map(ArgValue::Literal)
121 } else {
122 input
123 .parse()
124 .map(ArgValue::Type)
125 .or_else(|_| input.parse().map(ArgValue::Expr))
126 }
127 }
128}
129
130impl ToTokens for ArgValue {
131 fn to_tokens(&self, tokens: &mut TokenStream) {
132 match self {
133 ArgValue::Literal(lit) => lit.to_tokens(tokens),
134 ArgValue::Type(ty) => ty.to_tokens(tokens),
135 ArgValue::Expr(expr) => expr.to_tokens(tokens),
136 ArgValue::None => quote! { ! }.to_tokens(tokens),
137 }
138 }
139}