This project aims to provide simple executor which helps to delegate running asynchronous Rust code to external event loops. As example, it may be useful in case when you develop dynamic linked libraries which have async code in Rust and want to run it in different execution environments.
On a Rust side you should add extern_executor
as dependency to your cdylib
crate and use spawn()
function to run futures, like so:
```rust use extern_executor::spawn;
spawn(async { // your awaits }); ```
On a C side you should implement executor's driver using your preferred event loop API. For example, when libuv is used it may looks like so:
```c
static void taskwake(RustAsyncExecutorExternTask data) { uvasynct* handle = data; // wakeup uv's async task uvasync_send(handle); }
static void taskpoll(uvasynct* handle) { // poll internal task until task complete if (!rustasyncexecutorpoll(handle->data)) { // drop internal task when task complete rustasyncexecutordrop(handle->data); // drop uv's async task handle uvclose((uvhandlet*)handle, NULL); } }
static RustAsyncExecutorExternTask tasknew(RustAsyncExecutorUserData data) { uvloopt* loop = data; // crate and initialize uv's async task handle uvasynct* handle = malloc(sizeof(uvasynct)); uvasyncinit(loop, handle, taskpoll); return handle; }
static void taskrun(RustAsyncExecutorExternTask task, RustAsyncExecutorInternTask data) { uvasynct* handle = task; // store internal task handle to be able to poll it later handle->data = data; uvasync_send(handle); // do initial polling (important) }
void uvrustasyncexecutorinit(uvloopt *loop) { // send out executor API to Rust side rustasyncexecutorinit(tasknew, taskrun, taskwake, loop); } ```
Now you can run your async code in libuv's event loop like so:
```c int main(void) { uvloopt loop;
uv_loop_init(&loop);
uv_rust_async_executor_init(&loop);
my_async_function(my_async_callback);
uv_run(&loop, UV_RUN_DEFAULT);
uv_loop_close(&loop);
return 0;
} ```
The C header rustasyncexecutor.h generated using cbindgen. There are two options how you can get it:
In second case generated header will be available at target/$PROFILE/include
directory.
To simplify setup for some widely used event loops the built-in drivers was introduced. To use driver you should enable corresponding feature. Currently supported next drivers:
Rust currently have an issues related to re-exporting of symbols from crate's dependencies (#2771).
As temporary solution you can setup build profile like so:
toml
[profile.release]
lto = true
incremental = false
This executor incompatible with tokio's futures because tokio still has non-trivial executor which mixed with reactor.