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

Add a way to setmetatable of builtin types #445

Closed negrel closed 2 months ago

negrel commented 2 months ago

I want to override metatable of primitive types such as string. Currently this is not possible as set_metatable is only implemented for Table and lua builtin setmetatable check that arguments are tables.

use mlua::{
    chunk,
    ffi::{luaL_newmetatable, luaL_setmetatable, lua_pushstring},
    Lua, LuaOptions, StdLib,
};

fn main() {
    let lua = Lua::new_with(StdLib::NONE, LuaOptions::default()).unwrap();

    lua.load(chunk!({
        print(getmetatable("")); // print nil
    }))
    .eval::<()>()
    .unwrap();

    unsafe {
        let state = lua.state(); // local fork of mlua v0.9.9 with state() public.
        luaL_newmetatable(state, c"string".as_ptr());
        lua_pushstring(state, c"".as_ptr());
        luaL_setmetatable(state, c"string".as_ptr());
    }

    lua.load(chunk!({
        print(getmetatable("")); // print table: 0xdeadbeef
    }))
    .eval::<()>()
    .unwrap();
}

Is there a way to do so without using unsafe and forking mlua ? If not, do you want to implement it? I can make a PR if you want.

negrel commented 2 months ago

Nice thanks!

khvzak commented 2 months ago

I added support for this feature, see the linked commit.

Also the new version provides more simple way to run low-level funcs that are safe to longjmp:

unsafe {
    lua.with_raw_state((), |state| {
        // your code here
    })?;
}