Expand description
Write async libraries without choosing a runtime.
Your users should decide whether to use tokio, async-std, or any other runtime. Not you.
§How It Works
Instead of hard-coding tokio::spawn
, accept an executor parameter:
use executor_core::Executor;
pub async fn parallel_sum<E: Executor>(
executor: &E,
numbers: Vec<i32>
) -> i32 {
let (left, right) = numbers.split_at(numbers.len() / 2);
// Spawn on ANY runtime via the executor parameter
let left_sum = executor.spawn(async move {
left.iter().sum::<i32>()
});
let right_sum = executor.spawn(async move {
right.iter().sum::<i32>()
});
left_sum.await + right_sum.await
}
Now users can call your library with their preferred runtime:
// User already using tokio? Great!
tokio::runtime::Runtime::new().unwrap().block_on(async {
let runtime = tokio::runtime::Handle::current();
let sum = parallel_sum(&runtime, vec![1, 2, 3, 4]).await;
});
// User prefers async-executor? Also great!
async_executor::Executor::new().run(async {
let executor = async_executor::Executor::new();
let sum = parallel_sum(&executor, vec![1, 2, 3, 4]).await;
});
§Quick Start
For library authors: Just add the core crate, no features needed.
[dependencies]
executor-core = "0.2"
For app developers: Add with your runtime’s feature.
[dependencies]
executor-core = { version = "0.2", features = ["tokio"] }
§API
Two traits:
Executor
- ForSend
futuresLocalExecutor
- For non-Send
futures (Rc, RefCell, etc.)
Both return async_task::Task
:
ⓘ
let task = executor.spawn(async { work() });
let result = task.await; // Get result
task.cancel().await; // Cancel task
task.detach(); // Run in background
Modules§
Traits§
- Executor
- A trait for executor implementations that can spawn thread-safe futures.
- Local
Executor - A trait for executor implementations that can spawn futures on the current thread.