1 use proc_macro2::Span;
2 use syn::{
3     parse::{discouraged::Speculative, Parse, ParseStream, Result},
4     Attribute, Error, ItemFn, ItemImpl, ItemStatic, ItemTrait,
5 };
6 
7 pub enum Item {
8     Trait(ItemTrait),
9     Impl(ItemImpl),
10     Fn(ItemFn),
11     Static(ItemStatic),
12 }
13 
14 macro_rules! fork {
15     ($fork:ident = $input:ident) => {{
16         $fork = $input.fork();
17         &$fork
18     }};
19 }
20 
21 impl Parse for Item {
parse(input: ParseStream) -> Result<Self>22     fn parse(input: ParseStream) -> Result<Self> {
23         let attrs = input.call(Attribute::parse_outer)?;
24         let mut fork;
25         let item = if let Ok(mut item) = fork!(fork = input).parse::<ItemImpl>() {
26             item.attrs = attrs;
27             Item::Impl(item)
28         } else if let Ok(mut item) = fork!(fork = input).parse::<ItemTrait>() {
29             item.attrs = attrs;
30             Item::Trait(item)
31         } else if let Ok(mut item) = fork!(fork = input).parse::<ItemFn>() {
32             item.attrs = attrs;
33             Item::Fn(item)
34         } else if let Ok(mut item) = fork!(fork = input).parse::<ItemStatic>() {
35             item.attrs = attrs;
36             Item::Static(item)
37         } else {
38             return Err(Error::new(Span::call_site(), "expected impl, trait or fn"));
39         };
40         input.advance_to(&fork);
41         Ok(item)
42     }
43 }
44