use std::os::raw::{c_int, c_void};
use std::ptr;
use serde::{Deserialize, Serialize};
use crate::error::Result;
use crate::ffi;
use crate::lua::Lua;
use crate::table::Table;
use crate::util::{assert_stack, protect_lua, StackGuard};
use crate::value::Value;
pub trait LuaSerdeExt<'lua> {
fn null(&'lua self) -> Result<Value<'lua>>;
fn array_metatable(&'lua self) -> Result<Table<'lua>>;
fn to_value<T: Serialize + ?Sized>(&'lua self, t: &T) -> Result<Value<'lua>>;
fn from_value<T: Deserialize<'lua>>(&'lua self, value: Value<'lua>) -> Result<T>;
}
impl<'lua> LuaSerdeExt<'lua> for Lua {
fn null(&'lua self) -> Result<Value<'lua>> {
unsafe {
let _sg = StackGuard::new(self.state);
assert_stack(self.state, 3);
unsafe extern "C" fn push_null(state: *mut ffi::lua_State) -> c_int {
ffi::lua_pushlightuserdata(state, ptr::null_mut());
1
}
protect_lua(self.state, 0, push_null)?;
Ok(self.pop_value())
}
}
fn array_metatable(&'lua self) -> Result<Table<'lua>> {
unsafe {
let _sg = StackGuard::new(self.state);
assert_stack(self.state, 3);
unsafe extern "C" fn get_array_mt(state: *mut ffi::lua_State) -> c_int {
push_array_metatable(state);
1
}
protect_lua(self.state, 0, get_array_mt)?;
Ok(Table(self.pop_ref()))
}
}
fn to_value<T>(&'lua self, t: &T) -> Result<Value<'lua>>
where
T: Serialize + ?Sized,
{
t.serialize(ser::Serializer(self))
}
fn from_value<T>(&'lua self, value: Value<'lua>) -> Result<T>
where
T: Deserialize<'lua>,
{
T::deserialize(de::Deserializer(value))
}
}
pub(crate) unsafe fn init_metatables(state: *mut ffi::lua_State) {
ffi::lua_pushlightuserdata(
state,
&ARRAY_METATABLE_REGISTRY_KEY as *const u8 as *mut c_void,
);
ffi::lua_newtable(state);
ffi::lua_pushstring(state, cstr!("__metatable"));
ffi::lua_pushboolean(state, 0);
ffi::lua_rawset(state, -3);
ffi::lua_rawset(state, ffi::LUA_REGISTRYINDEX);
}
pub(crate) unsafe fn push_array_metatable(state: *mut ffi::lua_State) {
let key = &ARRAY_METATABLE_REGISTRY_KEY as *const u8 as *mut c_void;
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, key);
}
static ARRAY_METATABLE_REGISTRY_KEY: u8 = 0;
pub mod de;
pub mod ser;