mlua-rs / mlua

High level Lua 5.4/5.3/5.2/5.1 (including LuaJIT) and Roblox Luau bindings to Rust with async/await support
Other
1.76k stars 139 forks source link

set_hook doesn't work with async execution #347

Open b0bleet opened 11 months ago

b0bleet commented 11 months ago

set_hook doesn't work properly when executing Lua with exec_async()

use anyhow::Result;
use mlua::{HookTriggers, Lua};

#[tokio::main]
async fn main() -> Result<()> {
    let lua = Lua::new();
    lua.set_hook(HookTriggers::EVERY_LINE, move |_lua, _debug| {
        println!("test hook");
        Ok(())
    });

    lua.load(
        r#"
            local x = 2 + 3
            local y = x * 63
            local z = string.len(x..", "..y)
        "#,
    )
    .exec_async()
    .await?;

    lua.remove_hook();

    Ok(())
}
khvzak commented 10 months ago

It's not a bug, this is how Lua works. Async execution happens in coroutines, and each coroutine need to have their own hook. Setting it in main Lua thread would only update the main thread without affecting others.

The correct code for hooks in async context would be:

async fn main() -> Result<()> {
    let lua = Lua::new();

    let func = lua
        .load(
            r#"
            local x = 2 + 3
            local y = x * 63
            local z = string.len(x..", "..y)
        "#,
        )
        .into_function()?;

    let thread = lua.create_thread(func)?;
    thread.set_hook(HookTriggers::EVERY_LINE, move |_lua, _debug| {
        println!("test hook 2");
        Ok(())
    });
    let _: () = thread.into_async(()).await?;

    lua.remove_hook();

    Ok(())
}