use std::{ffi::c_void, sync::Arc};
use mlua::prelude::*;
use crate::{
lua::object::create_object,
shared::{
object::get_object,
pxs_Runtime,
var::{pxs_Var, pxs_VarObject, pxs_VarType},
},
};
unsafe extern "C" fn free_lua_mem(ptr: *mut c_void) {
if ptr.is_null() {
return;
}
let _ = Box::from(ptr);
}
pub(super) fn from_lua(value: LuaValue) -> Result<pxs_Var, anyhow::Error> {
match value {
LuaValue::Boolean(b) => Ok(pxs_Var::new_bool(b)),
LuaValue::Integer(i) => Ok(pxs_Var::new_i64(i)),
LuaValue::Number(n) => Ok(pxs_Var::new_f64(n)),
LuaValue::String(s) => Ok(pxs_Var::new_string(s.to_string_lossy())),
LuaValue::Function(f) => {
let func = Box::into_raw(Box::new(f));
Ok(pxs_Var::new_function(
func as *mut c_void,
Some(free_lua_mem),
))
}
LuaValue::Table(t) => {
let t_length = t.raw_len();
if t_length == 0 {
let obj = Box::into_raw(Box::new(t));
Ok(pxs_Var::new_object(pxs_VarObject::new_lang_only(obj as *mut c_void), Some(free_lua_mem)))
} else {
let mut values = vec![];
for i in 0..t_length {
let val = from_lua(t.get(i + 1)?)?;
values.push(val);
}
let list_var = pxs_Var::new_list_with(values);
Ok(list_var)
}
}
LuaValue::Error(error) => {
let msg = error.to_string();
Ok(pxs_Var::new_exception(msg))
}
_ => Ok(pxs_Var::new_null()),
}
}
pub(super) fn into_lua(lua: &Lua, var: &pxs_Var) -> LuaResult<LuaValue> {
match var.tag {
pxs_VarType::pxs_Int64 => Ok(mlua::Value::Integer(var.get_i64().unwrap())),
pxs_VarType::pxs_UInt64 => Ok(mlua::Value::Integer(var.get_u64().unwrap() as i64)),
pxs_VarType::pxs_String => {
let contents = var.get_string().unwrap().clone();
let lua_str = lua.create_string(contents)?;
Ok(mlua::Value::String(lua_str))
}
pxs_VarType::pxs_Bool => Ok(mlua::Value::Boolean(var.get_bool().unwrap())),
pxs_VarType::pxs_Float64 => Ok(mlua::Value::Number(var.get_f64().unwrap())),
pxs_VarType::pxs_Null => Ok(mlua::Value::Nil),
pxs_VarType::pxs_Object => {
unsafe {
let table_ptr = var.get_object_ptr() as *const LuaTable;
if table_ptr.is_null() {
return Err(mlua::Error::RuntimeError(
"Null pointer in Object".to_string(),
));
}
let lua_table = (&*table_ptr).clone();
Ok(mlua::Value::Table(lua_table))
}
}
pxs_VarType::pxs_HostObject => {
unsafe {
let idx = var.value.host_object_val;
let pixel_object = get_object(idx).unwrap();
let lang_ptr_is_null = pixel_object.lang_ptr.lock().unwrap().is_null();
if lang_ptr_is_null {
let table = create_object(lua, idx, Arc::clone(&pixel_object));
let table_ptr = Box::into_raw(Box::new(table));
pixel_object.update_lang_ptr(table_ptr as *mut c_void);
}
let lang_ptr = pixel_object.lang_ptr.lock().unwrap();
let table_ptr = *lang_ptr as *const LuaTable;
let table = (&*table_ptr).clone();
Ok(mlua::Value::Table(table))
}
}
pxs_VarType::pxs_List => {
let table = lua.create_table()?;
for item in var.get_list().unwrap().vars.iter() {
let lua_val = into_lua(lua, item)?;
table.push(lua_val)?;
}
Ok(mlua::Value::Table(table))
}
pxs_VarType::pxs_Function => {
unsafe {
let func_ptr = var.value.function_val as *const LuaFunction;
if func_ptr.is_null() {
return Err(mlua::Error::RuntimeError(
"Null pointer in Function".to_string(),
));
}
let lua_function = (&*func_ptr).clone();
Ok(mlua::Value::Function(lua_function))
}
}
pxs_VarType::pxs_Factory => {
let factory = var.get_factory().unwrap();
let res = factory.call(pxs_Runtime::pxs_Lua);
into_lua(lua, &res)
}
pxs_VarType::pxs_Exception => {
let msg = var.get_string();
if msg.is_err() {
Err(mlua::Error::RuntimeError(msg.unwrap_err().to_string()))
} else {
Err(mlua::Error::RuntimeError(msg.unwrap()))
}
}
pxs_VarType::pxs_Map => {
let table = lua.create_table()?;
let map = var.get_map().unwrap();
let keys = map.keys();
for k in keys {
let item = map.get_item(k);
if let Some(item) = item {
let lua_key = into_lua(lua, k)?;
let lua_val = into_lua(lua, item)?;
table.set(lua_key, lua_val)?;
}
}
Ok(mlua::Value::Table(table))
}
}
}