asynchronousrustrust-actix

How to execute async lua code with rlua-async?


I'm trying to run/script my existing rust async code with rlua-async. Sadly it is not well documented and has no examples but I have prevailed in getting my async functions defined but I have trouble getting my lua code executed in an async way.

I have created a minimal repository to reproduce the problem here

use rlua::{Lua};
use rlua_async::{ChunkExt, ContextExt};

#[actix_rt::main]
async fn main() {
    let lua_code = "my.asyncfunc(42)";
    let lua = Lua::new();

    lua.context(|lua_ctx| {
        let globals = lua_ctx.globals();
        let map_table = lua_ctx.create_table().unwrap();
        map_table
            .set(
                "asyncfunc",
                lua_ctx
                    .create_async_function(
                        |_ctx,
                         param:
                            u32
                        | async move {
                            println!("async function called {}", param);
                            Ok(())
                        }).unwrap()).unwrap();

        globals.set("my", map_table).unwrap();
    });

    lua.context(|lua_context| async move {
        let chunk = lua_context
            .load(&lua_code);
        chunk.exec_async(lua_context).await.unwrap();
    })
        .await;
    println!("finished");
}

But I'm getting this error message:

error: lifetime may not live long enough
  --> src\main.rs:28:31
   |
28 |       lua.context(|lua_context| async move {
   |  __________________------------_^
   | |                  |          |
   | |                  |          return type of closure is impl Future
   | |                  has type `LuaContext<'1>`
29 | |         let chunk = lua_context
30 | |             .load(&lua_code);
31 | |         chunk.exec_async(lua_context).await.unwrap();
32 | |     })
   | |_____^ returning this value requires that `'1` must outlive `'2`

I really don't get what the error is trying to tell me and there is no helpful tips or even documentation linked.

The closure is somehow different from the closure body and needs lifetime annotations? But why and how...?

EDIT: if I instead call the code without async like this:

lua.context(|lua_context| {
    let chunk = lua_context.load(&lua_code);
    chunk.exec().unwrap();
});

it compiles but I get the following panic on runtime:

thread 'main' panicked at 'cannot access a scoped thread local variable without calling `set` first', C:\Users\ahallmann\.cargo\registry\src\github.com-1ecc6299db9ec823\scoped-tls-1.0.0\src\lib.rs:168:9

Everything works fine if I define the function with create_function.


Solution

  • I figured it out with the kind help of the author of rlua-async. The issue is with the actix-rt itself as it requires 'static lifetimes for the block_on call.

    It works fine if you use either futures or tokio instead:

            tokio::runtime::Runtime::new()
                .unwrap()
                .block_on(chunk.exec_async(ctx))
    

    See https://github.com/actix/actix-net/issues/201 or https://github.com/Ekleog/rlua-async/issues/1 for further information.