1use quote::ToTokens;
52use syn::Lit;
53use syn::spanned::Spanned;
54
55use crate::diagnostic::Diagnostics;
56use crate::meta::Arg;
57use crate::meta::Args;
58use crate::types::Input;
59
60mod attr;
61mod data;
62mod fields;
63mod variants;
64
65pub use attr::*;
66pub use data::*;
67pub use fields::*;
68pub use variants::*;
69
70pub trait FromInput: Sized {
77 fn from_input(input: &Input) -> crate::Result<Self>;
78}
79
80pub struct Extract<T: FromInput>(T);
85
86impl<T: FromInput> Extract<T> {
87 pub fn inner(self) -> T {
89 self.0
90 }
91}
92
93impl<T: FromInput> std::ops::Deref for Extract<T> {
94 type Target = T;
95
96 fn deref(&self) -> &Self::Target {
97 &self.0
98 }
99}
100
101impl<T: FromInput> std::ops::DerefMut for Extract<T> {
102 fn deref_mut(&mut self) -> &mut Self::Target {
103 &mut self.0
104 }
105}
106
107impl<T: FromInput> FromInput for Extract<T> {
108 fn from_input(input: &Input) -> crate::Result<Self> {
109 T::from_input(input).map(Extract)
110 }
111}
112
113impl FromInput for proc_macro2::Ident {
114 fn from_input(input: &Input) -> crate::Result<Self> {
115 Ok(input.ident().clone())
116 }
117}
118
119impl FromInput for syn::Generics {
120 fn from_input(input: &Input) -> crate::Result<Self> {
121 Ok(input.generics().clone())
122 }
123}
124
125impl FromInput for syn::Visibility {
126 fn from_input(input: &Input) -> crate::Result<Self> {
127 Ok(input.vis().clone())
128 }
129}
130
131pub trait FromArg: Sized {
138 fn from_arg(arg: &Arg) -> crate::Result<Self>;
139}
140
141impl FromArg for bool {
142 fn from_arg(arg: &Arg) -> crate::Result<Self> {
143 match arg {
144 Arg::Flag(_) => Ok(true),
145 _ => Err(Diagnostics::error(arg.span(), "expected flag for bool")),
146 }
147 }
148}
149
150impl FromArg for String {
151 fn from_arg(arg: &Arg) -> crate::Result<Self> {
152 match arg.as_expr_lit() {
153 Some(Lit::Str(s)) => Ok(s.value()),
154 _ => Err(Diagnostics::error(arg.span(), "expected string literal")),
155 }
156 }
157}
158
159macro_rules! impl_from_arg_int {
160 ($($t:ty),*) => {
161 $(
162 impl FromArg for $t {
163 fn from_arg(arg: &Arg) -> crate::Result<Self> {
164 match arg.as_expr_lit() {
165 Some(Lit::Int(i)) => i.base10_parse::<$t>().map_err(|e| Diagnostics::error(i.span(), e.to_string())),
166 _ => Err(Diagnostics::error(arg.span(), concat!("expected integer literal for ", stringify!($t)))),
167 }
168 }
169 }
170 )*
171 };
172}
173
174impl_from_arg_int!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128);
175
176macro_rules! impl_from_arg_float {
177 ($($t:ty),*) => {
178 $(
179 impl FromArg for $t {
180 fn from_arg(arg: &Arg) -> crate::Result<Self> {
181 match arg.as_expr_lit() {
182 Some(Lit::Float(f)) => f.base10_parse::<$t>().map_err(|e| Diagnostics::error(f.span(), e.to_string())),
183 _ => Err(Diagnostics::error(arg.span(), concat!("expected float literal for ", stringify!($t)))),
184 }
185 }
186 }
187 )*
188 };
189}
190
191impl_from_arg_float!(f32, f64);
192
193impl FromArg for char {
194 fn from_arg(arg: &Arg) -> crate::Result<Self> {
195 match arg.as_expr_lit() {
196 Some(Lit::Char(c)) => Ok(c.value()),
197 _ => Err(Diagnostics::error(arg.span(), "expected char literal")),
198 }
199 }
200}
201
202impl FromArg for syn::Ident {
203 fn from_arg(arg: &Arg) -> crate::Result<Self> {
204 match arg {
205 Arg::Flag(i) => Ok(i.clone()),
206 _ => Err(Diagnostics::error(arg.span(), "expected identifier")),
207 }
208 }
209}
210
211impl FromArg for syn::Path {
212 fn from_arg(arg: &Arg) -> crate::Result<Self> {
213 match arg {
214 Arg::Flag(i) => Ok(syn::Path::from(i.clone())),
215 _ => Err(Diagnostics::error(
216 arg.span(),
217 "expected identifier for path",
218 )),
219 }
220 }
221}
222
223impl FromArg for syn::Expr {
224 fn from_arg(arg: &Arg) -> crate::Result<Self> {
225 match arg {
226 Arg::Expr(_, expr) => Ok(expr.clone()),
227 _ => Err(Diagnostics::error(arg.span(), "expected expression")),
228 }
229 }
230}
231
232impl FromArg for syn::LitStr {
233 fn from_arg(arg: &Arg) -> crate::Result<Self> {
234 match arg.as_expr_lit() {
235 Some(Lit::Str(s)) => Ok(s.clone()),
236 _ => Err(Diagnostics::error(arg.span(), "expected string literal")),
237 }
238 }
239}
240
241impl FromArg for syn::LitInt {
242 fn from_arg(arg: &Arg) -> crate::Result<Self> {
243 match arg.as_expr_lit() {
244 Some(Lit::Int(i)) => Ok(i.clone()),
245 _ => Err(Diagnostics::error(arg.span(), "expected integer literal")),
246 }
247 }
248}
249
250impl<T: FromArg> FromArg for Option<T> {
251 fn from_arg(arg: &Arg) -> crate::Result<Self> {
252 T::from_arg(arg).map(Some)
253 }
254}
255
256impl<T: FromArg> FromArg for Vec<T> {
257 fn from_arg(arg: &Arg) -> crate::Result<Self> {
258 match arg {
259 Arg::List(_, args) => args.iter().map(T::from_arg).collect(),
260 _ => Err(Diagnostics::error(arg.span(), "expected list argument")),
261 }
262 }
263}
264
265impl FromArg for Args {
266 fn from_arg(arg: &Arg) -> crate::Result<Self> {
267 match arg {
268 Arg::List(_, args) => syn::parse2(args.to_token_stream()).map_err(Diagnostics::from),
269 _ => Err(Diagnostics::error(arg.span(), "expected list argument")),
270 }
271 }
272}
273
274#[cfg(test)]
275mod tests {
276 use super::*;
277
278 mod bool_impl {
279 use super::*;
280
281 #[test]
282 fn from_flag() {
283 let arg: Arg = syn::parse_str("skip").unwrap();
284 assert_eq!(bool::from_arg(&arg).unwrap(), true);
285 }
286
287 #[test]
288 fn from_expr_is_err() {
289 let arg: Arg = syn::parse_str("skip = true").unwrap();
290 assert!(bool::from_arg(&arg).is_err());
291 }
292 }
293
294 mod string_impl {
295 use super::*;
296
297 #[test]
298 fn from_expr_string_lit() {
299 let arg: Arg = syn::parse_str("rename = \"foo\"").unwrap();
300 assert_eq!(String::from_arg(&arg).unwrap(), "foo");
301 }
302
303 #[test]
304 fn from_lit_string() {
305 let arg: Arg = syn::parse_str("\"bar\"").unwrap();
306 assert_eq!(String::from_arg(&arg).unwrap(), "bar");
307 }
308
309 #[test]
310 fn from_flag_is_err() {
311 let arg: Arg = syn::parse_str("skip").unwrap();
312 assert!(String::from_arg(&arg).is_err());
313 }
314 }
315
316 mod int_impl {
317 use super::*;
318
319 #[test]
320 fn i64_from_lit() {
321 let arg: Arg = syn::parse_str("42").unwrap();
322 assert_eq!(i64::from_arg(&arg).unwrap(), 42);
323 }
324
325 #[test]
326 fn i64_from_expr() {
327 let arg: Arg = syn::parse_str("count = 7").unwrap();
328 assert_eq!(i64::from_arg(&arg).unwrap(), 7);
329 }
330
331 #[test]
332 fn i64_from_flag_is_err() {
333 let arg: Arg = syn::parse_str("skip").unwrap();
334 assert!(i64::from_arg(&arg).is_err());
335 }
336
337 #[test]
338 fn u32_from_lit() {
339 let arg: Arg = syn::parse_str("100").unwrap();
340 assert_eq!(u32::from_arg(&arg).unwrap(), 100u32);
341 }
342 }
343
344 mod char_impl {
345 use super::*;
346
347 #[test]
348 fn from_lit() {
349 let arg: Arg = syn::parse_str("'x'").unwrap();
350 assert_eq!(char::from_arg(&arg).unwrap(), 'x');
351 }
352
353 #[test]
354 fn from_flag_is_err() {
355 let arg: Arg = syn::parse_str("skip").unwrap();
356 assert!(char::from_arg(&arg).is_err());
357 }
358 }
359
360 mod ident_impl {
361 use super::*;
362
363 #[test]
364 fn from_flag() {
365 let arg: Arg = syn::parse_str("my_ident").unwrap();
366 let ident = syn::Ident::from_arg(&arg).unwrap();
367 assert_eq!(ident.to_string(), "my_ident");
368 }
369
370 #[test]
371 fn from_expr_is_err() {
372 let arg: Arg = syn::parse_str("x = 1").unwrap();
373 assert!(syn::Ident::from_arg(&arg).is_err());
374 }
375 }
376
377 mod option_impl {
378 use super::*;
379
380 #[test]
381 fn some_from_expr() {
382 let arg: Arg = syn::parse_str("rename = \"foo\"").unwrap();
383 assert_eq!(
384 Option::<String>::from_arg(&arg).unwrap(),
385 Some("foo".to_string())
386 );
387 }
388
389 #[test]
390 fn propagates_err() {
391 let arg: Arg = syn::parse_str("skip").unwrap();
392 assert!(Option::<String>::from_arg(&arg).is_err());
393 }
394 }
395
396 mod vec_impl {
397 use super::*;
398
399 #[test]
400 fn from_list() {
401 let arg: Arg = syn::parse_str("tags(\"a\", \"b\", \"c\")").unwrap();
402 let v = Vec::<String>::from_arg(&arg).unwrap();
403 assert_eq!(v, vec!["a", "b", "c"]);
404 }
405
406 #[test]
407 fn from_flag_is_err() {
408 let arg: Arg = syn::parse_str("skip").unwrap();
409 assert!(Vec::<String>::from_arg(&arg).is_err());
410 }
411 }
412
413 mod args_impl {
414 use super::*;
415
416 #[test]
417 fn from_list() {
418 let arg: Arg = syn::parse_str("inner(a = 1, b = 2)").unwrap();
419 let args = Args::from_arg(&arg).unwrap();
420 assert!(args.has("a"));
421 assert!(args.has("b"));
422 }
423
424 #[test]
425 fn from_flag_is_err() {
426 let arg: Arg = syn::parse_str("skip").unwrap();
427 assert!(Args::from_arg(&arg).is_err());
428 }
429 }
430}