-
-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Procedural macro for boilerplate #12
Comments
macro does not mean you don't need to import. proc macro only transforms AST. I guess you are saying that the macro is importing it for you. |
What I meant is that with the proc macro you can remove the |
After a quick glance of
Maybe it's easier to just fork-and-edit |
Async-std's macro for this seems dead simple, maybe it could be copied over? https://github.com/async-rs/async-attributes/blob/master/src/lib.rs |
Hello I just wrote a macro for this, its a bit different but its pretty much the same as what you would have in async-ffi. For anyone that wants it, here. I'll make a pr for this tmrw #[proc_macro_attribute]
pub fn async_fn(_attr: TokenStream, item: TokenStream) -> TokenStream {
use syn::ReturnType;
let input = syn::parse_macro_input!(item as syn::ItemFn);
let ret_raw = &input.sig.output;
let ret = match ret_raw {
ReturnType::Default => quote!(-> BoxFuture<'static, ()>),
ReturnType::Type(_, t) => {
let ty = *t.clone();
quote!(-> BoxFuture<'static, #ty>)
}
};
let inputs = &input.sig.inputs;
let name = &input.sig.ident;
let body = &input.block;
let attrs = &input.attrs;
let vis = &input.vis;
if name == "main" {
return TokenStream::from(quote_spanned! { name.span() =>
compile_error!("the main function cannot be tagged with #[async_fn]"),
});
}
if input.sig.asyncness.is_none() {
return TokenStream::from(quote_spanned! { input.span() =>
compile_error!("the async keyword is missing from the function declaration"),
});
}
let result = quote! {
#(#attrs)*
#vis fn #name(#inputs) #ret {
use std::future::IntoFuture;
let future = async move {
#body
};
BoxFuture::new(future.into_future())
}
};
result.into()
} |
That is simple because Parameters which may include lifetimes and/or have #[somemacro]
async fn foo(foo: Foo<'_>, bar: &Bar) -> Baz { ... } should become, fn foo<'a>(foo: Foo<'_>, bar: &'a Bar) -> impl Future<Output = Baz> + 'a { // <- All lifetimes, including elided ones.
async move {
let foo = foo; // <- `async fn`'s behavior is to keep unused parameters in the returned Future.
let bar = bar;
...
}
} Technically the drop-order stuff doesn't really matter. Unlike
Thanks, but I think it's better to do it myself, since proc-macros should be in a new crate. |
Ah ok |
The proc-macro helper is available in 0.4.1 now. See docs. |
Looks great thanks! |
Awesome! Great work :) |
It'd be pretty nice to have a procedural macro that adds the boilerplate automatically. Instead of:
It would look like:
Notes:
async_ffi
.async
goes beforeextern "C"
according to Rust's syntax. Adding it afterextern "C"
shouldn't work.FfiFuture<>
to the return typeasync move { }.into_ffi()
automaticallyFutureExt
because the macro calls it withFutureExt::into_ffi(async move {})
instead.LocalFfiFuture
or such variants. For example#[async_ffi(local)]
.Having implemented a couple of them I would say it'd be relatively simple. I don't currently have time to implement it myself, but I'm opening this issue in case there are any takers, and to start some discussion and ideas.
The text was updated successfully, but these errors were encountered: