summaryrefslogtreecommitdiffstats
path: root/tokio-macros
diff options
context:
space:
mode:
authorCarl Lerche <me@carllerche.com>2020-01-07 14:29:44 -0800
committerGitHub <noreply@github.com>2020-01-07 14:29:44 -0800
commit7fb54315f1e1b12fc94558ada85ed521aea3ae77 (patch)
tree465a3a0942089483642c3b7195cb4db777b8a198 /tokio-macros
parentffd4025fce3c2fc44c0a91e38823a21d76bb6711 (diff)
macros: fix breaking changes (#2069)
Brings back old macro implementations and updates the version of tokio-macros that tokio depends on. Prepares a new release.
Diffstat (limited to 'tokio-macros')
-rw-r--r--tokio-macros/CHANGELOG.md7
-rw-r--r--tokio-macros/Cargo.toml4
-rw-r--r--tokio-macros/src/lib.rs238
3 files changed, 239 insertions, 10 deletions
diff --git a/tokio-macros/CHANGELOG.md b/tokio-macros/CHANGELOG.md
index 95271897..d6e3afa7 100644
--- a/tokio-macros/CHANGELOG.md
+++ b/tokio-macros/CHANGELOG.md
@@ -1,4 +1,11 @@
+# 0.2.3 (January 7, 2019)
+
+### Fixed
+- Revert breaking change.
+
# 0.2.2 (January 7, 2019)
+
+### Added
- General refactoring and inclusion of additional runtime options (#2022 and #2038)
# 0.2.1 (December 18, 2019)
diff --git a/tokio-macros/Cargo.toml b/tokio-macros/Cargo.toml
index 8d74e9d5..d69d48d6 100644
--- a/tokio-macros/Cargo.toml
+++ b/tokio-macros/Cargo.toml
@@ -7,13 +7,13 @@ name = "tokio-macros"
# - Cargo.toml
# - Update CHANGELOG.md.
# - Create "v0.1.x" git tag.
-version = "0.2.2"
+version = "0.2.3"
edition = "2018"
authors = ["Tokio Contributors <team@tokio.rs>"]
license = "MIT"
repository = "https://github.com/tokio-rs/tokio"
homepage = "https://tokio.rs"
-documentation = "https://docs.rs/tokio-macros/0.2.2/tokio_macros"
+documentation = "https://docs.rs/tokio-macros/0.2.3/tokio_macros"
description = """
Tokio's proc macros.
"""
diff --git a/tokio-macros/src/lib.rs b/tokio-macros/src/lib.rs
index ce38fabe..6eb57ea0 100644
--- a/tokio-macros/src/lib.rs
+++ b/tokio-macros/src/lib.rs
@@ -1,4 +1,4 @@
-#![doc(html_root_url = "https://docs.rs/tokio-macros/0.2.2")]
+#![doc(html_root_url = "https://docs.rs/tokio-macros/0.2.3")]
#![allow(clippy::needless_doctest_main)]
#![warn(
missing_debug_implementations,
@@ -215,7 +215,43 @@ fn parse_knobs(
#[proc_macro_attribute]
#[cfg(not(test))] // Work around for rust-lang/rust#62127
pub fn main_threaded(args: TokenStream, item: TokenStream) -> TokenStream {
- main(args, item, true)
+ main_impl(args, item, true)
+}
+
+/// Marks async function to be executed by selected runtime.
+///
+/// ## Options:
+///
+/// - `basic_scheduler` - All tasks are executed on the current thread.
+/// - `threaded_scheduler` - Uses the multi-threaded scheduler. Used by default.
+///
+/// ## Function arguments:
+///
+/// Arguments are allowed for any functions aside from `main` which is special
+///
+/// ## Usage
+///
+/// ### Using default
+///
+/// ```rust
+/// #[tokio::main]
+/// async fn main() {
+/// println!("Hello world");
+/// }
+/// ```
+///
+/// ### Select runtime
+///
+/// ```rust
+/// #[tokio::main(basic_scheduler)]
+/// async fn main() {
+/// println!("Hello world");
+/// }
+/// ```
+#[proc_macro_attribute]
+#[cfg(not(test))] // Work around for rust-lang/rust#62127
+pub fn main(args: TokenStream, item: TokenStream) -> TokenStream {
+ old::main(args, item)
}
/// Marks async function to be executed by selected runtime.
@@ -241,10 +277,11 @@ pub fn main_threaded(args: TokenStream, item: TokenStream) -> TokenStream {
#[proc_macro_attribute]
#[cfg(not(test))] // Work around for rust-lang/rust#62127
pub fn main_basic(args: TokenStream, item: TokenStream) -> TokenStream {
- main(args, item, false)
+ main_impl(args, item, false)
}
-fn main(args: TokenStream, item: TokenStream, rt_threaded: bool) -> TokenStream {
+#[cfg(not(test))] // Work around for rust-lang/rust#62127
+fn main_impl(args: TokenStream, item: TokenStream, rt_threaded: bool) -> TokenStream {
let input = syn::parse_macro_input!(item as syn::ItemFn);
let args = syn::parse_macro_input!(args as syn::AttributeArgs);
@@ -262,6 +299,37 @@ fn main(args: TokenStream, item: TokenStream, rt_threaded: bool) -> TokenStream
///
/// ## Options:
///
+/// - `basic_scheduler` - All tasks are executed on the current thread. Used by default.
+/// - `threaded_scheduler` - Use multi-threaded scheduler.
+///
+/// ## Usage
+///
+/// ### Select runtime
+///
+/// ```no_run
+/// #[tokio::test(threaded_scheduler)]
+/// async fn my_test() {
+/// assert!(true);
+/// }
+/// ```
+///
+/// ### Using default
+///
+/// ```no_run
+/// #[tokio::test]
+/// async fn my_test() {
+/// assert!(true);
+/// }
+/// ```
+#[proc_macro_attribute]
+pub fn test_threaded(args: TokenStream, item: TokenStream) -> TokenStream {
+ test_impl(args, item, true)
+}
+
+/// Marks async function to be executed by runtime, suitable to test enviornment
+///
+/// ## Options:
+///
/// - `core_threads=n` - Sets core threads to `n`.
/// - `max_threads=n` - Sets max threads to `n`.
///
@@ -285,8 +353,8 @@ fn main(args: TokenStream, item: TokenStream, rt_threaded: bool) -> TokenStream
/// }
/// ```
#[proc_macro_attribute]
-pub fn test_threaded(args: TokenStream, item: TokenStream) -> TokenStream {
- test(args, item, true)
+pub fn test(args: TokenStream, item: TokenStream) -> TokenStream {
+ old::test(args, item)
}
/// Marks async function to be executed by runtime, suitable to test enviornment
@@ -305,10 +373,10 @@ pub fn test_threaded(args: TokenStream, item: TokenStream) -> TokenStream {
/// ```
#[proc_macro_attribute]
pub fn test_basic(args: TokenStream, item: TokenStream) -> TokenStream {
- test(args, item, false)
+ test_impl(args, item, false)
}
-fn test(args: TokenStream, item: TokenStream, rt_threaded: bool) -> TokenStream {
+fn test_impl(args: TokenStream, item: TokenStream, rt_threaded: bool) -> TokenStream {
let input = syn::parse_macro_input!(item as syn::ItemFn);
let args = syn::parse_macro_input!(args as syn::AttributeArgs);
@@ -330,3 +398,157 @@ fn test(args: TokenStream, item: TokenStream, rt_threaded: bool) -> TokenStream
parse_knobs(input, args, true, rt_threaded).unwrap_or_else(|e| e.to_compile_error().into())
}
+
+mod old {
+ use proc_macro::TokenStream;
+ use quote::quote;
+
+ enum Runtime {
+ Basic,
+ Threaded,
+ Auto,
+ }
+
+ #[cfg(not(test))] // Work around for rust-lang/rust#62127
+ pub(crate) fn main(args: TokenStream, item: TokenStream) -> TokenStream {
+ let input = syn::parse_macro_input!(item as syn::ItemFn);
+ let args = syn::parse_macro_input!(args as syn::AttributeArgs);
+
+ let ret = &input.sig.output;
+ let name = &input.sig.ident;
+ let inputs = &input.sig.inputs;
+ let body = &input.block;
+ let attrs = &input.attrs;
+ let vis = input.vis;
+
+ if input.sig.asyncness.is_none() {
+ let msg = "the async keyword is missing from the function declaration";
+ return syn::Error::new_spanned(input.sig.fn_token, msg)
+ .to_compile_error()
+ .into();
+ } else if name == "main" && !inputs.is_empty() {
+ let msg = "the main function cannot accept arguments";
+ return syn::Error::new_spanned(&input.sig.inputs, msg)
+ .to_compile_error()
+ .into();
+ }
+
+ let mut runtime = Runtime::Auto;
+
+ for arg in args {
+ if let syn::NestedMeta::Meta(syn::Meta::Path(path)) = arg {
+ let ident = path.get_ident();
+ if ident.is_none() {
+ let msg = "Must have specified ident";
+ return syn::Error::new_spanned(path, msg).to_compile_error().into();
+ }
+ match ident.unwrap().to_string().to_lowercase().as_str() {
+ "threaded_scheduler" => runtime = Runtime::Threaded,
+ "basic_scheduler" => runtime = Runtime::Basic,
+ name => {
+ let msg = format!("Unknown attribute {} is specified; expected `basic_scheduler` or `threaded_scheduler`", name);
+ return syn::Error::new_spanned(path, msg).to_compile_error().into();
+ }
+ }
+ }
+ }
+
+ let result = match runtime {
+ Runtime::Threaded | Runtime::Auto => quote! {
+ #(#attrs)*
+ #vis fn #name(#inputs) #ret {
+ tokio::runtime::Runtime::new().unwrap().block_on(async { #body })
+ }
+ },
+ Runtime::Basic => quote! {
+ #(#attrs)*
+ #vis fn #name(#inputs) #ret {
+ tokio::runtime::Builder::new()
+ .basic_scheduler()
+ .enable_all()
+ .build()
+ .unwrap()
+ .block_on(async { #body })
+ }
+ },
+ };
+
+ result.into()
+ }
+
+ pub(crate) fn test(args: TokenStream, item: TokenStream) -> TokenStream {
+ let input = syn::parse_macro_input!(item as syn::ItemFn);
+ let args = syn::parse_macro_input!(args as syn::AttributeArgs);
+
+ let ret = &input.sig.output;
+ let name = &input.sig.ident;
+ let body = &input.block;
+ let attrs = &input.attrs;
+ let vis = input.vis;
+
+ for attr in attrs {
+ if attr.path.is_ident("test") {
+ let msg = "second test attribute is supplied";
+ return syn::Error::new_spanned(&attr, msg)
+ .to_compile_error()
+ .into();
+ }
+ }
+
+ if input.sig.asyncness.is_none() {
+ let msg = "the async keyword is missing from the function declaration";
+ return syn::Error::new_spanned(&input.sig.fn_token, msg)
+ .to_compile_error()
+ .into();
+ } else if !input.sig.inputs.is_empty() {
+ let msg = "the test function cannot accept arguments";
+ return syn::Error::new_spanned(&input.sig.inputs, msg)
+ .to_compile_error()
+ .into();
+ }
+
+ let mut runtime = Runtime::Auto;
+
+ for arg in args {
+ if let syn::NestedMeta::Meta(syn::Meta::Path(path)) = arg {
+ let ident = path.get_ident();
+ if ident.is_none() {
+ let msg = "Must have specified ident";
+ return syn::Error::new_spanned(path, msg).to_compile_error().into();
+ }
+ match ident.unwrap().to_string().to_lowercase().as_str() {
+ "threaded_scheduler" => runtime = Runtime::Threaded,
+ "basic_scheduler" => runtime = Runtime::Basic,
+ name => {
+ let msg = format!("Unknown attribute {} is specified; expected `basic_scheduler` or `threaded_scheduler`", name);
+ return syn::Error::new_spanned(path, msg).to_compile_error().into();
+ }
+ }
+ }
+ }
+
+ let result = match runtime {
+ Runtime::Threaded => quote! {
+ #[test]
+ #(#attrs)*
+ #vis fn #name() #ret {
+ tokio::runtime::Runtime::new().unwrap().block_on(async { #body })
+ }
+ },
+ Runtime::Basic | Runtime::Auto => quote! {
+ #[test]
+ #(#attrs)*
+ #vis fn #name() #ret {
+ tokio::runtime::Builder::new()
+ .basic_scheduler()
+ .enable_all()
+ .build()
+ .unwrap()
+ .block_on(async { #body })
+ }
+ },
+ };
+
+ result.into()
+ }
+}