|
6 | 6 | use std::mem;
|
7 | 7 |
|
8 | 8 | use proc_macro::TokenStream;
|
9 |
| -use quote::quote; |
| 9 | +use proc_macro2::TokenStream as TokenStream2; |
| 10 | +use quote::{quote, ToTokens, TokenStreamExt}; |
10 | 11 | use syn::{
|
11 |
| - parse_macro_input, parse_quote, AttributeArgs, Error, ItemFn, Lit, Meta, NestedMeta, Path, |
12 |
| - Result, Visibility, |
| 12 | + parse::{Parse, ParseStream}, |
| 13 | + parse_macro_input, parse_quote, AttrStyle, Attribute, AttributeArgs, Error, Lit, Meta, |
| 14 | + NestedMeta, Path, Result, Signature, Visibility, |
13 | 15 | };
|
14 | 16 |
|
15 | 17 | #[derive(Default)]
|
@@ -90,6 +92,44 @@ fn interpret_job_arg(options: &mut JobOptions, arg: NestedMeta) -> Result<()> {
|
90 | 92 | Ok(())
|
91 | 93 | }
|
92 | 94 |
|
| 95 | +#[derive(Clone)] |
| 96 | +struct MaybeItemFn { |
| 97 | + attrs: Vec<Attribute>, |
| 98 | + vis: Visibility, |
| 99 | + sig: Signature, |
| 100 | + block: TokenStream2, |
| 101 | +} |
| 102 | + |
| 103 | +/// This parses a `TokenStream` into a `MaybeItemFn` |
| 104 | +/// (just like `ItemFn`, but skips parsing the body). |
| 105 | +impl Parse for MaybeItemFn { |
| 106 | + fn parse(input: ParseStream<'_>) -> syn::Result<Self> { |
| 107 | + let attrs = input.call(syn::Attribute::parse_outer)?; |
| 108 | + let vis: Visibility = input.parse()?; |
| 109 | + let sig: Signature = input.parse()?; |
| 110 | + let block: TokenStream2 = input.parse()?; |
| 111 | + Ok(Self { |
| 112 | + attrs, |
| 113 | + vis, |
| 114 | + sig, |
| 115 | + block, |
| 116 | + }) |
| 117 | + } |
| 118 | +} |
| 119 | + |
| 120 | +impl ToTokens for MaybeItemFn { |
| 121 | + fn to_tokens(&self, tokens: &mut TokenStream2) { |
| 122 | + tokens.append_all( |
| 123 | + self.attrs |
| 124 | + .iter() |
| 125 | + .filter(|attr| matches!(attr.style, AttrStyle::Outer)), |
| 126 | + ); |
| 127 | + self.vis.to_tokens(tokens); |
| 128 | + self.sig.to_tokens(tokens); |
| 129 | + self.block.to_tokens(tokens); |
| 130 | + } |
| 131 | +} |
| 132 | + |
93 | 133 | /// Marks a function as being a background job.
|
94 | 134 | ///
|
95 | 135 | /// The first argument to the function must have type `CurrentJob`.
|
@@ -181,7 +221,7 @@ fn interpret_job_arg(options: &mut JobOptions, arg: NestedMeta) -> Result<()> {
|
181 | 221 | #[proc_macro_attribute]
|
182 | 222 | pub fn job(attr: TokenStream, item: TokenStream) -> TokenStream {
|
183 | 223 | let args = parse_macro_input!(attr as AttributeArgs);
|
184 |
| - let mut inner_fn = parse_macro_input!(item as ItemFn); |
| 224 | + let mut inner_fn = parse_macro_input!(item as MaybeItemFn); |
185 | 225 |
|
186 | 226 | let mut options = JobOptions::default();
|
187 | 227 | let mut errors = Vec::new();
|
|
0 commit comments