Bitte
Starting with Rust 1.75, it’s possible to use async fn in a trait:
But if you use an async function in a pub trait, Rust issues a warning:
⚠️ warning: use of
async fnin public traits is discouraged as auto trait bounds cannot be specified
ℹ️ help: you can alternatively desugar to a normalfnthat returnsimpl Future
This warning means that the async fn won’t be usable in a multithreaded program. For example, if Tokio’s multithreaded runtime is used, you cannot spawn a task to run the Future returned by get_user. Tokio may execute the future on other thread(s), so the future needs to be marked as sendable to other threads.
The compiler warning recommends “desugar”ing the async fn into something like:
By using the impl Future syntax instead, you’re able to apply the necessary Send and/or Sync bounds which allow your trait to be used in multi-threaded programs.
When you do this, any type that wants to implement your trait is also unable to use async fn, and must apply a similar desugaring:
Instead of doing this desugaring by hand, you can use bitte:
use bitte;
By default, Bitte won’t add any Send or Sync bounds; you can switch that default by enabling the threads feature, or individually by writing #[bitte(Send, Sync)].
Installation
Add this to your Cargo.toml:
[]
= "0.0.1"
For automatic Send + Sync bounds:
[]
= { = "0.0.1", = ["threads"] }
Usage
Apply #[bitte] to transform all async methods in a trait:
use bitte;
This transforms to:
Implementation with #[bitte]
Apply #[bitte] to impl blocks to write natural async methods:
Desugaring individual methods
Apply #[bitte] to specific methods:
Applying thread safety trait bounds
When the threads feature is enabled, Send + Sync bounds are automatically added:
// With threads feature: adds Send + Sync
Transforms to:
Explicit Send and/or Sync
Override the default behavior:
// Explicitly enable
// Explicitly disable
// Mix and match per method
Feature Flags
threads: AddSendand/orSyncbounds to desugared trait and implfns
Implementation
There are two ways to implement traits transformed by bitte:
With #[bitte] on impl block (recommended)
Apply #[bitte] to your impl block to write natural async methods:
Manual implementation
You can also manually implement the desugared methods:
Comparison with async-trait
Prior to Rust 1.75, most code that needed async in traits used the async-trait crate.
use async_trait;
The async_trait macro also desugars async fns, but turns them into a Box<dyn Future> instead:
You may still want to use async-trait – it’s not version 0.0.1, it’s already used in 8,000+ crates, its desugared traits are dyn-compatible, it lets you support older Rust versions, and it handles references in trait fn parameters.