future_form#
"This isn't even my
finalfuture form!"
Abstractions over Send and !Send futures in Rust.
The Problem#
Async Rust has a fragmentation problem: some runtimes require Send futures (like tokio), while others work with !Send futures (like Wasm). This forces library authors to duplicate their async trait implementations, pick a side, or maintain feature flags that swap entire trait hierarchies.
The Solution#
future_form lets you write async code once and support both Send and !Send futures:
use future_form::{FutureForm, Sendable, Local, future_form};
use std::marker::PhantomData;
trait Counter<K: FutureForm> {
fn next(&self) -> K::Future<'_, u32>;
}
struct Memory<K> {
val: u32,
_marker: PhantomData<K>,
}
// Generates impl for both Sendable and Local
#[future_form(Sendable, Local)]
impl<K: FutureForm> Counter<K> for Memory<K> {
fn next(&self) -> K::Future<'_, u32> {
let val = self.val;
K::from_future(async move { val + 1 })
}
}
Packages#
| Crate | Description |
|---|---|
future_form |
Core traits and types (FutureForm, Sendable, Local) |
future_form_ffi |
FFI support: host-driven polling, effect slots, handles |
future_form_macros |
The #[future_form] attribute macro |
See the future_form README for full documentation, usage patterns, and comparisons with async-trait and trait-variant.
Examples#
| Example | Description |
|---|---|
counter_simple |
Introductory: basic counter, Go/Java/Python hosts |
counter_effects |
Introductory: sans-IO effect protocol, host-fulfilled timestamps + logging |
key_value_store |
Intermediate: per-future Arc<EffectSlot>, concurrent operations, multi-step futures |
Design#
Architecture decisions and rationale are documented in design/.
License#
Licensed under either of Apache License, Version 2.0 or MIT license at your option.