use std::any::{Any, TypeId};
use std::mem;
use std::ptr;
use crate::{sys, LuaPush, LuaRead, LuaTable};
#[inline]
extern "C" fn destructor_wrapper<T>(lua: *mut sys::lua_State) -> libc::c_int {
unsafe {
let obj = sys::lua_touserdata(lua, -1);
ptr::drop_in_place(obj as *mut T);
0
}
}
pub fn push_userdata<'a, T, F>(data: T, lua: *mut sys::lua_State, mut metatable: F) -> i32
where
F: FnMut(LuaTable),
T: 'a + Any,
{
let typeid = format!("{:?}", TypeId::of::<T>());
let lua_data_raw =
unsafe { sys::lua_newuserdata(lua, mem::size_of::<T>() as libc::size_t) };
unsafe {
ptr::write(lua_data_raw as *mut _, data);
sys::lua_newtable(lua);
"__typeid".push_to_lua(lua);
typeid.push_to_lua(lua);
sys::lua_settable(lua, -3);
{
"__gc".push_to_lua(lua);
sys::lua_pushcfunction(lua, destructor_wrapper::<T>);
sys::lua_settable(lua, -3);
}
{
metatable(LuaRead::lua_read(lua).unwrap());
}
sys::lua_setmetatable(lua, -2);
}
1
}
pub fn push_lightuserdata<'a, T, F>(
data: &'a mut T,
lua: *mut sys::lua_State,
mut metatable: F,
) -> i32
where
F: FnMut(LuaTable),
T: 'a + Any,
{
let typeid = format!("{:?}", TypeId::of::<T>());
unsafe {
sys::lua_pushlightuserdata(lua, mem::transmute(data));
};
unsafe {
sys::lua_newtable(lua);
"__typeid".push_to_lua(lua);
typeid.push_to_lua(lua);
sys::lua_settable(lua, -3);
{
metatable(LuaRead::lua_read(lua).unwrap());
}
sys::lua_setmetatable(lua, -2);
}
1
}
pub fn read_userdata<'t, 'c, T>(lua: *mut sys::lua_State, index: i32) -> Option<&'t mut T>
where
T: 'static + Any,
{
unsafe {
let expected_typeid = format!("{:?}", TypeId::of::<T>());
if sys::lua_isuserdata(lua, index) == 0 {
return None;
}
let data_ptr = sys::lua_touserdata(lua, index);
if data_ptr.is_null() {
return None;
}
if sys::lua_getmetatable(lua, index) == 0 {
return None;
}
"__typeid".push_to_lua(lua);
sys::lua_gettable(lua, -2);
match <String as LuaRead>::lua_read(lua) {
Some(ref val) if val == &expected_typeid => {}
_ => {
sys::lua_pop(lua, 2);
return None;
}
}
sys::lua_pop(lua, 2);
Some(mem::transmute(data_ptr))
}
}