[][src]Crate extern_executor

External executor for async Rust

This project aims to provide simple executor which helps to run asynchronous Rust code using external event loops.

Usage

On a Rust side you should add extern_executor as dependency to your cdylib crate and use spawn() function to run futures, like so:

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:

#include <uv.h>
#include <rust_async_executor.h>

static void task_wake(RustAsyncExecutorExternTask data) {
    uv_async_t* handle = data;
    // wakeup uv's async task
    uv_async_send(handle);
}

static void task_poll(uv_async_t* handle) {
    // poll internal task until task complete
    if (!rust_async_executor_poll(handle->data)) {
        // drop internal task when task complete
        rust_async_executor_drop(handle->data);
        // drop uv's async task handle
        uv_close((uv_handle_t*)handle, NULL);
    }
}

static RustAsyncExecutorExternTask
task_new(RustAsyncExecutorUserData data) {
    uv_loop_t* loop = data;
    // crate and initialize uv's async task handle
    uv_async_t* handle = malloc(sizeof(uv_async_t));
    uv_async_init(loop, handle, task_poll);
    return handle;
}

static void task_run(RustAsyncExecutorExternTask task,
                     RustAsyncExecutorInternTask data) {
    uv_async_t* handle = task;
    // store internal task handle to be able to poll it later
    handle->data = data;
    uv_async_send(handle); // do initial polling (important)
}

void uv_rust_async_executor_init(uv_loop_t *loop) {
    // send out executor API to Rust side
    rust_async_executor_init(task_new, task_run, task_wake, loop);
}

Now you can run your async code in libuv's event loop like so:

int main(void) {
    uv_loop_t 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 rust_async_executor.h generated using cbindgen. There are two options how you can get it:

  • Copy from include directory in this repo
  • Generate by youself by using cbindgen feature

In second case generated header will be available at target/$PROFILE/include directory.

Built-in event-loop drivers

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:

  • uv built-in libuv event loop integration (see example_uv)
  • dart built-in dart-lang event loop integration (see example_dart)

Linking issues

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:

[profile.release]
lto = true
incremental = false

Tokio compatibility

This executor incompatible with tokio's futures because tokio still has non-trivial executor which mixed with reactor.

Modules

ffi

Macros

externsDeprecated

Functions

spawn

Spawn task