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