Async
Rust async functions can be exported just like regular functions. Add async to the function signature and BoltFFI handles bridging the future to the target language’s async model. The generated bindings let callers await the result using native syntax, with no manual callback wiring or polling logic on either side. Cancellation propagates from the caller back to Rust, and errors work the same as synchronous functions.
How It Works
BoltFFI uses continuation-based polling to bridge Rust futures to target languages. When you call an async function, BoltFFI creates a handle to the future and returns it immediately. The target language’s async runtime then polls this handle, passing a continuation callback. When the Rust future makes progress or completes, the callback fires and the target language resumes execution. This approach is lock-free with no busy-waiting, and the target language drives the entire polling lifecycle.
See Async Internals for the full implementation details including the FFI protocol and sequence diagram.
Standalone Functions
Standalone async functions work like regular exported functions with the async keyword added. The function runs on the target language’s async context and returns when the Rust future completes. Parameters are captured when the function is called, and the result is delivered through the native async mechanism.
Methods
Methods on classes can be async. The object reference is captured along with any parameters when the method is called. This lets you build clients and services that hold connections or state and expose async operations on them. Both &self and &mut self methods can be async.
Error Handling
Async functions can return Result just like synchronous functions. The error is delivered through the target language’s native error handling mechanism when the async operation completes. The same error types and conversion rules apply as described in Errors.
Cancellation
Cancellation in the target language propagates back to Rust. When a caller cancels an async operation, the future is marked as cancelled, and the next poll returns immediately without running more of the future’s code. This is cooperative cancellation, not preemption. The future is not forcibly aborted mid-execution, so any cleanup code after an await point may not run if cancellation happens before reaching it.
Runtime
BoltFFI wraps your future and lets the target language drive polling. BoltFFI itself does not require a Rust async runtime. The polling mechanism is built into the generated bindings and works without tokio, async-std, or any other executor.
However, if your async code uses libraries that depend on a runtime, that runtime must be available. Pure computation and channel-based async works without any runtime. Libraries like reqwest or tokio::fs require tokio’s reactor to be running because they rely on it for I/O. If you use such libraries, you need to ensure a tokio runtime is active when your async functions execute.