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