1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
//! Experimental language-level polyfills for Async Rust.
//!
//! # Examples
//!
//! ```
//! #[async_attributes::main]
//! async fn main() {
//! println!("Hello, world!");
//! }
//! ```
//!
//! # About
//!
//! Async Rust is a work in progress. The language has enabled us to do some
//! fantastic things, but not everything is figured out yet. This crate exists
//! to polyfill language-level support for async idioms before they can be part
//! of the language.
//!
//! A great example of this is `async fn main`, which we first introduced as
//! part of the [`runtime`](https://docs.rs/runtime/0.3.0-alpha.7/runtime/) crate.
//! Its premise is that if `async fn` is required for every `await` call, it
//! makes sense to apply that even to `fn main`. Unfortunately this would
//! require compiler support to enable, so we've provided an experimental
//! polyfill for it in the mean time.
#![forbid(unsafe_code, future_incompatible, rust_2018_idioms)]
#![deny(missing_debug_implementations, nonstandard_style)]
#![recursion_limit = "512"]
use proc_macro::TokenStream;
use quote::{quote, quote_spanned};
use syn::spanned::Spanned;
/// Enables an async main function.
///
/// # Examples
///
/// ```ignore
/// #[async_std::main]
/// async fn main() -> std::io::Result<()> {
/// Ok(())
/// }
/// ```
#[cfg(not(test))] // NOTE: exporting main breaks tests, we should file an issue.
#[proc_macro_attribute]
pub fn main(_attr: TokenStream, item: TokenStream) -> TokenStream {
let input = syn::parse_macro_input!(item as syn::ItemFn);
let ret = &input.sig.output;
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!("only the main function can be tagged with #[async_std::main]"),
});
}
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! {
#vis fn main() #ret {
#(#attrs)*
async fn main(#inputs) #ret {
#body
}
async_std::task::block_on(async {
main().await
})
}
};
result.into()
}
/// Enables an async test function.
///
/// # Examples
///
/// ```ignore
/// #[async_std::test]
/// async fn my_test() -> std::io::Result<()> {
/// assert_eq!(2 * 2, 4);
/// Ok(())
/// }
/// ```
#[proc_macro_attribute]
pub fn test(_attr: TokenStream, item: TokenStream) -> TokenStream {
let input = syn::parse_macro_input!(item as syn::ItemFn);
let ret = &input.sig.output;
let name = &input.sig.ident;
let body = &input.block;
let attrs = &input.attrs;
let vis = &input.vis;
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! {
#[::core::prelude::v1::test]
#(#attrs)*
#vis fn #name() #ret {
async_std::task::block_on(async { #body })
}
};
result.into()
}
/// Enables an async benchmark function.
///
/// # Examples
///
/// ```ignore
/// #![feature(test)]
/// extern crate test;
///
/// #[async_std::bench]
/// async fn bench_1(b: &mut test::Bencher) {
/// b.iter(|| {
/// println!("hello world");
/// })
/// }
/// ```
#[proc_macro_attribute]
pub fn bench(_attr: TokenStream, item: TokenStream) -> TokenStream {
let input = syn::parse_macro_input!(item as syn::ItemFn);
let ret = &input.sig.output;
let args = &input.sig.inputs;
let name = &input.sig.ident;
let body = &input.block;
let attrs = &input.attrs;
let vis = &input.vis;
if input.sig.asyncness.is_none() {
return TokenStream::from(quote_spanned! { input.span() =>
compile_error!("the async keyword is missing from the function declaration"),
});
}
if !args.is_empty() {
return TokenStream::from(quote_spanned! { args.span() =>
compile_error!("async benchmarks don't take any arguments"),
});
}
let result = quote! {
#[::core::prelude::v1::bench]
#(#attrs)*
#vis fn #name(b: &mut test::Bencher) #ret {
task::block_on(task::spawn(async {
#body
}))
}
};
result.into()
}