Bindings and a high-level interface to Binaryen's Asyncify transformation for WebAssembly.
Asyncify is a feature of Binaryen that allows WebAssembly code to pause and resume execution. This enables async/await style programming in WebAssembly modules that don't natively support it.
bysyncify provides Rust bindings and abstractions for working with Asyncify, allowing you to:
- Suspend and resume WebAssembly execution at arbitrary points
- Embed Rust futures within synchronous coroutine code
- Create coroutines that can be driven by async executors
no_stdcompatible: Works in bare-metal and embedded WebAssembly environments- Low-level API: Direct access to Asyncify primitives via
RawStack,RawCore, andRawCoroutine - High-level API (with
allocfeature): Ergonomic interface with automatic memory management viaCore,Coroutine, andCoreHandle - Trait implementations: Implements
awaiter-traitandawaiter-trait-02for interoperability
Add this to your Cargo.toml:
[dependencies]
bysyncify = "0.2"To enable heap-allocated types:
[dependencies]
bysyncify = { version = "0.2", features = ["alloc"] }Your WebAssembly module must be processed with Binaryen's Asyncify transformation. This can be done using the wasm-opt tool:
wasm-opt --asyncify -O3 input.wasm -o output.wasmThe asyncify imports (asyncify.start_unwind, asyncify.stop_unwind, etc.) must be provided by the host environment.
use bysyncify::Coroutine;
use core::pin::pin;
// Create a coroutine with a 4KB stack
let coroutine = Coroutine::new(4096, |handle| {
// Use handle.embed() to await futures within the coroutine
// let result = handle.embed(pin!(async_operation()));
// Return a value from the coroutine
42
});
// The coroutine implements Future, so it can be awaited
// let result = coroutine.await;- Create a coroutine: Use
Coroutine::new()with a stack size and a closure - Embed futures: Within the closure, use
handle.embed()to await futures - Suspension: When a future returns
Poll::Pending, Asyncify unwinds the stack - Resumption: When the coroutine is polled again, Asyncify rewinds the stack
- Completion: When the closure returns, the coroutine completes
The stack size determines how much state can be saved during suspension. A larger stack allows deeper call stacks but uses more memory. 4KB-16KB is typically sufficient for most use cases.
RawStack: Memory buffer for Asyncify stateRawCore: Core state manager for Asyncify operationsRawCoroutine<U, T>: Low-level coroutine wrapper
Core: Heap-allocated core with automatic memory managementCoroutine<U, T>: High-level coroutine that implementsFutureCoreHandle<'a>: Handle for embedding futures within coroutinesRawCoreHandle: Raw handle without lifetime constraints
start_unwind(stack): Begin stack unwindingstop_unwind(): Complete stack unwindingstart_rewind(stack): Begin stack rewindingstop_rewind(): Complete stack rewindingget_state(): Get current Asyncify state (0=normal, 1=unwinding, 2=rewinding)
This project is licensed under CC0-1.0.
- Binaryen - WebAssembly toolchain with Asyncify
- Asyncify blog post - Technical overview of Asyncify
- awaiter-trait - Trait for awaiter implementations
- Provide safe Rust wrappers for Asyncify
- Integrate with
awaiter-trait
- Crate setup (v0.2.6) with
awaiter-traitintegration
AI assisted