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