Skip to content

Commit 0564b67

Browse files
author
Andrew J Westlake
committed
Added basic tokio main proc macro, added some docs for the attributes feature
1 parent 450ce88 commit 0564b67

File tree

6 files changed

+102
-2
lines changed

6 files changed

+102
-2
lines changed

Cargo.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,12 @@ default = []
2525
[[example]]
2626
name = "async_std"
2727
path = "examples/async_std.rs"
28-
required-features = ["async-std-runtime"]
28+
required-features = ["attributes", "async-std-runtime"]
29+
30+
[[example]]
31+
name = "tokio"
32+
path = "examples/tokio.rs"
33+
required-features = ["attributes", "tokio-runtime"]
2934

3035
[[test]]
3136
name = "test_async_std_asyncio"

examples/tokio.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#[pyo3_asyncio::tokio::main]
2+
async fn main() -> PyResult<()> {
3+
let fut = Python::with_gil(|py| {
4+
let asyncio = py.import("asyncio")?;
5+
6+
// convert asyncio.sleep into a Rust Future
7+
pyo3_asyncio::into_future(asyncio.call_method1("sleep", (1.into_py(py),))?)
8+
})?;
9+
10+
println!("sleeping for 1s");
11+
fut.await?;
12+
println!("done");
13+
14+
Ok(())
15+
}

pyo3-asyncio-macros/src/lib.rs

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use proc_macro::TokenStream;
66
use quote::{quote, quote_spanned};
77
use syn::spanned::Spanned;
88

9-
/// Enables an async main function.
9+
/// Enables an async main function that uses the async-std runtime.
1010
///
1111
/// # Examples
1212
///
@@ -66,3 +66,65 @@ pub fn async_std_main(_attr: TokenStream, item: TokenStream) -> TokenStream {
6666

6767
result.into()
6868
}
69+
70+
/// Enables an async main function that uses the tokio runtime.
71+
///
72+
/// # Examples
73+
///
74+
/// ```ignore
75+
/// #[pyo3_asyncio::tokio::main]
76+
/// async fn main() -> PyResult<()> {
77+
/// Ok(())
78+
/// }
79+
/// ```
80+
#[cfg(not(test))] // NOTE: exporting main breaks tests, we should file an issue.
81+
#[proc_macro_attribute]
82+
pub fn tokio_main(_attr: TokenStream, item: TokenStream) -> TokenStream {
83+
let input = syn::parse_macro_input!(item as syn::ItemFn);
84+
85+
let ret = &input.sig.output;
86+
let inputs = &input.sig.inputs;
87+
let name = &input.sig.ident;
88+
let body = &input.block;
89+
let attrs = &input.attrs;
90+
let vis = &input.vis;
91+
92+
if name != "main" {
93+
return TokenStream::from(quote_spanned! { name.span() =>
94+
compile_error!("only the main function can be tagged with #[async_std::main]"),
95+
});
96+
}
97+
98+
if input.sig.asyncness.is_none() {
99+
return TokenStream::from(quote_spanned! { input.span() =>
100+
compile_error!("the async keyword is missing from the function declaration"),
101+
});
102+
}
103+
104+
let result = quote! {
105+
#vis fn main() {
106+
#(#attrs)*
107+
async fn main(#inputs) #ret {
108+
#body
109+
}
110+
111+
use pyo3::prelude::*;
112+
113+
pyo3_asyncio::tokio::init_multi_thread();
114+
115+
Python::with_gil(|py| {
116+
pyo3_asyncio::with_runtime(py, || {
117+
pyo3_asyncio::tokio::run_until_complete(py, main())?;
118+
119+
Ok(())
120+
})
121+
.map_err(|e| {
122+
e.print_and_set_sys_last_vars(py);
123+
})
124+
.unwrap();
125+
});
126+
}
127+
};
128+
129+
result.into()
130+
}

src/async_std.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use pyo3::prelude::*;
55

66
use crate::generic::{self, JoinError, Runtime};
77

8+
/// <span class="module-item stab portability" style="display: inline; border-radius: 3px; padding: 2px; font-size: 80%; line-height: 1.2;"><code>attributes</code></span> Sets up the async-std runtime and runs an async fn as main
89
#[cfg(feature = "attributes")]
910
pub use pyo3_asyncio_macros::async_std_main as main;
1011

src/lib.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,19 @@
4040
//! <span
4141
//! class="module-item stab portability"
4242
//! style="display: inline; border-radius: 3px; padding: 2px; font-size: 80%; line-height: 1.2;"
43+
//! ><code>attributes</code></span>
44+
//! are only available when the `attributes` Cargo feature is enabled:
45+
//!
46+
//! ```toml
47+
//! [dependencies.pyo3-asyncio]
48+
//! version = "0.13.0"
49+
//! features = ["attributes"]
50+
//! ```
51+
//!
52+
//! Items marked with
53+
//! <span
54+
//! class="module-item stab portability"
55+
//! style="display: inline; border-radius: 3px; padding: 2px; font-size: 80%; line-height: 1.2;"
4356
//! ><code>async-std-runtime</code></span>
4457
//! are only available when the `async-std-runtime` Cargo feature is enabled:
4558
//!

src/tokio.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ use pyo3::prelude::*;
1212

1313
use crate::generic;
1414

15+
/// <span class="module-item stab portability" style="display: inline; border-radius: 3px; padding: 2px; font-size: 80%; line-height: 1.2;"><code>attributes</code></span> Sets up the tokio runtime and runs an async fn as main
16+
#[cfg(feature = "attributes")]
17+
pub use pyo3_asyncio_macros::tokio_main as main;
18+
1519
static TOKIO_RUNTIME: OnceCell<Runtime> = OnceCell::new();
1620

1721
const EXPECT_TOKIO_INIT: &str = "Tokio runtime must be initialized";

0 commit comments

Comments
 (0)