#![allow(nonstandard_style, unused_imports)]
use ::core::{
ops::Not as _,
};
use ::proc_macro::{
TokenStream,
};
use ::proc_macro2::{
Span,
TokenStream as TokenStream2,
TokenTree as TT,
};
use ::quote::{
format_ident,
quote,
quote_spanned,
ToTokens,
};
use ::syn::{*,
parse::{Parse, Parser, ParseStream},
punctuated::Punctuated,
Result, };
#[proc_macro_attribute] pub
fn bare_future (
attrs: TokenStream,
input: TokenStream,
) -> TokenStream
{
bare_future_impl(attrs.into(), input.into())
.unwrap_or_else(|err| {
let mut errors =
err .into_iter()
.map(|err| Error::new(
err.span(),
format_args!("`#[async_fn::bare_future]`: {}", err),
))
;
let mut err = errors.next().unwrap();
errors.for_each(|cur| err.combine(cur));
err.to_compile_error()
})
.into()
}
fn bare_future_impl (
attrs: TokenStream2,
input: TokenStream2,
) -> Result<TokenStream2>
{
let _: parse::Nothing = parse2(attrs)?;
let mut fun: ImplItemFn = parse2(input)?;
let sig = &mut fun.sig;
let async_ = if let Some(it) = sig.asyncness.take() { it } else {
let span =
Option::or(
sig.unsafety.as_ref().map(|it| it.span),
sig.abi.as_ref().map(|it| it.extern_token.span),
)
.unwrap_or(sig.fn_token.span)
;
return Err(Error::new(span, "expected `async`"));
};
let mut stmts = match *fun.block.stmts {
| [
Stmt::Item(
Item::Macro(ItemMacro {
ref attrs,
ident: None,
ref mut mac,
semi_token: _,
}),
),
..
]
| [
Stmt::Expr(
Expr::Macro(ExprMacro {
ref attrs,
ref mut mac,
}),
Some(_),
),
..
]
| [
Stmt::Macro(StmtMacro {
ref attrs,
ref mut mac,
semi_token: _,
}),
..
]
if mac.path.is_ident("before_async")
|| (0 .. mac.path.segments.len()).all({
let expected_segments = ["async_fn", "before_async"];
let mac = &mac;
move |i| {
mac.path.segments[i].ident == expected_segments[i]
}
})
=> {
if let Some(attr) = attrs.first() {
return Err(Error::new_spanned(
attr,
"unexpected attribute(s)",
));
}
let mut stmts = vec![];
let () = mac.parse_body_with(|tts: ParseStream<'_>| Ok({
while tts.is_empty().not() {
stmts.push(tts.parse::<Stmt>()?);
}
}))?;
mac.tokens = quote!(@);
if mac.path.segments.len() == 1 {
stmts.push(parse_quote!(
use ::async_fn::__::before_async::*;
));
}
stmts
},
| _ => vec![],
};
stmts.push(Stmt::Expr(
Expr::Async(ExprAsync {
attrs: vec![],
async_token: async_,
capture: Some(token::Move { span: fun.sig.fn_token.span }),
block: Block {
brace_token: fun.block.brace_token,
stmts: ::core::mem::take(&mut fun.block.stmts),
},
}),
None)
);
fun.block.stmts = stmts;
Ok(fun.into_token_stream())
}