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 std::borrow::{Borrow, Cow};
|
||||||
|
|
||||||
use crate::{AsLua, FromLua, Function, State};
|
use crate::{FromLua, Function, IntoLuaVec, State};
|
||||||
|
|
||||||
pub struct Chunk<'a> {
|
pub struct Chunk<'a> {
|
||||||
state: &'a State,
|
state: &'a State,
|
||||||
|
@ -38,7 +38,7 @@ impl<'a> Chunk<'a> {
|
||||||
/// Execute the chunk in the Lua context
|
/// Execute the chunk in the Lua context
|
||||||
pub fn execute<A, R>(&'a self, args: A) -> crate::Result<R>
|
pub fn execute<A, R>(&'a self, args: A) -> crate::Result<R>
|
||||||
where
|
where
|
||||||
A: AsLua<'a>,
|
A: IntoLuaVec<'a>,
|
||||||
R: FromLua<'a>
|
R: FromLua<'a>
|
||||||
{
|
{
|
||||||
self.state.execute_chunk::<A, R>(self, args)
|
self.state.execute_chunk::<A, R>(self, args)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::sync::Arc;
|
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;
|
use mlua_sys as lua;
|
||||||
|
|
||||||
|
@ -38,19 +38,15 @@ impl<'a> Function<'a> {
|
||||||
|
|
||||||
pub fn exec<A, R>(&self, args: A) -> crate::Result<R>
|
pub fn exec<A, R>(&self, args: A) -> crate::Result<R>
|
||||||
where
|
where
|
||||||
A: AsLua<'a>,
|
A: IntoLuaVec<'a>,
|
||||||
R: FromLua<'a>,
|
R: FromLua<'a>,
|
||||||
{
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
let _g = StackGuard::new(self.state);
|
let _g = StackGuard::new(self.state);
|
||||||
let s = self.state.state_ptr();
|
let s = self.state.state_ptr();
|
||||||
|
|
||||||
let args_val = args.as_lua(self.state)?;
|
let args_val = args.into_lua_value_vec(self.state)?;
|
||||||
let args_len = match args_val {
|
let args_len = args_val.len() as _;
|
||||||
Value::Variable(v) => v.len(),
|
|
||||||
Value::None => 0,
|
|
||||||
_ => 1,
|
|
||||||
} as _;
|
|
||||||
|
|
||||||
self.state.ensure_stack(2 + args_len)?;
|
self.state.ensure_stack(2 + args_len)?;
|
||||||
|
|
||||||
|
@ -64,7 +60,8 @@ impl<'a> Function<'a> {
|
||||||
|
|
||||||
self.push_to_lua_stack(self.state)?;
|
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)?;
|
args_val.push_to_lua_stack(self.state)?;
|
||||||
|
|
||||||
match lua::lua_pcall(s, args_len, lua::LUA_MULTRET, handler_idx) {
|
match lua::lua_pcall(s, args_len, lua::LUA_MULTRET, handler_idx) {
|
||||||
|
@ -101,3 +98,9 @@ impl<'a> AsLua<'a> for Function<'a> {
|
||||||
Ok(crate::Value::Function(self.clone()))
|
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()
|
||||||
|
}
|
||||||
|
}
|
156
src/main.rs
156
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;
|
use mlua_sys as lua;
|
||||||
|
|
||||||
|
@ -43,90 +43,35 @@ fn main() -> Result<()> {
|
||||||
let f = lua.create_function(a)?;
|
let f = lua.create_function(a)?;
|
||||||
globals.set("native_test", f)?;
|
globals.set("native_test", f)?;
|
||||||
|
|
||||||
let ud = lua.create_userdata(UserdataProxy::<Vec2>::new())?;
|
/* let ud = lua.create_userdata(UserdataProxy::<Vec2>::new())?;
|
||||||
globals.set("Vec2", ud)?;
|
globals.set("Vec2", ud)?; */
|
||||||
|
|
||||||
let tbl = lua.create_table()?;
|
let cell = RefCell::new(Vec2 {
|
||||||
tbl.set("x", 10)?;
|
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#"
|
let chunk = lua.load("text.lua", r#"
|
||||||
require "util"
|
require "util"
|
||||||
|
|
||||||
--[[function dump_table(tbl)
|
if vec2 ~= nil then
|
||||||
for k, v in pairs(tbl) do
|
print("vec2: (" .. vec2.x .. ", " .. vec2.y .. ")")
|
||||||
if type(v) == "table" then
|
|
||||||
dump_table(v)
|
|
||||||
elseif type(v) == "function" then
|
|
||||||
|
|
||||||
else
|
|
||||||
print(k .. "=" .. tostring(v))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
--print("vec2.x = " .. vec2.x)
|
||||||
end
|
--print("vec2.y = " .. vec2.y)
|
||||||
|
|
||||||
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)
|
|
||||||
"#)?;
|
"#)?;
|
||||||
|
|
||||||
|
for _ in 0..2 {
|
||||||
// I don't care about the result of this execution, so I set the result as a
|
// I don't care about the result of this execution, so I set the result as a
|
||||||
// Value which can be anything
|
// Value which can be anything
|
||||||
//
|
//
|
||||||
|
@ -139,6 +84,24 @@ fn main() -> Result<()> {
|
||||||
panic!("{}", e);
|
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 {
|
unsafe {
|
||||||
assert_eq!(lua::lua_gettop(lua.state_ptr()), 0); // ensure that nothing is left on the stack
|
assert_eq!(lua::lua_gettop(lua.state_ptr()), 0); // ensure that nothing is left on the stack
|
||||||
}
|
}
|
||||||
|
@ -310,7 +273,7 @@ pub struct Vec3 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Userdata for 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!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,7 +288,7 @@ pub struct Vec2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Userdata for 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
|
builder
|
||||||
.field_getter("x", |_, this| Ok(this.x))
|
.field_getter("x", |_, this| Ok(this.x))
|
||||||
.field_getter("y", |_, this| Ok(this.y))
|
.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> {
|
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();
|
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
|
// only the functions need to be added since they're the only thing usable from a proxy
|
||||||
builder.functions = other.functions;
|
builder.functions = other.functions;
|
||||||
|
@ -396,3 +359,38 @@ impl<T: Userdata> Userdata for UserdataProxy<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 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> {
|
pub fn ptr_to_string(ptr: *const i8) -> std::result::Result<String, Utf8Error> {
|
||||||
let c = unsafe { CStr::from_ptr(ptr) };
|
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>
|
pub fn execute_chunk<'a, A, R>(&'a self, chunk: &'a Chunk, args: A) -> Result<R>
|
||||||
where
|
where
|
||||||
A: AsLua<'a>,
|
A: IntoLuaVec<'a>,
|
||||||
R: FromLua<'a>
|
R: FromLua<'a>
|
||||||
{
|
{
|
||||||
let handler = self.create_function(|lua, msg: String| {
|
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>> {
|
pub(crate) fn create_userdata_metatable<'a, T: Userdata + 'static>(&'a self) -> Result<Table<'a>> {
|
||||||
let mut builder = UserdataBuilder::<T>::new();
|
let mut builder = UserdataBuilder::<T>::new();
|
||||||
T::build(&mut builder)?;
|
T::build(self, &mut builder)?;
|
||||||
|
|
||||||
let getters = builder.field_getters;
|
let getters = builder.field_getters;
|
||||||
let setters = builder.field_setters;
|
let setters = builder.field_setters;
|
||||||
|
@ -502,10 +502,11 @@ impl State {
|
||||||
let ud_ptr = ud.as_ptr_unchecked::<T>().unwrap();
|
let ud_ptr = ud.as_ptr_unchecked::<T>().unwrap();
|
||||||
ud_ptr.drop_in_place();
|
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();
|
let extra = lua.get_extra_space();
|
||||||
extra.userdata_metatables.remove(&TypeId::of::<T>());
|
extra.userdata_metatables.remove(&TypeId::of::<T>());
|
||||||
|
//todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
74
src/table.rs
74
src/table.rs
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
use mlua_sys as lua;
|
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)]
|
#[derive(Clone)]
|
||||||
pub struct Table<'a> {
|
pub struct Table<'a> {
|
||||||
|
@ -83,8 +83,8 @@ impl<'a> Table<'a> {
|
||||||
/// This may trigger the `__newindex` metamethod, see [`Table::raw_set`]
|
/// This may trigger the `__newindex` metamethod, see [`Table::raw_set`]
|
||||||
pub fn set<K, V>(&self, key: K, val: V) -> Result<()>
|
pub fn set<K, V>(&self, key: K, val: V) -> Result<()>
|
||||||
where
|
where
|
||||||
K: PushToLuaStack<'a>,
|
K: AsLua<'a>,
|
||||||
V: PushToLuaStack<'a>
|
V: AsLua<'a>
|
||||||
{
|
{
|
||||||
let s = self.state.state_ptr();
|
let s = self.state.state_ptr();
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -97,8 +97,10 @@ impl<'a> Table<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.lref.push_to_lua_stack(self.state)?;
|
self.lref.push_to_lua_stack(self.state)?;
|
||||||
key.push_to_lua_stack(self.state)?;
|
key.as_lua(self.state)?
|
||||||
val.push_to_lua_stack(self.state)?;
|
.push_to_lua_stack(self.state)?;
|
||||||
|
val.as_lua(self.state)?
|
||||||
|
.push_to_lua_stack(self.state)?;
|
||||||
|
|
||||||
lua::lua_settable(s, -3);
|
lua::lua_settable(s, -3);
|
||||||
}
|
}
|
||||||
|
@ -111,8 +113,8 @@ impl<'a> Table<'a> {
|
||||||
/// This may trigger the `__index` metamethod, see [`Table::raw_get`]
|
/// This may trigger the `__index` metamethod, see [`Table::raw_get`]
|
||||||
pub fn get<K, V>(&self, key: K) -> Result<V>
|
pub fn get<K, V>(&self, key: K) -> Result<V>
|
||||||
where
|
where
|
||||||
K: PushToLuaStack<'a>,
|
K: AsLua<'a>,
|
||||||
V: FromLuaStack<'a>,
|
V: FromLua<'a>,
|
||||||
{
|
{
|
||||||
let s = self.state.state_ptr();
|
let s = self.state.state_ptr();
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -120,10 +122,13 @@ impl<'a> Table<'a> {
|
||||||
let _g = StackGuard::new(self.state);
|
let _g = StackGuard::new(self.state);
|
||||||
|
|
||||||
self.lref.push_to_lua_stack(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
|
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)
|
Ok(val)
|
||||||
}
|
}
|
||||||
|
@ -150,7 +155,7 @@ impl<'a> Table<'a> {
|
||||||
/// Returns a boolean indicating if this table has a key
|
/// Returns a boolean indicating if this table has a key
|
||||||
pub fn has_key<K>(&self, key: K) -> Result<bool>
|
pub fn has_key<K>(&self, key: K) -> Result<bool>
|
||||||
where
|
where
|
||||||
K: PushToLuaStack<'a>,
|
K: AsLua<'a>,
|
||||||
{
|
{
|
||||||
let s = self.state.state_ptr();
|
let s = self.state.state_ptr();
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -158,7 +163,8 @@ impl<'a> Table<'a> {
|
||||||
let _g = StackGuard::new(self.state);
|
let _g = StackGuard::new(self.state);
|
||||||
|
|
||||||
self.lref.push_to_lua_stack(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
|
// table[key] is at top of stack
|
||||||
if lua::lua_gettable(s, -2) == lua::LUA_TNIL {
|
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.
|
/// 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<()>
|
pub fn raw_set<K, V>(&self, key: K, val: V) -> Result<()>
|
||||||
where
|
where
|
||||||
K: PushToLuaStack<'a>,
|
K: AsLua<'a>,
|
||||||
V: PushToLuaStack<'a>
|
V: AsLua<'a>
|
||||||
{
|
{
|
||||||
let s = self.state.state_ptr();
|
let s = self.state.state_ptr();
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -181,8 +187,10 @@ impl<'a> Table<'a> {
|
||||||
let _g = StackGuard::new(self.state);
|
let _g = StackGuard::new(self.state);
|
||||||
|
|
||||||
self.lref.push_to_lua_stack(self.state)?;
|
self.lref.push_to_lua_stack(self.state)?;
|
||||||
key.push_to_lua_stack(self.state)?;
|
key.as_lua(self.state)?
|
||||||
val.push_to_lua_stack(self.state)?;
|
.push_to_lua_stack(self.state)?;
|
||||||
|
val.as_lua(self.state)?
|
||||||
|
.push_to_lua_stack(self.state)?;
|
||||||
|
|
||||||
lua::lua_rawset(s, -3);
|
lua::lua_rawset(s, -3);
|
||||||
}
|
}
|
||||||
|
@ -191,10 +199,10 @@ impl<'a> Table<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a value from the table without calling any meta methods.
|
/// 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
|
where
|
||||||
K: PushToLuaStack<'a>,
|
K: AsLua<'a>,
|
||||||
V: FromLuaStack<'a>,
|
V: FromLua<'a>,
|
||||||
{
|
{
|
||||||
let s = self.state.state_ptr();
|
let s = self.state.state_ptr();
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -202,9 +210,13 @@ impl<'a> Table<'a> {
|
||||||
let _g = StackGuard::new(self.state);
|
let _g = StackGuard::new(self.state);
|
||||||
|
|
||||||
self.lref.push_to_lua_stack(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
|
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.
|
/// 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>
|
pub fn raw_has_key<K>(&self, key: K) -> Result<bool>
|
||||||
where
|
where
|
||||||
K: PushToLuaStack<'a>,
|
K: AsLua<'a>,
|
||||||
{
|
{
|
||||||
let s = self.state.state_ptr();
|
let s = self.state.state_ptr();
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -234,7 +246,9 @@ impl<'a> Table<'a> {
|
||||||
let _g = StackGuard::new(self.state);
|
let _g = StackGuard::new(self.state);
|
||||||
|
|
||||||
self.lref.push_to_lua_stack(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
|
// table[key] is at top of stack
|
||||||
Ok(lua::lua_rawget(s, -2) != lua::LUA_TNIL)
|
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
|
/// Does nothing if this table is not a metatable
|
||||||
pub fn set_meta<K, V>(&self, key: K, val: V) -> Result<()>
|
pub fn set_meta<K, V>(&self, key: K, val: V) -> Result<()>
|
||||||
where
|
where
|
||||||
K: PushToLuaStack<'a>,
|
K: AsLua<'a>,
|
||||||
V: PushToLuaStack<'a>
|
V: AsLua<'a>
|
||||||
{
|
{
|
||||||
if self.mt_marker {
|
if self.mt_marker {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -255,8 +269,10 @@ impl<'a> Table<'a> {
|
||||||
let _g = StackGuard::new(self.state);
|
let _g = StackGuard::new(self.state);
|
||||||
|
|
||||||
self.lref.push_to_lua_stack(self.state)?;
|
self.lref.push_to_lua_stack(self.state)?;
|
||||||
key.push_to_lua_stack(self.state)?;
|
key.as_lua(self.state)?
|
||||||
val.push_to_lua_stack(self.state)?;
|
.push_to_lua_stack(self.state)?;
|
||||||
|
val.as_lua(self.state)?
|
||||||
|
.push_to_lua_stack(self.state)?;
|
||||||
lua::lua_settable(s, -3);
|
lua::lua_settable(s, -3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -280,3 +296,9 @@ impl<'a> FromLuaStack<'a> for Table<'a> {
|
||||||
Table::with_ref(state, LuaRef::from_stack(state)?, false)
|
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;
|
use mlua_sys as lua;
|
||||||
|
|
||||||
|
pub mod unsafe_ud;
|
||||||
|
pub use unsafe_ud::*;
|
||||||
|
|
||||||
/// An enum representing all Lua MetaMethods
|
/// An enum representing all Lua MetaMethods
|
||||||
/// https://gist.github.com/oatmealine/655c9e64599d0f0dd47687c1186de99f
|
/// https://gist.github.com/oatmealine/655c9e64599d0f0dd47687c1186de99f
|
||||||
pub enum MetaMethod {
|
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 struct UserdataBuilder<'a, T> {
|
||||||
pub(crate) name: String,
|
pub(crate) name: String,
|
||||||
|
@ -97,6 +100,9 @@ pub struct UserdataBuilder<'a, T> {
|
||||||
pub(crate) field_setters: HashMap<String, UserdataFn<'a>>,
|
pub(crate) field_setters: HashMap<String, UserdataFn<'a>>,
|
||||||
pub(crate) functions: HashMap<String, UserdataFn<'a>>,
|
pub(crate) functions: HashMap<String, UserdataFn<'a>>,
|
||||||
pub(crate) meta_methods: 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>,
|
_marker: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,6 +114,7 @@ impl<'a, T: Userdata> UserdataBuilder<'a, T> {
|
||||||
field_setters: HashMap::new(),
|
field_setters: HashMap::new(),
|
||||||
functions: HashMap::new(),
|
functions: HashMap::new(),
|
||||||
meta_methods: HashMap::new(),
|
meta_methods: HashMap::new(),
|
||||||
|
wrapped_getter: Arc::new(OnceCell::new()),
|
||||||
_marker: PhantomData,
|
_marker: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,11 +125,34 @@ impl<'a, T: Userdata> UserdataBuilder<'a, T> {
|
||||||
R: AsLua<'a>,
|
R: AsLua<'a>,
|
||||||
T: Userdata + 'static
|
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 wrap = move |lua: &'a State, mut val: ValueVec<'a>| {
|
||||||
let val = val.pop_front().unwrap();
|
let val = val.pop_front().unwrap();
|
||||||
let this = val.as_userdata().unwrap(); // if this panics, its a bug
|
let this = val.as_userdata().unwrap(); // if this panics, its a bug
|
||||||
|
|
||||||
|
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>()?;
|
let this = this.as_ref::<T>()?;
|
||||||
f(lua, &*this).and_then(|r| r.as_lua(lua))
|
f(lua, &*this).and_then(|r| r.as_lua(lua))
|
||||||
|
}
|
||||||
};
|
};
|
||||||
self.field_getters.insert(name.to_string(), Box::new(wrap));
|
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 wrap = move |lua: &'a State, mut val: ValueVec<'a>| {
|
||||||
let this_val = val.pop_front().unwrap();
|
let this_val = val.pop_front().unwrap();
|
||||||
let this = this_val.as_userdata().unwrap(); // if this panics, its a bug
|
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 = this.as_ref::<T>()?;
|
||||||
|
|
||||||
let this_name = T::name();
|
let this_name = T::name();
|
||||||
|
@ -233,78 +264,60 @@ impl<'a, T: Userdata> UserdataBuilder<'a, T> {
|
||||||
|
|
||||||
self
|
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 {
|
pub trait Userdata: Sized {
|
||||||
fn name() -> String;
|
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
|
/// A handle to some userdata on the stack
|
||||||
#[derive(Clone)]
|
//#[derive(Clone)]
|
||||||
pub struct AnyUserdata<'a> {
|
pub struct AnyUserdata<'a> {
|
||||||
pub(crate) lref: LuaRef<'a>,
|
pub(crate) unsafe_ud: UnsafeUserdata<'a>,
|
||||||
state: &'a State,
|
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> {
|
impl<'a> AnyUserdata<'a> {
|
||||||
pub fn from_ref(state: &'a State, lref: LuaRef<'a>) -> Self {
|
pub fn from_ref(state: &'a State, lref: LuaRef<'a>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
lref,
|
|
||||||
state,
|
state,
|
||||||
|
unsafe_ud: UnsafeUserdata::from_ref(state, lref)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a borrow to the userdata.
|
/// Returns a borrow to the userdata.
|
||||||
pub fn as_ref<T: Userdata + 'static>(&self) -> crate::Result<Ref<'a, T>> {
|
pub fn as_ref<T: Userdata + 'static>(&self) -> crate::Result<Ref<'a, T>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.state.ensure_stack(3)?;
|
let cell = &*self.unsafe_ud.as_ptr_unchecked::<RefCell<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::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())
|
Ok(cell.borrow())
|
||||||
} else {
|
|
||||||
return Err(crate::Error::UserdataMismatch);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a mutable reference to the userdata.
|
/// Returns a mutable reference to the userdata.
|
||||||
pub fn as_mut<T: Userdata + 'static>(&self) -> crate::Result<RefMut<'a, T>> {
|
pub fn as_mut<T: Userdata + 'static>(&self) -> crate::Result<RefMut<'a, T>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.state.ensure_stack(3)?;
|
let cell = &*self.unsafe_ud.as_ptr_unchecked::<RefCell<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);
|
|
||||||
let cell = &*cptr.cast::<RefCell<T>>();
|
|
||||||
Ok(cell.borrow_mut())
|
Ok(cell.borrow_mut())
|
||||||
} else {
|
|
||||||
Err(crate::Error::UserdataMismatch)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,14 +330,8 @@ impl<'a> AnyUserdata<'a> {
|
||||||
/// If there is a possibility that these types do not match, use [`AnyUserdata::as_ptr`]
|
/// If there is a possibility that these types do not match, use [`AnyUserdata::as_ptr`]
|
||||||
/// which does verify the types.
|
/// which does verify the types.
|
||||||
pub unsafe fn as_ptr_unchecked<T: Userdata + 'static>(&self) -> crate::Result<*mut RefCell<T>> {
|
pub unsafe fn as_ptr_unchecked<T: Userdata + 'static>(&self) -> crate::Result<*mut RefCell<T>> {
|
||||||
self.state.ensure_stack(1)?;
|
let cell = self.unsafe_ud.as_ptr_unchecked::<RefCell<T>>()?;
|
||||||
let _g = StackGuard::new(self.state);
|
Ok(cell)
|
||||||
let s = self.state.state_ptr();
|
|
||||||
|
|
||||||
self.lref.push_to_lua_stack(self.state)?;
|
|
||||||
let cptr = lua::lua_touserdata(s, -3);
|
|
||||||
|
|
||||||
Ok(cptr.cast())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a mutable pointer of the [`RefCell`] storing the userdata.
|
/// 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 _g = StackGuard::new(self.state);
|
||||||
let s = self.state.state_ptr();
|
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 {
|
if lua::lua_getmetatable(s, -1) == 0 {
|
||||||
return Err(crate::Error::MissingMetatable);
|
return Err(crate::Error::MissingMetatable);
|
||||||
|
@ -345,8 +352,9 @@ impl<'a> AnyUserdata<'a> {
|
||||||
.push_to_lua_stack(self.state)?;
|
.push_to_lua_stack(self.state)?;
|
||||||
|
|
||||||
if lua::lua_rawequal(s, -2, -1) == 1 {
|
if lua::lua_rawequal(s, -2, -1) == 1 {
|
||||||
let cptr = lua::lua_touserdata(s, -3);
|
drop(_g);
|
||||||
Ok(cptr.cast())
|
let cell = self.unsafe_ud.as_ptr_unchecked::<RefCell<T>>()?;
|
||||||
|
Ok(cell)
|
||||||
} else {
|
} else {
|
||||||
Err(crate::Error::UserdataMismatch)
|
Err(crate::Error::UserdataMismatch)
|
||||||
}
|
}
|
||||||
|
@ -358,7 +366,7 @@ impl<'a> AnyUserdata<'a> {
|
||||||
self.state.ensure_stack(3)?;
|
self.state.ensure_stack(3)?;
|
||||||
let _g = StackGuard::new(self.state);
|
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();
|
let s = self.state.state_ptr();
|
||||||
|
|
||||||
if lua::lua_getmetatable(s, -1) == 0 {
|
if lua::lua_getmetatable(s, -1) == 0 {
|
||||||
|
@ -378,6 +386,69 @@ impl<'a> AnyUserdata<'a> {
|
||||||
Ok(cstr.to_string())
|
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> {
|
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)?;
|
ensure_type(state, lua::LUA_TUSERDATA, -1)?;
|
||||||
|
|
||||||
Ok(AnyUserdata {
|
Ok(AnyUserdata {
|
||||||
lref: LuaRef::from_stack(state)?,
|
|
||||||
state,
|
state,
|
||||||
|
unsafe_ud: UnsafeUserdata::from_lua_stack(state)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PushToLuaStack<'a> for AnyUserdata<'a> {
|
impl<'a> PushToLuaStack<'a> for AnyUserdata<'a> {
|
||||||
unsafe fn push_to_lua_stack(&self, state: &'a State) -> crate::Result<()> {
|
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 {
|
match self {
|
||||||
Value::Userdata(ud) => Ok(ud),
|
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> {
|
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();
|
let s = state.state_ptr();
|
||||||
|
|
||||||
match self {
|
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 {
|
impl<'a, T: FromLua<'a>> FromLuaVec<'a> for T {
|
||||||
fn from_lua_value_vec(state: &'a State, mut values: ValueVec<'a>) -> crate::Result<Self> {
|
fn from_lua_value_vec(state: &'a State, mut values: ValueVec<'a>) -> crate::Result<Self> {
|
||||||
if let Some(val) = values.pop_front() {
|
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 {
|
macro_rules! impl_from_lua_vec_tuple {
|
||||||
( $count: expr, $first: tt, $( $name: tt ),+ ) => (
|
( $count: expr, $first: tt, $( $name: tt ),+ ) => (
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
|
|
Loading…
Reference in New Issue