I'm registering the module with:
\nglobals.set(\"vec2\", lua.create_proxy::<Vec2>()?)?;It seems like the mlua userdata is dealing with this differently from the C API so it fails to detect the userdata as the correct type.
","upvoteCount":1,"answerCount":1,"acceptedAnswer":{"@type":"Answer","text":"Check my example, it works:
\nstruct Vec2(f32, f32);\n\nlet lua = Lua::new();\n\nlet push_vector = lua.create_function(|lua, (x, y): (f32, f32)| {\n let vec = Vec2(x, y);\n lua.create_any_userdata(vec)\n})?;\nlua.set_named_registry_value(\"push_vector\", push_vector)?;\n\nlet get_vector = lua.create_function(|_, mut ud: UserDataRefMut<Vec2>| {\n let vec: *mut Vec2 = &mut *ud;\n Ok(Value::LightUserData(LightUserData(vec as *mut c_void)))\n})?;\nlua.set_named_registry_value(\"get_vector\", get_vector)?;\n\nunsafe extern \"C\" fn lua_isvector(L: *mut lua_State, idx: c_int) -> c_int {\n !lua_tovector(L, idx).is_null() as c_int\n}\n\nunsafe extern \"C\" fn lua_pushvector(L: *mut lua_State, x: f32, y: f32) {\n ffi::lua_getfield(L, ffi::LUA_REGISTRYINDEX, c\"push_vector\".as_ptr());\n ffi::lua_pushnumber(L, x as f64);\n ffi::lua_pushnumber(L, y as f64);\n ffi::lua_call(L, 2, 1);\n}\n\nunsafe extern \"C\" fn lua_tovector(L: *mut lua_State, idx: c_int) -> *mut Vec2 {\n let idx = lua_absindex(L, idx);\n ffi::lua_getfield(L, ffi::LUA_REGISTRYINDEX, c\"get_vector\".as_ptr());\n ffi::lua_pushvalue(L, idx);\n let vec = match ffi::lua_pcall(L, 1, 1, 0) {\n ffi::LUA_OK => ffi::lua_touserdata(L, -1) as *mut Vec2,\n _ => std::ptr::null_mut(),\n };\n ffi::lua_pop(L, 1);\n vec\n}\n\nunsafe {\n lua.exec_raw::<()>((), |state| {\n lua_pushvector(state, 1.0, 2.0);\n println!(\"is vector: {}\", lua_isvector(state, -1));\n let vec2 = lua_tovector(state, -1);\n if !vec2.is_null() {\n println!(\"vector: ({}, {})\", (*vec2).0, (*vec2).1);\n }\n })?;\n}-
|
I'm porting a large C codebase, and need to provide a C API for static VEC2_METATABLE: &[u8; 5] = b"vec2\0";
#[unsafe(no_mangle)]
pub unsafe extern "C" fn lua_tovector( L: *mut mlua::lua_State, ind: c_int ) -> *mut Vec2 {
unsafe {
ffi::lua_touserdata( L, ind ) as *mut Vec2
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn luaL_checkvector( L: *mut mlua::lua_State, ind: c_int ) -> *mut Vec2 {
unsafe {
match lua_isvector( L, ind ) {
0 => {
ffi::luaL_typerror( L, ind, VEC2_METATABLE.as_ptr() as *const c_char );
std::ptr::null_mut()
},
_ => lua_tovector( L, ind ),
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn lua_pushvector( L: *mut mlua::lua_State, vec: Vec2 ) -> *mut Vec2 {
let size = std::mem::size_of::<Vec2>();
unsafe {
let v: *mut Vec2 = ffi::lua_newuserdata( L, size ) as *mut Vec2;
std::ptr::copy_nonoverlapping( &vec as *const Vec2, v, size );
ffi::luaL_getmetatable( L, VEC2_METATABLE.as_ptr() as *const c_char );
ffi::lua_setmetatable( L, -2 );
v
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn lua_isvector( L: *mut mlua::lua_State, ind: c_int ) -> c_int {
unsafe {
if ffi::lua_getmetatable( L, ind ) == 0 {
return 0;
}
ffi::lua_getfield( L, ffi::LUA_REGISTRYINDEX, VEC2_METATABLE.as_ptr() as *const c_char );
let ret = match ffi::lua_rawequal( L, -1, -2 ) { /* Check metatable. */
0 => 0,
_ => 1,
};
ffi::lua_pop( L, 2 ); /* remove both metatables */
ret
}
}I'm registering the module with: globals.set("vec2", lua.create_proxy::<Vec2>()?)?;It seems like the mlua userdata is dealing with this differently from the C API so it fails to detect the userdata as the correct type. |
Beta Was this translation helpful? Give feedback.
-
mlua by-design support only userdata that were made using mlua (high level) api, to ensure data types safety. Probably the easiest way would be making |
Beta Was this translation helpful? Give feedback.
Check my example, it works: