use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use syn::{ItemFn, ReturnType, Type, Visibility};
pub fn task(attr: TokenStream, item: TokenStream) -> TokenStream {
let f: ItemFn = match syn::parse2(item.clone()) {
Ok(x) => x,
Err(e) => return e.to_compile_error(),
};
let mut args = Vec::new();
let mut fargs = f.sig.inputs.clone();
for arg in fargs.iter_mut() {
match arg {
syn::FnArg::Typed(t) => {
match t.pat.as_mut() {
syn::Pat::Ident(id) => {
id.mutability = None;
args.push((id.clone(), t.attrs.clone()));
}
_ => {}
}
}
_ => {}
}
}
let generics = &f.sig.generics;
let where_clause = &f.sig.generics.where_clause;
let unsafety = &f.sig.unsafety;
let visibility = &f.vis;
let task_outer_attrs = &f.attrs;
let mut full_args = Vec::new();
for (arg, cfgs) in args {
full_args.push(quote!(
#(#cfgs)*
#arg
));
}
let task_ident = f.sig.ident.clone();
let task_inner_ident = format_ident!("__{}_task", task_ident);
let mut fargs = f.sig.inputs.clone();
let mut task_inner_function = f.clone();
let task_inner_function_ident = format_ident!("__{}_task_inner_function", task_ident);
task_inner_function.sig.ident = task_inner_function_ident.clone();
task_inner_function.vis = Visibility::Inherited;
let task_inner_body = quote! {
#task_inner_function
#unsafety {
#task_inner_function_ident(#(#full_args,)*)
}
};
let executor = quote!(::uefi_async);
let pool_size = 1usize;
let task_inner_future_output = match &f.sig.output {
ReturnType::Default => quote! {-> impl ::core::future::Future<Output = ()>},
ReturnType::Type(arrow, maybe_never) if f.sig.asyncness.is_some() && matches!(**maybe_never, Type::Never(_)) => {
quote! {
#arrow impl ::core::future::Future<Output=#executor::Never>
}
},
ReturnType::Type(arrow, maybe_never) if matches!(**maybe_never, Type::Never(_)) => quote! {
#arrow #maybe_never
},
ReturnType::Type(arrow, typ) if f.sig.asyncness.is_some() => quote! {
#arrow impl ::core::future::Future<Output = #typ>
},
ReturnType::Type(arrow, typ) => quote! {
#arrow #typ
},
};
let task_inner = quote! {
#visibility fn #task_inner_ident #generics (#fargs)
#task_inner_future_output
#where_clause
{
#task_inner_body
}
};
let task_outer_body = quote! {
const POOL_SIZE: usize = #pool_size;
static POOL: #executor::TaskPoolLayout<
{#executor::task_pool_size::<_, _, _, POOL_SIZE>(#task_inner_ident)},
{#executor::task_pool_align::<_, _, _, POOL_SIZE>(#task_inner_ident)},
> = unsafe { ::core::mem::transmute(#executor::task_pool_new::<_, _, _, POOL_SIZE>(#task_inner_ident)) };
};
quote! {
#task_inner
#(#task_outer_attrs)*
#visibility #unsafety fn #task_ident #generics (#fargs) #where_clause{
#task_outer_body
}
}
}