Skip to content

Commit

Permalink
Merge pull request #982 from wvwwvwwv/main
Browse files Browse the repository at this point in the history
Change: #959 ditch async_trait for the singlethreade feature
  • Loading branch information
drmingdrmer authored Dec 29, 2023
2 parents e9e065e + 12eda69 commit 455422a
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 9 deletions.
3 changes: 1 addition & 2 deletions macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,5 @@ proc-macro = true

[features]

# Passes `?Send` to `async_trait` to force affected tasks to be spawned in the current thread.
# Do not use `async_trait` and do not add `Send` bounds.
singlethreaded = []

21 changes: 14 additions & 7 deletions macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
use proc_macro::TokenStream;

/// This macro either emits `#[async_trait::async_trait]` or `#[async_trait::async_trait(?Send)]`
/// based on the activated feature set.
/// This macro emits `#[async_trait::async_trait]` if the `singlethreaded` feature is disabled.
///
/// This assumes that the `[async_trait](https://crates.io/crates/async-trait)` crate is imported
/// as `async_trait`. If the `singlethreaded` feature is enabled, `?Send` is passed to
/// `async_trait`, thereby forcing the affected asynchronous trait functions and methods to be run
/// in the same thread.
/// Starting from Rust 1.75.0, the `async_fn_in_trait` language feature is generally available
/// that allows traits to contain asynchronous methods and associated functions. However, the
/// feature has several known issues that are mainly related to Rust compiler's abilities to infer
/// `Send` bounds of associated types: [`90696``](https://github.com/rust-lang/rust/issues/90696).
///
/// Therefore, if a trait requires `Send` bounds in its associated data types, this macro
/// circumvents the compiler shortcomings by using the
/// [`async-trait`](https://crates.io/crates/async-trait) crate which boxes return
/// [`Future`](https://doc.rust-lang.org/std/future/trait.Future.html) types of all the
/// asynchronous methods and associated functions of the trait.
#[proc_macro_attribute]
pub fn add_async_trait(_attr: TokenStream, item: TokenStream) -> TokenStream {
if cfg!(feature = "singlethreaded") {
let mut output = "#[async_trait::async_trait(?Send)]".parse::<TokenStream>().unwrap();
// `async_fn_in_trait` requires the user to explicitly specify the `Send` bound for public
// trait methods, however the `singlethreaded` feature renders the requirement irrelevant.
let mut output = "#[allow(async_fn_in_trait)]".parse::<TokenStream>().unwrap();
output.extend(item);
output
} else {
Expand Down
2 changes: 2 additions & 0 deletions openraft/src/docs/feature_flags/feature-flags.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ By default openraft enables no features.
- `singlethreaded`: removes `Send` and `Sync` bounds from `AppData`, `AppDataResponse`, `RaftEntry`, `SnapshotData`
and other types to force the asynchronous runtime to spawn any tasks in the current thread.
This is for any single-threaded application that never allows a raft instance to be shared among multiple threads.
This feature relies on the `async_fn_in_trait` language feature that is officially supported from Rust 1.75.0.
If the feature is enabled, affected asynchronous trait methods and associated functions no longer use `async_trait`.
In order to use the feature, `AsyncRuntime::spawn` should invoke `tokio::task::spawn_local` or equivalents.
<br/><br/>

Expand Down

0 comments on commit 455422a

Please sign in to comment.