1use proc_macro2::{Ident, TokenStream};
8use quote::quote;
9use syn::meta::ParseNestedMeta;
10use syn::parse::Parse;
11use syn::punctuated::Punctuated;
12use syn::{Attribute, Meta, MetaList, Path, Result, Token, bracketed};
13
14pub(crate) mod class;
15pub(crate) mod function;
16pub(crate) mod krate;
17pub(crate) mod name;
18pub(crate) mod property;
19pub(crate) mod trace;
20pub(crate) mod value;
21
22#[derive(Copy, Clone, Debug)]
23pub(crate) struct Optional<T>(pub(crate) Option<T>);
24
25impl<T> Default for Optional<T> {
26 fn default() -> Optional<T> {
27 Optional(None)
28 }
29}
30
31pub(crate) enum ArgumentError<'a> {
32 Kind(&'a str),
33 Full(&'a str),
34 None,
35}
36
37impl ArgumentError<'_> {
38 fn error(self, meta: &ParseNestedMeta, key: &str) -> Result<()> {
39 match self {
40 ArgumentError::Kind(kind) => Err(meta.error(format!("{kind} cannot have multiple `{key}` attributes."))),
41 ArgumentError::Full(error) => Err(meta.error(error)),
42 ArgumentError::None => Ok(()),
43 }
44 }
45}
46
47impl<'a> From<&'a str> for ArgumentError<'a> {
48 fn from(kind: &'a str) -> ArgumentError<'a> {
49 ArgumentError::Kind(kind)
50 }
51}
52
53impl<'a> From<Option<&'a str>> for ArgumentError<'a> {
54 fn from(kind: Option<&'a str>) -> ArgumentError<'a> {
55 match kind {
56 Some(kind) => ArgumentError::from(kind),
57 None => ArgumentError::None,
58 }
59 }
60}
61
62pub(crate) trait ParseArgumentWith {
63 type With;
64
65 fn handle_argument_with<'a>(
66 &mut self, meta: &ParseNestedMeta, with: Self::With, key: &str, error: impl Into<ArgumentError<'a>>,
67 ) -> Result<bool>;
68
69 fn parse_argument_with<'a>(
70 &mut self, meta: &ParseNestedMeta, with: Self::With, key: &str, error: impl Into<ArgumentError<'a>>,
71 ) -> Result<bool> {
72 if meta.path.is_ident(key) {
73 return self.handle_argument_with(meta, with, key, error);
74 }
75 Ok(false)
76 }
77}
78
79pub(crate) trait ParseArgument: ParseArgumentWith {
80 fn handle_argument<'a>(
81 &mut self, meta: &ParseNestedMeta, key: &str, error: impl Into<ArgumentError<'a>>,
82 ) -> Result<bool>;
83
84 fn parse_argument<'a>(
85 &mut self, meta: &ParseNestedMeta, key: &str, error: impl Into<ArgumentError<'a>>,
86 ) -> Result<bool> {
87 if meta.path.is_ident(key) {
88 return self.handle_argument(meta, key, error);
89 }
90 Ok(false)
91 }
92}
93
94impl ParseArgumentWith for bool {
95 type With = bool;
96
97 fn handle_argument_with<'a>(
98 &mut self, meta: &ParseNestedMeta, with: bool, key: &str, error: impl Into<ArgumentError<'a>>,
99 ) -> Result<bool> {
100 if *self {
101 error.into().error(meta, key)?;
102 return Ok(false);
103 }
104 *self = with;
105 Ok(true)
106 }
107}
108
109impl ParseArgument for bool {
110 fn handle_argument<'a>(
111 &mut self, meta: &ParseNestedMeta, key: &str, error: impl Into<ArgumentError<'a>>,
112 ) -> Result<bool> {
113 self.handle_argument_with(meta, true, key, error)
114 }
115}
116
117impl<T> ParseArgumentWith for Option<T> {
118 type With = T;
119
120 fn handle_argument_with<'a>(
121 &mut self, meta: &ParseNestedMeta, with: T, key: &str, error: impl Into<ArgumentError<'a>>,
122 ) -> Result<bool> {
123 if self.is_some() {
124 error.into().error(meta, key)?;
125 return Ok(false);
126 }
127 *self = Some(with);
128 Ok(true)
129 }
130}
131
132impl<T: Parse> ParseArgument for Option<T> {
133 fn handle_argument<'a>(
134 &mut self, meta: &ParseNestedMeta, key: &str, error: impl Into<ArgumentError<'a>>,
135 ) -> Result<bool> {
136 let _: Token![=] = meta.input.parse()?;
137 let argument = meta.input.parse()?;
138 self.handle_argument_with(meta, argument, key, error)
139 }
140}
141
142impl<T> ParseArgumentWith for Optional<T> {
143 type With = T;
144
145 fn handle_argument_with<'a>(
146 &mut self, meta: &ParseNestedMeta, with: T, key: &str, error: impl Into<ArgumentError<'a>>,
147 ) -> Result<bool> {
148 if self.0.is_some() {
149 error.into().error(meta, key)?;
150 return Ok(false);
151 }
152 self.0 = Some(with);
153 Ok(true)
154 }
155}
156
157impl<T: Parse + Default> ParseArgument for Optional<T> {
158 fn handle_argument<'a>(
159 &mut self, meta: &ParseNestedMeta, key: &str, error: impl Into<ArgumentError<'a>>,
160 ) -> Result<bool> {
161 let eq: Option<Token![=]> = meta.input.parse()?;
162 let argument = eq.map(|_| meta.input.parse()).transpose()?.unwrap_or_default();
163 self.handle_argument_with(meta, argument, key, error)
164 }
165}
166
167impl<T> ParseArgumentWith for Vec<T> {
168 type With = Punctuated<T, Token![,]>;
169
170 fn handle_argument_with<'a>(
171 &mut self, meta: &ParseNestedMeta, with: Punctuated<T, Token![,]>, key: &str,
172 error: impl Into<ArgumentError<'a>>,
173 ) -> Result<bool> {
174 if !self.is_empty() {
175 error.into().error(meta, key)?;
176 return Ok(false);
177 }
178 self.extend(with);
179 Ok(true)
180 }
181}
182
183impl<T: Parse> ParseArgument for Vec<T> {
184 fn handle_argument<'a>(
185 &mut self, meta: &ParseNestedMeta, key: &str, error: impl Into<ArgumentError<'a>>,
186 ) -> Result<bool> {
187 let _: Token![=] = meta.input.parse()?;
188 let inner;
189 bracketed!(inner in meta.input);
190 let value = inner.parse_terminated(T::parse, Token![,])?;
191 self.handle_argument_with(meta, value, key, error)
192 }
193}
194
195pub(crate) trait ParseAttribute: Default {
196 type Parent<'a>: Copy;
197
198 fn from_parent(_parent: Self::Parent<'_>) -> Self {
199 Self::default()
200 }
201
202 fn merge(&mut self, _parent: Self::Parent<'_>) {}
203
204 fn parse(&mut self, meta: &ParseNestedMeta) -> Result<bool>;
205
206 fn from_attributes<I: ?Sized>(path: &I, attributes: &mut Vec<Attribute>, parent: Self::Parent<'_>) -> Result<Self>
207 where
208 Ident: PartialEq<I>,
209 {
210 let mut data = Self::from_parent(parent);
211
212 attributes.retain_mut(|attribute| {
213 if !attribute.path().is_ident(path) {
214 return true;
215 }
216
217 let mut raw: Vec<(Path, TokenStream)> = Vec::new();
218 let mut parsed = Vec::new();
219
220 let _ = attribute.parse_nested_meta(|meta| {
221 raw.push((meta.path.clone(), meta.input.fork().parse()?));
222 if data.parse(&meta)? {
223 parsed.push(raw.len());
224 }
225
226 Ok(())
227 });
228
229 if parsed.len() == raw.len() {
230 return false;
231 }
232
233 if let Meta::List(MetaList { tokens, .. }) = &mut attribute.meta {
234 let raw = raw
235 .into_iter()
236 .enumerate()
237 .filter_map(|(i, (k, v))| (!parsed.contains(&i)).then(|| quote!(#k #v)));
238 *tokens = quote!(#(#raw),*);
239 }
240
241 true
242 });
243
244 data.merge(parent);
245 Ok(data)
246 }
247}