make it possible to provide references of rust types to lua
This commit is contained in:
parent
6c9798eb5b
commit
03e81f5553
|
@ -1,6 +1,6 @@
|
|||
use std::borrow::{Borrow, Cow};
|
||||
|
||||
use crate::{AsLua, FromLua, Function, State};
|
||||
use crate::{FromLua, Function, IntoLuaVec, State};
|
||||
|
||||
pub struct Chunk<'a> {
|
||||
state: &'a State,
|
||||
|
@ -38,7 +38,7 @@ impl<'a> Chunk<'a> {
|
|||
/// Execute the chunk in the Lua context
|
||||
pub fn execute<A, R>(&'a self, args: A) -> crate::Result<R>
|
||||
where
|
||||
A: AsLua<'a>,
|
||||
A: IntoLuaVec<'a>,
|
||||
R: FromLua<'a>
|
||||
{
|
||||
self.state.execute_chunk::<A, R>(self, args)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use crate::{AsLua, FromLua, FromLuaStack, LuaRef, PushToLuaStack, StackGuard, State, Value, ValueVec};
|
||||
use crate::{AsLua, FromLua, FromLuaStack, IntoLuaVec, LuaRef, PushToLuaStack, StackGuard, State, Value, ValueVec};
|
||||
|
||||
use mlua_sys as lua;
|
||||
|
||||
|
@ -38,19 +38,15 @@ impl<'a> Function<'a> {
|
|||
|
||||
pub fn exec<A, R>(&self, args: A) -> crate::Result<R>
|
||||
where
|
||||
A: AsLua<'a>,
|
||||
A: IntoLuaVec<'a>,
|
||||
R: FromLua<'a>,
|
||||
{
|
||||
unsafe {
|
||||
let _g = StackGuard::new(self.state);
|
||||
let s = self.state.state_ptr();
|
||||
|
||||
let args_val = args.as_lua(self.state)?;
|
||||
let args_len = match args_val {
|
||||
Value::Variable(v) => v.len(),
|
||||
Value::None => 0,
|
||||
_ => 1,
|
||||
} as _;
|
||||
let args_val = args.into_lua_value_vec(self.state)?;
|
||||
let args_len = args_val.len() as _;
|
||||
|
||||
self.state.ensure_stack(2 + args_len)?;
|
||||
|
||||
|
@ -64,7 +60,8 @@ impl<'a> Function<'a> {
|
|||
|
||||
self.push_to_lua_stack(self.state)?;
|
||||
|
||||
let args_val = args.as_lua(self.state)?;
|
||||
/* let args_val = args.into_lua_value_vec(self.state)?;
|
||||
args_val.push_to_lua_stack(self.state)?; */
|
||||
args_val.push_to_lua_stack(self.state)?;
|
||||
|
||||
match lua::lua_pcall(s, args_len, lua::LUA_MULTRET, handler_idx) {
|
||||
|
@ -100,4 +97,10 @@ impl<'a> AsLua<'a> for Function<'a> {
|
|||
fn as_lua(&self, _lua: &'a State) -> crate::Result<crate::Value<'a>> {
|
||||
Ok(crate::Value::Function(self.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromLua<'a> for Function<'a> {
|
||||
fn from_lua(_lua: &'a State, val: Value<'a>) -> crate::Result<Self> {
|
||||
val.into_function()
|
||||
}
|
||||
}
|
174
src/main.rs
174
src/main.rs
|
@ -1,4 +1,4 @@
|
|||
use std::{cell::Ref, marker::PhantomData, sync::Arc};
|
||||
use std::{cell::{Ref, RefCell}, marker::PhantomData, mem, sync::Arc};
|
||||
|
||||
use mlua_sys as lua;
|
||||
|
||||
|
@ -43,100 +43,63 @@ fn main() -> Result<()> {
|
|||
let f = lua.create_function(a)?;
|
||||
globals.set("native_test", f)?;
|
||||
|
||||
let ud = lua.create_userdata(UserdataProxy::<Vec2>::new())?;
|
||||
globals.set("Vec2", ud)?;
|
||||
/* let ud = lua.create_userdata(UserdataProxy::<Vec2>::new())?;
|
||||
globals.set("Vec2", ud)?; */
|
||||
|
||||
let tbl = lua.create_table()?;
|
||||
tbl.set("x", 10)?;
|
||||
let cell = RefCell::new(Vec2 {
|
||||
x: 50.0,
|
||||
y: 5.0
|
||||
});
|
||||
|
||||
//let globals = lua.globals()?;
|
||||
globals.set("X", tbl)?;
|
||||
{
|
||||
let ud = lua.create_userdata(UserdataRef {
|
||||
ud_ptr: unsafe {
|
||||
mem::transmute::<Ref<Vec2>, Ref<Vec2>>(cell.borrow())
|
||||
},
|
||||
})?;
|
||||
globals.set("vec2", ud)?;
|
||||
}
|
||||
|
||||
let chunk = lua.load("text.lua", r#"
|
||||
require "util"
|
||||
|
||||
--[[function dump_table(tbl)
|
||||
for k, v in pairs(tbl) do
|
||||
if type(v) == "table" then
|
||||
dump_table(v)
|
||||
elseif type(v) == "function" then
|
||||
|
||||
else
|
||||
print(k .. "=" .. tostring(v))
|
||||
end
|
||||
|
||||
end
|
||||
if vec2 ~= nil then
|
||||
print("vec2: (" .. vec2.x .. ", " .. vec2.y .. ")")
|
||||
end
|
||||
|
||||
for k, v in pairs(_G) do
|
||||
--print("Found global named " .. k)
|
||||
|
||||
if k == "X" then
|
||||
--dump_table(v)
|
||||
end
|
||||
end]]--
|
||||
|
||||
function multiply_print(a, b)
|
||||
print(a .. " * " .. b .. " = " .. a*b)
|
||||
end
|
||||
|
||||
function multiply_ret(a, b)
|
||||
return a * b
|
||||
end
|
||||
|
||||
function say_number(a)
|
||||
print("Lua says " .. a)
|
||||
end
|
||||
|
||||
cool_num = 50
|
||||
|
||||
print("Lua is about to exec native_test")
|
||||
local res = native_test(50)
|
||||
print("Lua got " .. res .. " back from rust!")
|
||||
|
||||
print("Vec2: " .. dump_table(Vec2))
|
||||
print("Meta Vec2: " .. dump_table(getmetatable(Vec2)))
|
||||
|
||||
--print("Vec2 is (" .. Vec2.x .. ", " .. Vec2.y .. ")")
|
||||
|
||||
local v1 = Vec2.new(50, 50)
|
||||
print("v1 is (" .. v1.x .. ", " .. v1.y .. ")")
|
||||
|
||||
local v2 = Vec2.new(500, 500)
|
||||
print("v2 is (" .. v2.x .. ", " .. v2.y .. ")")
|
||||
|
||||
local v_add = v1 + v2
|
||||
v_add.x = 90
|
||||
print("v_add is (" .. v_add.x .. ", " .. v_add.y .. ")")
|
||||
|
||||
function f1(v1, v2)
|
||||
--print("f1 tb: " .. debug.traceback(1))
|
||||
local v_add = v1:add(v2)
|
||||
end
|
||||
|
||||
function f2(v1, v2)
|
||||
--print("f2 tb: " .. debug.traceback(1))
|
||||
f1(v1, v2)
|
||||
end
|
||||
|
||||
function f3(v1, v2)
|
||||
--print("f3 tb: " .. debug.traceback(1))
|
||||
f2(v1, v2)
|
||||
end
|
||||
|
||||
--f3(v1, v2)
|
||||
--print("vec2.x = " .. vec2.x)
|
||||
--print("vec2.y = " .. vec2.y)
|
||||
"#)?;
|
||||
|
||||
// I don't care about the result of this execution, so I set the result as a
|
||||
// Value which can be anything
|
||||
//
|
||||
// Chunks can also be executed with: `chunk.execute(())?;`
|
||||
let res = lua.execute_chunk::<_, Value>(&chunk, ());
|
||||
for _ in 0..2 {
|
||||
// I don't care about the result of this execution, so I set the result as a
|
||||
// Value which can be anything
|
||||
//
|
||||
// Chunks can also be executed with: `chunk.execute(())?;`
|
||||
let res = lua.execute_chunk::<_, Value>(&chunk, ());
|
||||
|
||||
// if unwrapped, the new lines in the message would be escaped making
|
||||
// the traceback in the error difficult to read.
|
||||
if let Err(e) = res {
|
||||
panic!("{}", e);
|
||||
// if unwrapped, the new lines in the message would be escaped making
|
||||
// the traceback in the error difficult to read.
|
||||
if let Err(e) = res {
|
||||
panic!("{}", e);
|
||||
}
|
||||
|
||||
let vec2 = globals.get::<_, AnyUserdata>("vec2")?;
|
||||
vec2.garbage_collect()?;
|
||||
globals.set("vec2", Value::Nil)?;
|
||||
|
||||
let mut t = cell.borrow_mut();
|
||||
t.x += 50.0;
|
||||
t.y += 5.0;
|
||||
drop(t);
|
||||
|
||||
let ud = lua.create_userdata(UserdataRef {
|
||||
// TODO: avoid unsafe here
|
||||
ud_ptr: unsafe {
|
||||
mem::transmute::<Ref<Vec2>, Ref<Vec2>>(cell.borrow())
|
||||
},
|
||||
})?;
|
||||
globals.raw_set("vec2", ud)?;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
|
@ -310,7 +273,7 @@ pub struct Vec3 {
|
|||
}
|
||||
|
||||
impl Userdata for Vec3 {
|
||||
fn build<'a>(_builder: &mut UserdataBuilder<'a, Self>) -> crate::Result<()> {
|
||||
fn build<'a>(_state: &State, _builder: &mut UserdataBuilder<'a, Self>) -> crate::Result<()> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
@ -325,7 +288,7 @@ pub struct Vec2 {
|
|||
}
|
||||
|
||||
impl Userdata for Vec2 {
|
||||
fn build<'a>(builder: &mut UserdataBuilder<'a, Vec2>) -> crate::Result<()> {
|
||||
fn build<'a>(_state: &State, builder: &mut UserdataBuilder<'a, Vec2>) -> crate::Result<()> {
|
||||
builder
|
||||
.field_getter("x", |_, this| Ok(this.x))
|
||||
.field_getter("y", |_, this| Ok(this.y))
|
||||
|
@ -381,9 +344,9 @@ impl<'a, T: Userdata> AsLua<'a> for UserdataProxy<T> {
|
|||
}
|
||||
|
||||
impl<T: Userdata> Userdata for UserdataProxy<T> {
|
||||
fn build<'a>(builder: &mut UserdataBuilder<'a, Self>) -> crate::Result<()> {
|
||||
fn build<'a>(state: &State, builder: &mut UserdataBuilder<'a, Self>) -> crate::Result<()> {
|
||||
let mut other = UserdataBuilder::<T>::new();
|
||||
T::build(&mut other)?;
|
||||
T::build(state, &mut other)?;
|
||||
|
||||
// only the functions need to be added since they're the only thing usable from a proxy
|
||||
builder.functions = other.functions;
|
||||
|
@ -395,4 +358,39 @@ impl<T: Userdata> Userdata for UserdataProxy<T> {
|
|||
let name = format!("{}Proxy", T::name());
|
||||
name
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UserdataRef<'a, T: Userdata> {
|
||||
ud_ptr: Ref<'a, T>
|
||||
}
|
||||
|
||||
impl<'a, T: Userdata + 'static> Userdata for UserdataRef<'a, T> {
|
||||
fn build<'b>(state: &State, builder: &mut UserdataBuilder<'b, Self>) -> crate::Result<()> {
|
||||
let mut other = UserdataBuilder::<T>::new();
|
||||
T::build(state, &mut other)?;
|
||||
|
||||
builder.expand_with(other);
|
||||
|
||||
let getter: fn(AnyUserdata<'_>) -> Result<*const ()> = move |ud: AnyUserdata| {
|
||||
let ud_ptr = {
|
||||
let ud = ud.as_ref::<UserdataRef<T>>()?;
|
||||
|
||||
let ud_ptr: *const T = &*ud.ud_ptr;
|
||||
ud_ptr
|
||||
};
|
||||
|
||||
Ok(ud_ptr.cast::<()>())
|
||||
};
|
||||
|
||||
if builder.wrapped_getter.set(Box::new(getter)).is_err() {
|
||||
panic!("Somehow the wrapped getter has already been set");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn name() -> String {
|
||||
let name = format!("{}Ref", T::name());
|
||||
name
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ use std::{alloc::{self, Layout}, any::TypeId, cell::RefCell, collections::HashMa
|
|||
|
||||
use mlua_sys as lua;
|
||||
|
||||
use crate::{lua_error_guard, AnyUserdata, IntoChunkData, AsLua, Chunk, Error, FromLua, FromLuaStack, FromLuaVec, Function, LuaRef, MetaMethod, PushToLuaStack, Result, StackGuard, Table, Userdata, UserdataBuilder, Value, ValueVec};
|
||||
use crate::{lua_error_guard, AnyUserdata, AsLua, Chunk, Error, FromLua, FromLuaStack, FromLuaVec, Function, IntoChunkData, IntoLuaVec, LuaRef, MetaMethod, PushToLuaStack, Result, StackGuard, Table, Userdata, UserdataBuilder, Value, ValueVec};
|
||||
|
||||
pub fn ptr_to_string(ptr: *const i8) -> std::result::Result<String, Utf8Error> {
|
||||
let c = unsafe { CStr::from_ptr(ptr) };
|
||||
|
@ -212,7 +212,7 @@ impl State {
|
|||
|
||||
pub fn execute_chunk<'a, A, R>(&'a self, chunk: &'a Chunk, args: A) -> Result<R>
|
||||
where
|
||||
A: AsLua<'a>,
|
||||
A: IntoLuaVec<'a>,
|
||||
R: FromLua<'a>
|
||||
{
|
||||
let handler = self.create_function(|lua, msg: String| {
|
||||
|
@ -431,7 +431,7 @@ impl State {
|
|||
|
||||
pub(crate) fn create_userdata_metatable<'a, T: Userdata + 'static>(&'a self) -> Result<Table<'a>> {
|
||||
let mut builder = UserdataBuilder::<T>::new();
|
||||
T::build(&mut builder)?;
|
||||
T::build(self, &mut builder)?;
|
||||
|
||||
let getters = builder.field_getters;
|
||||
let setters = builder.field_setters;
|
||||
|
@ -502,10 +502,11 @@ impl State {
|
|||
let ud_ptr = ud.as_ptr_unchecked::<T>().unwrap();
|
||||
ud_ptr.drop_in_place();
|
||||
|
||||
lua::luaL_unref(lua.state_ptr(), lua::LUA_REGISTRYINDEX, *ud.lref.0);
|
||||
lua::luaL_unref(lua.state_ptr(), lua::LUA_REGISTRYINDEX, *ud.unsafe_ud.lref.0);
|
||||
|
||||
let extra = lua.get_extra_space();
|
||||
extra.userdata_metatables.remove(&TypeId::of::<T>());
|
||||
//todo!()
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
74
src/table.rs
74
src/table.rs
|
@ -1,7 +1,7 @@
|
|||
|
||||
use mlua_sys as lua;
|
||||
|
||||
use crate::{ensure_type, FromLuaStack, LuaRef, PushToLuaStack, Result, StackGuard, State};
|
||||
use crate::{ensure_type, AsLua, FromLua, FromLuaStack, LuaRef, PushToLuaStack, Result, StackGuard, State, Value};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Table<'a> {
|
||||
|
@ -83,8 +83,8 @@ impl<'a> Table<'a> {
|
|||
/// This may trigger the `__newindex` metamethod, see [`Table::raw_set`]
|
||||
pub fn set<K, V>(&self, key: K, val: V) -> Result<()>
|
||||
where
|
||||
K: PushToLuaStack<'a>,
|
||||
V: PushToLuaStack<'a>
|
||||
K: AsLua<'a>,
|
||||
V: AsLua<'a>
|
||||
{
|
||||
let s = self.state.state_ptr();
|
||||
unsafe {
|
||||
|
@ -97,8 +97,10 @@ impl<'a> Table<'a> {
|
|||
}
|
||||
|
||||
self.lref.push_to_lua_stack(self.state)?;
|
||||
key.push_to_lua_stack(self.state)?;
|
||||
val.push_to_lua_stack(self.state)?;
|
||||
key.as_lua(self.state)?
|
||||
.push_to_lua_stack(self.state)?;
|
||||
val.as_lua(self.state)?
|
||||
.push_to_lua_stack(self.state)?;
|
||||
|
||||
lua::lua_settable(s, -3);
|
||||
}
|
||||
|
@ -111,8 +113,8 @@ impl<'a> Table<'a> {
|
|||
/// This may trigger the `__index` metamethod, see [`Table::raw_get`]
|
||||
pub fn get<K, V>(&self, key: K) -> Result<V>
|
||||
where
|
||||
K: PushToLuaStack<'a>,
|
||||
V: FromLuaStack<'a>,
|
||||
K: AsLua<'a>,
|
||||
V: FromLua<'a>,
|
||||
{
|
||||
let s = self.state.state_ptr();
|
||||
unsafe {
|
||||
|
@ -120,10 +122,13 @@ impl<'a> Table<'a> {
|
|||
let _g = StackGuard::new(self.state);
|
||||
|
||||
self.lref.push_to_lua_stack(self.state)?;
|
||||
key.push_to_lua_stack(self.state)?;
|
||||
let val = key.as_lua(self.state)?;
|
||||
val.push_to_lua_stack(self.state)?;
|
||||
|
||||
lua::lua_gettable(s, -2); // table[key] is at top of stack
|
||||
|
||||
let val = V::from_lua_stack(self.state)?;
|
||||
let val = Value::from_lua_stack(self.state)?;
|
||||
let val = V::from_lua(self.state, val)?;
|
||||
|
||||
Ok(val)
|
||||
}
|
||||
|
@ -150,7 +155,7 @@ impl<'a> Table<'a> {
|
|||
/// Returns a boolean indicating if this table has a key
|
||||
pub fn has_key<K>(&self, key: K) -> Result<bool>
|
||||
where
|
||||
K: PushToLuaStack<'a>,
|
||||
K: AsLua<'a>,
|
||||
{
|
||||
let s = self.state.state_ptr();
|
||||
unsafe {
|
||||
|
@ -158,7 +163,8 @@ impl<'a> Table<'a> {
|
|||
let _g = StackGuard::new(self.state);
|
||||
|
||||
self.lref.push_to_lua_stack(self.state)?;
|
||||
key.push_to_lua_stack(self.state)?;
|
||||
let key_val = key.as_lua(self.state)?;
|
||||
key_val.push_to_lua_stack(self.state)?;
|
||||
|
||||
// table[key] is at top of stack
|
||||
if lua::lua_gettable(s, -2) == lua::LUA_TNIL {
|
||||
|
@ -172,8 +178,8 @@ impl<'a> Table<'a> {
|
|||
/// Set a key to a value in the table without calling any meta methods.
|
||||
pub fn raw_set<K, V>(&self, key: K, val: V) -> Result<()>
|
||||
where
|
||||
K: PushToLuaStack<'a>,
|
||||
V: PushToLuaStack<'a>
|
||||
K: AsLua<'a>,
|
||||
V: AsLua<'a>
|
||||
{
|
||||
let s = self.state.state_ptr();
|
||||
unsafe {
|
||||
|
@ -181,8 +187,10 @@ impl<'a> Table<'a> {
|
|||
let _g = StackGuard::new(self.state);
|
||||
|
||||
self.lref.push_to_lua_stack(self.state)?;
|
||||
key.push_to_lua_stack(self.state)?;
|
||||
val.push_to_lua_stack(self.state)?;
|
||||
key.as_lua(self.state)?
|
||||
.push_to_lua_stack(self.state)?;
|
||||
val.as_lua(self.state)?
|
||||
.push_to_lua_stack(self.state)?;
|
||||
|
||||
lua::lua_rawset(s, -3);
|
||||
}
|
||||
|
@ -191,10 +199,10 @@ impl<'a> Table<'a> {
|
|||
}
|
||||
|
||||
/// Get a value from the table without calling any meta methods.
|
||||
pub fn raw_get<K, V>(&'a self, key: K) -> Result<V>
|
||||
pub fn raw_get<K, V>(&self, key: K) -> Result<V>
|
||||
where
|
||||
K: PushToLuaStack<'a>,
|
||||
V: FromLuaStack<'a>,
|
||||
K: AsLua<'a>,
|
||||
V: FromLua<'a>,
|
||||
{
|
||||
let s = self.state.state_ptr();
|
||||
unsafe {
|
||||
|
@ -202,9 +210,13 @@ impl<'a> Table<'a> {
|
|||
let _g = StackGuard::new(self.state);
|
||||
|
||||
self.lref.push_to_lua_stack(self.state)?;
|
||||
key.push_to_lua_stack(self.state)?;
|
||||
key.as_lua(self.state)?
|
||||
.push_to_lua_stack(self.state)?;
|
||||
|
||||
lua::lua_rawget(s, -2); // table[key] is at top of stack
|
||||
V::from_lua_stack(self.state)
|
||||
|
||||
let val = Value::from_lua_stack(self.state)?;
|
||||
V::from_lua(self.state, val)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -226,7 +238,7 @@ impl<'a> Table<'a> {
|
|||
/// Returns a boolean indicating if this table has a key without calling any meta methods.
|
||||
pub fn raw_has_key<K>(&self, key: K) -> Result<bool>
|
||||
where
|
||||
K: PushToLuaStack<'a>,
|
||||
K: AsLua<'a>,
|
||||
{
|
||||
let s = self.state.state_ptr();
|
||||
unsafe {
|
||||
|
@ -234,7 +246,9 @@ impl<'a> Table<'a> {
|
|||
let _g = StackGuard::new(self.state);
|
||||
|
||||
self.lref.push_to_lua_stack(self.state)?;
|
||||
key.push_to_lua_stack(self.state)?;
|
||||
key.as_lua(self.state)?
|
||||
.push_to_lua_stack(self.state)?;
|
||||
|
||||
// table[key] is at top of stack
|
||||
Ok(lua::lua_rawget(s, -2) != lua::LUA_TNIL)
|
||||
}
|
||||
|
@ -245,8 +259,8 @@ impl<'a> Table<'a> {
|
|||
/// Does nothing if this table is not a metatable
|
||||
pub fn set_meta<K, V>(&self, key: K, val: V) -> Result<()>
|
||||
where
|
||||
K: PushToLuaStack<'a>,
|
||||
V: PushToLuaStack<'a>
|
||||
K: AsLua<'a>,
|
||||
V: AsLua<'a>
|
||||
{
|
||||
if self.mt_marker {
|
||||
unsafe {
|
||||
|
@ -255,8 +269,10 @@ impl<'a> Table<'a> {
|
|||
let _g = StackGuard::new(self.state);
|
||||
|
||||
self.lref.push_to_lua_stack(self.state)?;
|
||||
key.push_to_lua_stack(self.state)?;
|
||||
val.push_to_lua_stack(self.state)?;
|
||||
key.as_lua(self.state)?
|
||||
.push_to_lua_stack(self.state)?;
|
||||
val.as_lua(self.state)?
|
||||
.push_to_lua_stack(self.state)?;
|
||||
lua::lua_settable(s, -3);
|
||||
}
|
||||
}
|
||||
|
@ -279,4 +295,10 @@ impl<'a> FromLuaStack<'a> for Table<'a> {
|
|||
ensure_type(state, lua::LUA_TTABLE, -1)?;
|
||||
Table::with_ref(state, LuaRef::from_stack(state)?, false)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromLua<'a> for Table<'a> {
|
||||
fn from_lua(_lua: &'a State, val: Value<'a>) -> crate::Result<Self> {
|
||||
val.into_table()
|
||||
}
|
||||
}
|
|
@ -1,9 +1,12 @@
|
|||
use std::{cell::{Ref, RefCell, RefMut}, collections::HashMap, ffi::CStr, marker::PhantomData, ops::DerefMut};
|
||||
use std::{cell::{OnceCell, Ref, RefCell, RefMut}, collections::HashMap, ffi::CStr, marker::PhantomData, mem, ops::{Deref, DerefMut}, sync::Arc};
|
||||
|
||||
use crate::{ensure_type, AsLua, FromLua, FromLuaStack, FromLuaVec, LuaRef, PushToLuaStack, StackGuard, State, Value, ValueVec};
|
||||
use crate::{ensure_type, AsLua, FromLua, FromLuaStack, FromLuaVec, Function, IntoLuaVec, LuaRef, PushToLuaStack, StackGuard, State, Table, Value, ValueVec};
|
||||
|
||||
use mlua_sys as lua;
|
||||
|
||||
pub mod unsafe_ud;
|
||||
pub use unsafe_ud::*;
|
||||
|
||||
/// An enum representing all Lua MetaMethods
|
||||
/// https://gist.github.com/oatmealine/655c9e64599d0f0dd47687c1186de99f
|
||||
pub enum MetaMethod {
|
||||
|
@ -89,7 +92,7 @@ impl<'a> PushToLuaStack<'a> for MetaMethod {
|
|||
}
|
||||
}
|
||||
|
||||
type UserdataFn<'a> = Box<dyn Fn(&'a State, ValueVec<'a>) -> crate::Result<Value<'a>>>;
|
||||
pub type UserdataFn<'a> = Box<dyn Fn(&'a State, ValueVec<'a>) -> crate::Result<Value<'a>>>;
|
||||
|
||||
pub struct UserdataBuilder<'a, T> {
|
||||
pub(crate) name: String,
|
||||
|
@ -97,6 +100,9 @@ pub struct UserdataBuilder<'a, T> {
|
|||
pub(crate) field_setters: HashMap<String, UserdataFn<'a>>,
|
||||
pub(crate) functions: HashMap<String, UserdataFn<'a>>,
|
||||
pub(crate) meta_methods: HashMap<String, UserdataFn<'a>>,
|
||||
|
||||
pub(crate) wrapped_getter: Arc<OnceCell<Box<dyn Fn(AnyUserdata<'a>) -> crate::Result<*const ()>>>>,
|
||||
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
|
@ -108,6 +114,7 @@ impl<'a, T: Userdata> UserdataBuilder<'a, T> {
|
|||
field_setters: HashMap::new(),
|
||||
functions: HashMap::new(),
|
||||
meta_methods: HashMap::new(),
|
||||
wrapped_getter: Arc::new(OnceCell::new()),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
@ -118,11 +125,34 @@ impl<'a, T: Userdata> UserdataBuilder<'a, T> {
|
|||
R: AsLua<'a>,
|
||||
T: Userdata + 'static
|
||||
{
|
||||
let wrapped = self.wrapped_getter.clone();
|
||||
let wrapped: Arc<OnceCell<Box<dyn Fn(AnyUserdata<'_>) -> Result<*const (), crate::Error>>>> = unsafe { mem::transmute(wrapped) };
|
||||
let fn_name = Arc::new(name.to_string());
|
||||
|
||||
let wrap = move |lua: &'a State, mut val: ValueVec<'a>| {
|
||||
let val = val.pop_front().unwrap();
|
||||
let this = val.as_userdata().unwrap(); // if this panics, its a bug
|
||||
let this = this.as_ref::<T>()?;
|
||||
f(lua, &*this).and_then(|r| r.as_lua(lua))
|
||||
|
||||
if let Some(getter) = wrapped.get() {
|
||||
let this_ptr = match getter(this.clone()) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
return Err(crate::Error::BadArgument {
|
||||
func: Some(fn_name.deref().clone()),
|
||||
arg_index: 1,
|
||||
arg_name: Some("self".to_string()),
|
||||
error: Arc::new(e),
|
||||
});
|
||||
}
|
||||
};
|
||||
let this_ptr = this_ptr.cast::<T>();
|
||||
let this = unsafe { &*this_ptr };
|
||||
|
||||
f(lua, this).and_then(|r| r.as_lua(lua))
|
||||
} else {
|
||||
let this = this.as_ref::<T>()?;
|
||||
f(lua, &*this).and_then(|r| r.as_lua(lua))
|
||||
}
|
||||
};
|
||||
self.field_getters.insert(name.to_string(), Box::new(wrap));
|
||||
|
||||
|
@ -192,6 +222,7 @@ impl<'a, T: Userdata> UserdataBuilder<'a, T> {
|
|||
let wrap = move |lua: &'a State, mut val: ValueVec<'a>| {
|
||||
let this_val = val.pop_front().unwrap();
|
||||
let this = this_val.as_userdata().unwrap(); // if this panics, its a bug
|
||||
//this.unsafe_ud.as_ptr_unchecked()
|
||||
let this = this.as_ref::<T>()?;
|
||||
|
||||
let this_name = T::name();
|
||||
|
@ -233,78 +264,60 @@ impl<'a, T: Userdata> UserdataBuilder<'a, T> {
|
|||
|
||||
self
|
||||
}
|
||||
|
||||
//fn append_fields_from<S>(&mut self, other: UserDataRegistry<'lua, S>) {
|
||||
pub fn expand_with<U>(&mut self, other: UserdataBuilder<'a, U>) {
|
||||
self.field_getters = other.field_getters;
|
||||
self.field_setters = other.field_setters;
|
||||
self.functions = other.functions;
|
||||
self.meta_methods = other.meta_methods;
|
||||
self.wrapped_getter = other.wrapped_getter;
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Userdata: Sized {
|
||||
fn name() -> String;
|
||||
|
||||
fn build<'a>(builder: &mut UserdataBuilder<'a, Self>) -> crate::Result<()>;
|
||||
fn build<'a>(state: &State, builder: &mut UserdataBuilder<'a, Self>) -> crate::Result<()>;
|
||||
}
|
||||
|
||||
/// A handle to some userdata on the stack
|
||||
#[derive(Clone)]
|
||||
//#[derive(Clone)]
|
||||
pub struct AnyUserdata<'a> {
|
||||
pub(crate) lref: LuaRef<'a>,
|
||||
pub(crate) unsafe_ud: UnsafeUserdata<'a>,
|
||||
state: &'a State,
|
||||
}
|
||||
|
||||
impl<'a> Clone for AnyUserdata<'a> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
state: self.state,
|
||||
unsafe_ud: self.unsafe_ud.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AnyUserdata<'a> {
|
||||
pub fn from_ref(state: &'a State, lref: LuaRef<'a>) -> Self {
|
||||
Self {
|
||||
lref,
|
||||
state,
|
||||
unsafe_ud: UnsafeUserdata::from_ref(state, lref)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a borrow to the userdata.
|
||||
pub fn as_ref<T: Userdata + 'static>(&self) -> crate::Result<Ref<'a, T>> {
|
||||
unsafe {
|
||||
self.state.ensure_stack(3)?;
|
||||
let _g = StackGuard::new(self.state);
|
||||
let s = self.state.state_ptr();
|
||||
|
||||
self.lref.push_to_lua_stack(self.state)?;
|
||||
|
||||
if lua::lua_getmetatable(s, -1) == 0 {
|
||||
return Err(crate::Error::UserdataMismatch);
|
||||
}
|
||||
|
||||
self.state.get_userdata_metatable::<T>()
|
||||
.push_to_lua_stack(self.state)?;
|
||||
|
||||
if lua::lua_rawequal(s, -2, -1) == 1 {
|
||||
let cptr = lua::lua_touserdata(s, -3);
|
||||
let cell = &*cptr.cast::<RefCell<T>>();
|
||||
Ok(cell.borrow())
|
||||
} else {
|
||||
return Err(crate::Error::UserdataMismatch);
|
||||
}
|
||||
let cell = &*self.unsafe_ud.as_ptr_unchecked::<RefCell<T>>()?;
|
||||
Ok(cell.borrow())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the userdata.
|
||||
pub fn as_mut<T: Userdata + 'static>(&self) -> crate::Result<RefMut<'a, T>> {
|
||||
unsafe {
|
||||
self.state.ensure_stack(3)?;
|
||||
let _g = StackGuard::new(self.state);
|
||||
let s = self.state.state_ptr();
|
||||
|
||||
self.lref.push_to_lua_stack(self.state)?;
|
||||
|
||||
if lua::lua_getmetatable(s, -1) == 0 {
|
||||
return Err(crate::Error::MissingMetatable);
|
||||
}
|
||||
|
||||
self.state.get_userdata_metatable::<T>()
|
||||
.push_to_lua_stack(self.state)?;
|
||||
|
||||
if lua::lua_rawequal(s, -2, -1) == 1 {
|
||||
let cptr = lua::lua_touserdata(s, -3);
|
||||
let cell = &*cptr.cast::<RefCell<T>>();
|
||||
Ok(cell.borrow_mut())
|
||||
} else {
|
||||
Err(crate::Error::UserdataMismatch)
|
||||
}
|
||||
let cell = &*self.unsafe_ud.as_ptr_unchecked::<RefCell<T>>()?;
|
||||
Ok(cell.borrow_mut())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -317,14 +330,8 @@ impl<'a> AnyUserdata<'a> {
|
|||
/// If there is a possibility that these types do not match, use [`AnyUserdata::as_ptr`]
|
||||
/// which does verify the types.
|
||||
pub unsafe fn as_ptr_unchecked<T: Userdata + 'static>(&self) -> crate::Result<*mut RefCell<T>> {
|
||||
self.state.ensure_stack(1)?;
|
||||
let _g = StackGuard::new(self.state);
|
||||
let s = self.state.state_ptr();
|
||||
|
||||
self.lref.push_to_lua_stack(self.state)?;
|
||||
let cptr = lua::lua_touserdata(s, -3);
|
||||
|
||||
Ok(cptr.cast())
|
||||
let cell = self.unsafe_ud.as_ptr_unchecked::<RefCell<T>>()?;
|
||||
Ok(cell)
|
||||
}
|
||||
|
||||
/// Returns a mutable pointer of the [`RefCell`] storing the userdata.
|
||||
|
@ -335,7 +342,7 @@ impl<'a> AnyUserdata<'a> {
|
|||
let _g = StackGuard::new(self.state);
|
||||
let s = self.state.state_ptr();
|
||||
|
||||
self.lref.push_to_lua_stack(self.state)?;
|
||||
self.unsafe_ud.lref.push_to_lua_stack(self.state)?;
|
||||
|
||||
if lua::lua_getmetatable(s, -1) == 0 {
|
||||
return Err(crate::Error::MissingMetatable);
|
||||
|
@ -345,8 +352,9 @@ impl<'a> AnyUserdata<'a> {
|
|||
.push_to_lua_stack(self.state)?;
|
||||
|
||||
if lua::lua_rawequal(s, -2, -1) == 1 {
|
||||
let cptr = lua::lua_touserdata(s, -3);
|
||||
Ok(cptr.cast())
|
||||
drop(_g);
|
||||
let cell = self.unsafe_ud.as_ptr_unchecked::<RefCell<T>>()?;
|
||||
Ok(cell)
|
||||
} else {
|
||||
Err(crate::Error::UserdataMismatch)
|
||||
}
|
||||
|
@ -358,7 +366,7 @@ impl<'a> AnyUserdata<'a> {
|
|||
self.state.ensure_stack(3)?;
|
||||
let _g = StackGuard::new(self.state);
|
||||
|
||||
self.lref.push_to_lua_stack(self.state)?;
|
||||
self.unsafe_ud.lref.push_to_lua_stack(self.state)?;
|
||||
let s = self.state.state_ptr();
|
||||
|
||||
if lua::lua_getmetatable(s, -1) == 0 {
|
||||
|
@ -378,6 +386,69 @@ impl<'a> AnyUserdata<'a> {
|
|||
Ok(cstr.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the metatable of this userdata
|
||||
pub fn get_metatable(&self) -> crate::Result<Table<'a>> {
|
||||
unsafe {
|
||||
self.state.ensure_stack(2)?;
|
||||
let _g = StackGuard::new(self.state);
|
||||
|
||||
self.unsafe_ud.lref.push_to_lua_stack(self.state)?;
|
||||
let s = self.state.state_ptr();
|
||||
|
||||
if lua::lua_getmetatable(s, -1) == 0 {
|
||||
Err(crate::Error::MissingMetatable)
|
||||
} else {
|
||||
Ok(Table::from_lua_stack(self.state)?)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets something from the userdata.
|
||||
///
|
||||
/// Will trigger a call to the `__index` metamethod. Use [`AnyUserdata::raw_get`] if you
|
||||
/// don't want to call it.
|
||||
pub fn get<K, V>(&'a self, key: K) -> crate::Result<V>
|
||||
where
|
||||
K: AsLua<'a>,
|
||||
V: FromLua<'a>,
|
||||
{
|
||||
let mt = self.get_metatable()?;
|
||||
mt.get::<K, V>(key)
|
||||
}
|
||||
|
||||
/// Gets something from the userdata. Will **not** trigger a call to the `__index` metamethod.
|
||||
pub fn raw_get<K, V>(&'a self, key: K) -> crate::Result<V>
|
||||
where
|
||||
K: AsLua<'a>,
|
||||
V: FromLua<'a>,
|
||||
{
|
||||
let mt = self.get_metatable()?;
|
||||
mt.raw_get::<K, V>(key)
|
||||
}
|
||||
|
||||
/// Execute a method on this userdata. This finds a function with `name` and executes it
|
||||
/// with the userdata as the first argument.
|
||||
pub fn execute_method<A, R>(&self, name: &str, args: A) -> crate::Result<R>
|
||||
where
|
||||
A: IntoLuaVec<'a>,
|
||||
R: FromLua<'a>,
|
||||
{
|
||||
//let s: &Self = unsafe { mem::transmute(self) };
|
||||
let name = name.to_string();
|
||||
let mt = self.get_metatable()?;
|
||||
let f = mt.get::<_, Function>(name)?;
|
||||
|
||||
let mut args = args.into_lua_value_vec(self.state)?;
|
||||
args.push_front(self.clone().as_lua(self.state)?);
|
||||
|
||||
f.exec(args)
|
||||
}
|
||||
|
||||
/// Trigger garbage collection on the userdata.
|
||||
pub fn garbage_collect(self) -> crate::Result<()> {
|
||||
self.execute_method("__gc", ()).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromLuaStack<'a> for AnyUserdata<'a> {
|
||||
|
@ -385,15 +456,15 @@ impl<'a> FromLuaStack<'a> for AnyUserdata<'a> {
|
|||
ensure_type(state, lua::LUA_TUSERDATA, -1)?;
|
||||
|
||||
Ok(AnyUserdata {
|
||||
lref: LuaRef::from_stack(state)?,
|
||||
state,
|
||||
unsafe_ud: UnsafeUserdata::from_lua_stack(state)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PushToLuaStack<'a> for AnyUserdata<'a> {
|
||||
unsafe fn push_to_lua_stack(&self, state: &'a State) -> crate::Result<()> {
|
||||
self.lref.push_to_lua_stack(state)
|
||||
self.unsafe_ud.lref.push_to_lua_stack(state)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,180 @@
|
|||
use std::ffi::CStr;
|
||||
|
||||
use crate::{ensure_type, FromLuaStack, LuaRef, PushToLuaStack, StackGuard, State, Userdata};
|
||||
|
||||
use mlua_sys as lua;
|
||||
|
||||
pub struct UnsafeUserdata<'a> {
|
||||
pub(crate) lref: LuaRef<'a>,
|
||||
state: &'a State,
|
||||
}
|
||||
|
||||
impl<'a> Clone for UnsafeUserdata<'a> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
lref: self.lref.clone(),
|
||||
state: self.state,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> UnsafeUserdata<'a> {
|
||||
pub fn from_ref(state: &'a State, lref: LuaRef<'a>) -> Self {
|
||||
Self {
|
||||
lref,
|
||||
state,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a borrow to the userdata.
|
||||
pub fn as_ref<T: Userdata + 'static>(&self) -> crate::Result<&'a T> {
|
||||
unsafe {
|
||||
self.state.ensure_stack(3)?;
|
||||
let _g = StackGuard::new(self.state);
|
||||
let s = self.state.state_ptr();
|
||||
|
||||
self.lref.push_to_lua_stack(self.state)?;
|
||||
|
||||
if lua::lua_getmetatable(s, -1) == 0 {
|
||||
return Err(crate::Error::UserdataMismatch);
|
||||
}
|
||||
|
||||
self.state.get_userdata_metatable::<T>()
|
||||
.push_to_lua_stack(self.state)?;
|
||||
|
||||
if lua::lua_rawequal(s, -2, -1) == 1 {
|
||||
let cptr = lua::lua_touserdata(s, -3);
|
||||
let t = &*cptr.cast::<T>();
|
||||
Ok(t)
|
||||
} else {
|
||||
return Err(crate::Error::UserdataMismatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the userdata.
|
||||
pub fn as_mut<T: Userdata + 'static>(&self) -> crate::Result<&'a mut T> {
|
||||
unsafe {
|
||||
self.state.ensure_stack(3)?;
|
||||
let _g = StackGuard::new(self.state);
|
||||
let s = self.state.state_ptr();
|
||||
|
||||
self.lref.push_to_lua_stack(self.state)?;
|
||||
|
||||
if lua::lua_getmetatable(s, -1) == 0 {
|
||||
return Err(crate::Error::MissingMetatable);
|
||||
}
|
||||
|
||||
self.state.get_userdata_metatable::<T>()
|
||||
.push_to_lua_stack(self.state)?;
|
||||
|
||||
if lua::lua_rawequal(s, -2, -1) == 1 {
|
||||
let cptr = lua::lua_touserdata(s, -3);
|
||||
let t = &mut *cptr.cast::<T>();
|
||||
Ok(t)
|
||||
} else {
|
||||
Err(crate::Error::UserdataMismatch)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a mutable pointer of the [`RefCell`] of userdata **WITHOUT verifying the type of it**.
|
||||
///
|
||||
/// # Safety
|
||||
/// * You must be certain that the type `T` is the same type that this userdata has a handle to.
|
||||
/// There is a blind cast from `void*` to `T*`
|
||||
///
|
||||
/// If there is a possibility that these types do not match, use [`UnsafeUserdata::as_ptr`]
|
||||
/// which does verify the types.
|
||||
pub unsafe fn as_ptr_unchecked<T>(&self) -> crate::Result<*mut T> {
|
||||
self.state.ensure_stack(1)?;
|
||||
let _g = StackGuard::new(self.state);
|
||||
let s = self.state.state_ptr();
|
||||
|
||||
self.lref.push_to_lua_stack(self.state)?;
|
||||
let cptr = lua::lua_touserdata(s, -1);
|
||||
|
||||
Ok(cptr.cast())
|
||||
}
|
||||
|
||||
/// Returns a mutable pointer of the data stored.
|
||||
///
|
||||
/// This function ensures that the type of the userdata this struct has a handle to is the
|
||||
/// same as `T`. If it isn't, a `UserdataMismatch` error will be returned.
|
||||
pub unsafe fn as_ptr<T: Userdata + 'static>(&self) -> crate::Result<*mut T> {
|
||||
let _g = StackGuard::new(self.state);
|
||||
let s = self.state.state_ptr();
|
||||
|
||||
self.lref.push_to_lua_stack(self.state)?;
|
||||
|
||||
if lua::lua_getmetatable(s, -1) == 0 {
|
||||
return Err(crate::Error::MissingMetatable);
|
||||
}
|
||||
|
||||
self.state.get_userdata_metatable::<T>()
|
||||
.push_to_lua_stack(self.state)?;
|
||||
|
||||
if lua::lua_rawequal(s, -2, -1) == 1 {
|
||||
let cptr = lua::lua_touserdata(s, -3);
|
||||
Ok(cptr.cast())
|
||||
} else {
|
||||
Err(crate::Error::UserdataMismatch)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the name of the userdata by accessing the metatable
|
||||
pub fn name(&self) -> crate::Result<String> {
|
||||
unsafe {
|
||||
self.state.ensure_stack(3)?;
|
||||
let _g = StackGuard::new(self.state);
|
||||
|
||||
self.lref.push_to_lua_stack(self.state)?;
|
||||
let s = self.state.state_ptr();
|
||||
|
||||
if lua::lua_getmetatable(s, -1) == 0 {
|
||||
return Err(crate::Error::MissingMetatable);
|
||||
}
|
||||
|
||||
lua::lua_pushliteral(s, "__name");
|
||||
lua::lua_rawget(s, -2);
|
||||
|
||||
ensure_type(self.state, lua::LUA_TSTRING, -1)?;
|
||||
|
||||
let cstr = CStr::from_ptr(lua::lua_tostring(s, -1));
|
||||
let cstr = cstr.to_str()
|
||||
// on panic, this should be considered a bug
|
||||
.expect("Metatable name has invalid utf8 bytes!");
|
||||
|
||||
Ok(cstr.to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromLuaStack<'a> for UnsafeUserdata<'a> {
|
||||
unsafe fn from_lua_stack(state: &'a State) -> crate::Result<Self> {
|
||||
ensure_type(state, lua::LUA_TUSERDATA, -1)?;
|
||||
|
||||
Ok(UnsafeUserdata {
|
||||
lref: LuaRef::from_stack(state)?,
|
||||
state,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PushToLuaStack<'a> for UnsafeUserdata<'a> {
|
||||
unsafe fn push_to_lua_stack(&self, state: &'a State) -> crate::Result<()> {
|
||||
self.lref.push_to_lua_stack(state)
|
||||
}
|
||||
}
|
||||
|
||||
/* impl<'a> AsLua<'a> for UnsafeUserdata<'a> {
|
||||
fn as_lua(&self, _lua: &'a State) -> crate::Result<Value<'a>> {
|
||||
Ok(Value::Userdata(self.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromLua<'a> for UnsafeUserdata<'a> {
|
||||
fn from_lua(_lua: &State, val: Value<'a>) -> crate::Result<Self> {
|
||||
val.into_userdata()
|
||||
}
|
||||
} */
|
38
src/value.rs
38
src/value.rs
|
@ -36,7 +36,7 @@ impl<'a> Value<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn as_userdata(&self) -> crate::Result<&AnyUserdata> {
|
||||
pub fn as_userdata(&self) -> crate::Result<&AnyUserdata<'a>> {
|
||||
match self {
|
||||
Value::Userdata(ud) => Ok(ud),
|
||||
_ => {
|
||||
|
@ -74,10 +74,28 @@ impl<'a> Value<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_table(self) -> crate::Result<Table<'a>> {
|
||||
match self {
|
||||
Value::Table(v) => Ok(v),
|
||||
_ => {
|
||||
Err(crate::Error::UnexpectedType("Table".to_string(), self.type_name().to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_function(self) -> crate::Result<Function<'a>> {
|
||||
match self {
|
||||
Value::Function(v) => Ok(v),
|
||||
_ => {
|
||||
Err(crate::Error::UnexpectedType("Function".to_string(), self.type_name().to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PushToLuaStack<'a> for Value<'a> {
|
||||
unsafe fn push_to_lua_stack(&self, state: &crate::State) -> crate::Result<()> {
|
||||
unsafe fn push_to_lua_stack(&self, state: &'a crate::State) -> crate::Result<()> {
|
||||
let s = state.state_ptr();
|
||||
|
||||
match self {
|
||||
|
@ -304,6 +322,16 @@ impl<'a> FromLuaVec<'a> for ValueVec<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> PushToLuaStack<'a> for ValueVec<'a> {
|
||||
unsafe fn push_to_lua_stack(&self, state: &'a State) -> crate::Result<()> {
|
||||
for v in self.iter() {
|
||||
v.push_to_lua_stack(state)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: FromLua<'a>> FromLuaVec<'a> for T {
|
||||
fn from_lua_value_vec(state: &'a State, mut values: ValueVec<'a>) -> crate::Result<Self> {
|
||||
if let Some(val) = values.pop_front() {
|
||||
|
@ -317,6 +345,12 @@ impl<'a, T: FromLua<'a>> FromLuaVec<'a> for T {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoLuaVec<'a> for () {
|
||||
fn into_lua_value_vec(self, _state: &'a State) -> crate::Result<ValueVec<'a>> {
|
||||
Ok(ValueVec::new())
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_from_lua_vec_tuple {
|
||||
( $count: expr, $first: tt, $( $name: tt ),+ ) => (
|
||||
#[allow(non_snake_case)]
|
||||
|
|
Loading…
Reference in New Issue