Groundwork for userdata
Still need a way to add methods and functions
This commit is contained in:
parent
71199bc905
commit
2b03b55014
|
@ -1,9 +1,10 @@
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
|
|
||||||
use crate::{FromLuaStack, LuaRef, PushToLuaStack, StackGuard, State};
|
use crate::{AsLua, FromLuaStack, LuaRef, PushToLuaStack, StackGuard, State};
|
||||||
|
|
||||||
use mlua_sys as lua;
|
use mlua_sys as lua;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Function<'a> {
|
pub struct Function<'a> {
|
||||||
state: &'a State,
|
state: &'a State,
|
||||||
lref: LuaRef
|
lref: LuaRef
|
||||||
|
@ -18,7 +19,7 @@ impl<'a> FromLuaStack<'a> for Function<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PushToLuaStack for Function<'a> {
|
impl<'a> PushToLuaStack<'a> for Function<'a> {
|
||||||
unsafe fn push_to_lua_stack(&self, state: &State) -> crate::Result<()> {
|
unsafe fn push_to_lua_stack(&self, state: &State) -> crate::Result<()> {
|
||||||
self.lref.push_to_lua_stack(state)
|
self.lref.push_to_lua_stack(state)
|
||||||
}
|
}
|
||||||
|
@ -59,20 +60,26 @@ impl<'a> Function<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait PushToLuaStackMulti<'a> {
|
pub trait PushToLuaStackMulti<'a> {
|
||||||
fn len(&self) -> usize;
|
fn len(&self) -> usize;
|
||||||
fn push_args_to_lua_stack(&self, state: &State) -> crate::Result<()>;
|
fn push_args_to_lua_stack(&self, state: &'a State) -> crate::Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> PushToLuaStackMulti<'a> for T
|
impl<'a, T> PushToLuaStackMulti<'a> for T
|
||||||
where
|
where
|
||||||
T: PushToLuaStack,
|
T: PushToLuaStack<'a>,
|
||||||
{
|
{
|
||||||
fn len(&self) -> usize {
|
fn len(&self) -> usize {
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_args_to_lua_stack(&self, state: &State) -> crate::Result<()> {
|
fn push_args_to_lua_stack(&self, state: &'a State) -> crate::Result<()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.push_to_lua_stack(state)?;
|
self.push_to_lua_stack(state)?;
|
||||||
}
|
}
|
||||||
|
@ -109,14 +116,14 @@ impl<'a, T: FromLuaStack<'a>> FromLuaStackMulti<'a> for T {
|
||||||
macro_rules! impl_function_arg_tuple {
|
macro_rules! impl_function_arg_tuple {
|
||||||
( $count: expr, $first: tt, $( $name: tt ),+ ) => (
|
( $count: expr, $first: tt, $( $name: tt ),+ ) => (
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
impl<'a, $first: PushToLuaStack, $($name: PushToLuaStack,)+> PushToLuaStackMulti<'a> for ($first, $($name,)+) {
|
impl<'a, $first: PushToLuaStack<'a>, $($name: PushToLuaStack<'a>,)+> PushToLuaStackMulti<'a> for ($first, $($name,)+) {
|
||||||
fn len(&self) -> usize {
|
fn len(&self) -> usize {
|
||||||
// this will end up generating $count - 1 - 1 - 1... hopefully the compiler will
|
// this will end up generating $count - 1 - 1 - 1... hopefully the compiler will
|
||||||
// optimize that out
|
// optimize that out
|
||||||
$count
|
$count
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_args_to_lua_stack(&self, state: &State) -> crate::Result<()> {
|
fn push_args_to_lua_stack(&self, state: &'a State) -> crate::Result<()> {
|
||||||
let ($first, $($name,)+) = self;
|
let ($first, $($name,)+) = self;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -134,7 +141,13 @@ macro_rules! impl_function_arg_tuple {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn results_from_lua_stack(state: &'a State) -> crate::Result<Self> {
|
fn results_from_lua_stack(state: &'a State) -> crate::Result<Self> {
|
||||||
Ok(unsafe { ( $first::from_lua_stack(state)?, $( $name::from_lua_stack(state)?, )+ ) })
|
unsafe {
|
||||||
|
let ($( $name, )+ $first) = ( $( $name::from_lua_stack(state)?, )+ $first::from_lua_stack(state)? );
|
||||||
|
|
||||||
|
Ok( ($first, $( $name, )+) )
|
||||||
|
}
|
||||||
|
//Ok(unsafe { ( $( $name::from_lua_stack(state)?, )+ $first::from_lua_stack(state)? ) })
|
||||||
|
//Ok(unsafe { ( $first::from_lua_stack(state)?, $( $name::from_lua_stack(state)?, )+ ) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,12 +157,12 @@ macro_rules! impl_function_arg_tuple {
|
||||||
// implements PushToLuaStackMulti and FromLuaStackMulti for a tuple with a single element
|
// implements PushToLuaStackMulti and FromLuaStackMulti for a tuple with a single element
|
||||||
( $count: expr, $only: tt ) => {
|
( $count: expr, $only: tt ) => {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
impl<'a, $only: PushToLuaStack> PushToLuaStackMulti<'a> for ($only,) {
|
impl<'a, $only: PushToLuaStack<'a>> PushToLuaStackMulti<'a> for ($only,) {
|
||||||
fn len(&self) -> usize {
|
fn len(&self) -> usize {
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_args_to_lua_stack(&self, state: &State) -> crate::Result<()> {
|
fn push_args_to_lua_stack(&self, state: &'a State) -> crate::Result<()> {
|
||||||
let (a,) = self;
|
let (a,) = self;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
229
src/main.rs
229
src/main.rs
|
@ -1,4 +1,4 @@
|
||||||
use std::{ffi::CStr, str::Utf8Error, sync::Arc};
|
use std::{any::type_name, ffi::CStr, marker::PhantomData, mem, ptr, str::Utf8Error, sync::Arc};
|
||||||
|
|
||||||
use lua::{lua_typename, lua_type};
|
use lua::{lua_typename, lua_type};
|
||||||
use mlua_sys as lua;
|
use mlua_sys as lua;
|
||||||
|
@ -18,65 +18,28 @@ use value::*;
|
||||||
pub mod guard;
|
pub mod guard;
|
||||||
use guard::*;
|
use guard::*;
|
||||||
|
|
||||||
/* struct RustFn {
|
pub mod userdata;
|
||||||
|
use userdata::*;
|
||||||
} */
|
|
||||||
|
|
||||||
/* struct RustFnUpvalue {
|
|
||||||
|
|
||||||
} */
|
|
||||||
|
|
||||||
///
|
|
||||||
pub fn ptr_to_string(ptr: *const i8) -> std::result::Result<String, Utf8Error> {
|
|
||||||
let c = unsafe { CStr::from_ptr(ptr) };
|
|
||||||
let s= c.to_str()?;
|
|
||||||
Ok(s.to_string())
|
|
||||||
}
|
|
||||||
|
|
||||||
|
pub mod util;
|
||||||
|
use util::*;
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
let lua = State::new();
|
let lua = State::new();
|
||||||
lua.expose_libraries(&[StdLibrary::Debug]);
|
lua.expose_libraries(&[StdLibrary::Debug, StdLibrary::Package]);
|
||||||
|
|
||||||
let globals = lua.globals()?;
|
let globals = lua.globals()?;
|
||||||
|
|
||||||
let a = |lua: &State, (num,): (i32,)| -> Result<i32> {
|
let a = |_lua: &State, (num,): (i32,)| -> Result<i32> {
|
||||||
println!("Rust got number from lua: {}", num);
|
println!("Rust got number from lua: {}", num);
|
||||||
Ok(999)
|
Ok(999)
|
||||||
};
|
};
|
||||||
|
|
||||||
let f = lua.create_function(a)?;
|
let f = lua.create_function(a)?;
|
||||||
globals.set("native_test", f)?;
|
globals.set("native_test", f)?;
|
||||||
|
|
||||||
//let tbl = lua.create_table()?;
|
|
||||||
|
|
||||||
let vec2_add = lua.create_function(|lua: &State, (a, b): (Table, Table)| -> Result<Table> {
|
|
||||||
let ax: i32 = a.get("x")?;
|
|
||||||
let ay: i32 = a.get("y")?;
|
|
||||||
|
|
||||||
let bx: i32 = b.get("x")?;
|
|
||||||
let by: i32 = b.get("y")?;
|
|
||||||
|
|
||||||
let rx = ax + bx;
|
|
||||||
let ry = ay + by;
|
|
||||||
|
|
||||||
let mt = lua.create_meta_table("Vec2")?;
|
|
||||||
mt.set("x", rx)?;
|
|
||||||
mt.set("y", ry)?;
|
|
||||||
Ok(mt)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
|
let ud = lua.create_userdata("Vec2", Vec2 { x: 0.0, y: 0.0})?;
|
||||||
let mt = lua.create_meta_table("Vec2")?;
|
globals.set("Vec2", ud)?;
|
||||||
mt.set("x", 50)?;
|
|
||||||
mt.set("y", 50)?;
|
|
||||||
mt.set_meta("__add", vec2_add)?;
|
|
||||||
globals.set("pos1", mt)?;
|
|
||||||
|
|
||||||
let mt = lua.create_meta_table("Vec2")?;
|
|
||||||
mt.set("x", 25)?;
|
|
||||||
mt.set("y", 25)?;
|
|
||||||
globals.set("pos2", mt)?;
|
|
||||||
|
|
||||||
let tbl = lua.create_table()?;
|
let tbl = lua.create_table()?;
|
||||||
tbl.set("x", 10)?;
|
tbl.set("x", 10)?;
|
||||||
|
@ -85,6 +48,8 @@ fn main() -> Result<()> {
|
||||||
globals.set("X", tbl)?;
|
globals.set("X", tbl)?;
|
||||||
|
|
||||||
lua.execute(r#"
|
lua.execute(r#"
|
||||||
|
require "util"
|
||||||
|
|
||||||
--[[function dump_table(tbl)
|
--[[function dump_table(tbl)
|
||||||
for k, v in pairs(tbl) do
|
for k, v in pairs(tbl) do
|
||||||
if type(v) == "table" then
|
if type(v) == "table" then
|
||||||
|
@ -123,28 +88,12 @@ fn main() -> Result<()> {
|
||||||
local res = native_test(50)
|
local res = native_test(50)
|
||||||
print("Lua got " .. res .. " back from rust!")
|
print("Lua got " .. res .. " back from rust!")
|
||||||
|
|
||||||
print("Pos1 is (" .. pos1.x .. ", " .. pos1.y .. ")")
|
print("Vec2: " .. dump_table(Vec2))
|
||||||
print("Pos2 is (" .. pos2.x .. ", " .. pos2.y .. ")")
|
print("Meta Vec2: " .. dump_table(getmetatable(Vec2)))
|
||||||
|
--local vec2 = Vec2.new(50, 50)
|
||||||
local add_pos = pos1 + pos2
|
print("Vec2 is (" .. Vec2.x .. ", " .. Vec2.y .. ")")
|
||||||
print("Pos1 + pos2 is (" .. add_pos.x .. ", " .. add_pos.y .. ")")
|
|
||||||
"#).unwrap();
|
"#).unwrap();
|
||||||
|
|
||||||
let num = globals.get::<_, i32>("cool_num")?;
|
|
||||||
assert_eq!(num, 50);
|
|
||||||
println!("Got number as 50!");
|
|
||||||
|
|
||||||
let num = globals.get::<_, Function>("say_number")?;
|
|
||||||
num.exec::<_, ()>(50)?;
|
|
||||||
|
|
||||||
let num = globals.get::<_, Function>("multiply_print")?;
|
|
||||||
num.exec::<_, ()>((10, 5))?;
|
|
||||||
|
|
||||||
let num = globals.get::<_, Function>("multiply_ret")?;
|
|
||||||
let num: i32 = num.exec::<_, i32>((10, 5))?;
|
|
||||||
assert_eq!(num, 50);
|
|
||||||
println!("Did math in lua and got 50!");
|
|
||||||
|
|
||||||
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
|
||||||
}
|
}
|
||||||
|
@ -165,10 +114,8 @@ impl LuaRef {
|
||||||
/// Creates a reference to what is at the top of the stack.
|
/// Creates a reference to what is at the top of the stack.
|
||||||
pub unsafe fn from_stack(state: &State) -> Result<Self> {
|
pub unsafe fn from_stack(state: &State) -> Result<Self> {
|
||||||
let s = state.state_ptr();
|
let s = state.state_ptr();
|
||||||
let t = lua::lua_gettop(s);
|
|
||||||
|
|
||||||
let r = lua::luaL_ref(s, lua::LUA_REGISTRYINDEX);
|
let r = lua::luaL_ref(s, lua::LUA_REGISTRYINDEX);
|
||||||
let t = lua::lua_gettop(s);
|
|
||||||
if r == lua::LUA_REFNIL {
|
if r == lua::LUA_REFNIL {
|
||||||
Err(Error::Nil)
|
Err(Error::Nil)
|
||||||
} else {
|
} else {
|
||||||
|
@ -177,7 +124,7 @@ impl LuaRef {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PushToLuaStack for LuaRef {
|
impl<'a> PushToLuaStack<'a> for LuaRef {
|
||||||
unsafe fn push_to_lua_stack(&self, state: &State) -> Result<()> {
|
unsafe fn push_to_lua_stack(&self, state: &State) -> Result<()> {
|
||||||
let s = state.state_ptr();
|
let s = state.state_ptr();
|
||||||
|
|
||||||
|
@ -236,73 +183,65 @@ impl Error {
|
||||||
let msg = format!("{}", self);
|
let msg = format!("{}", self);
|
||||||
let msg_c = msg.as_ptr() as *const i8;
|
let msg_c = msg.as_ptr() as *const i8;
|
||||||
lua::luaL_error(lua, msg_c);
|
lua::luaL_error(lua, msg_c);
|
||||||
panic!("never gets here");
|
unreachable!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A result for use with lua functions
|
/// A result for use with lua functions
|
||||||
type Result<T> = core::result::Result<T, Error>;
|
type Result<T> = core::result::Result<T, Error>;
|
||||||
|
|
||||||
pub trait PushToLuaStack {
|
pub trait PushToLuaStack<'a> {
|
||||||
unsafe fn push_to_lua_stack(&self, state: &State) -> Result<()>;
|
unsafe fn push_to_lua_stack(&self, state: &'a State) -> Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FromLuaStack<'a>: Sized {
|
pub trait FromLuaStack<'a>: Sized {
|
||||||
unsafe fn from_lua_stack(state: &'a State) -> Result<Self>;
|
unsafe fn from_lua_stack(state: &'a State) -> Result<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* impl<'a> FromLuaStack<'a> for () {
|
|
||||||
unsafe fn from_lua_stack(state: &'a State) -> Result<Self> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
} */
|
|
||||||
|
|
||||||
/// Implements PushToLuaStack for a number
|
/// Implements PushToLuaStack for a number
|
||||||
macro_rules! impl_push_to_lua_stack_number {
|
macro_rules! impl_as_lua_number {
|
||||||
($ty: ident) => {
|
($ty: ident) => {
|
||||||
impl PushToLuaStack for $ty {
|
impl<'a> AsLua<'a> for $ty {
|
||||||
unsafe fn push_to_lua_stack(&self, state: &State) -> Result<()> {
|
fn as_lua(&self, _lua: &'a State) -> crate::Result<Value<'a>> {
|
||||||
state.ensure_stack(1)?;
|
Ok(Value::Number(*self as f64))
|
||||||
lua::lua_pushnumber(state.state_ptr(), *self as f64);
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FromLua for $ty {
|
||||||
|
fn from_lua(_lua: &State, val: Value) -> crate::Result<Self> {
|
||||||
|
match val {
|
||||||
|
Value::Number(v) => Ok(v as $ty),
|
||||||
|
_ => {
|
||||||
|
Err(Error::UnexpectedType("Number".to_string(), val.type_name().to_string()))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> PushToLuaStack<'a> for $ty {
|
||||||
|
unsafe fn push_to_lua_stack(&self, state: &'a State) -> crate::Result<()> {
|
||||||
|
let v = self.as_lua(state)?;
|
||||||
|
v.push_to_lua_stack(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FromLuaStack<'a> for i32 {
|
impl_as_lua_number!(i8);
|
||||||
unsafe fn from_lua_stack(state: &'a State) -> Result<Self> {
|
impl_as_lua_number!(i16);
|
||||||
let s = state.state_ptr();
|
impl_as_lua_number!(i32);
|
||||||
|
impl_as_lua_number!(i64);
|
||||||
|
|
||||||
if lua::lua_isnumber(s, -1) == 1 {
|
impl_as_lua_number!(u8);
|
||||||
let v = lua::lua_tonumber(s, -1) as i32;
|
impl_as_lua_number!(u16);
|
||||||
lua::lua_pop(s, 1);
|
impl_as_lua_number!(u32);
|
||||||
Ok(v)
|
impl_as_lua_number!(u64);
|
||||||
} else {
|
|
||||||
let lua_ty = lua_type(s, -1);
|
|
||||||
let typec = CStr::from_ptr(lua_typename(s, lua_ty));
|
|
||||||
let type_str = typec.to_str()
|
|
||||||
.expect("Type has invalid bytes!");
|
|
||||||
|
|
||||||
Err(Error::unexpected_type("Number", type_str))
|
impl_as_lua_number!(f32);
|
||||||
}
|
impl_as_lua_number!(f64);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_push_to_lua_stack_number!(i8);
|
impl<'a> PushToLuaStack<'a> for String {
|
||||||
impl_push_to_lua_stack_number!(i16);
|
|
||||||
impl_push_to_lua_stack_number!(i32);
|
|
||||||
impl_push_to_lua_stack_number!(i64);
|
|
||||||
|
|
||||||
impl_push_to_lua_stack_number!(u8);
|
|
||||||
impl_push_to_lua_stack_number!(u16);
|
|
||||||
impl_push_to_lua_stack_number!(u32);
|
|
||||||
impl_push_to_lua_stack_number!(u64);
|
|
||||||
|
|
||||||
impl_push_to_lua_stack_number!(f32);
|
|
||||||
impl_push_to_lua_stack_number!(f64);
|
|
||||||
|
|
||||||
impl PushToLuaStack for String {
|
|
||||||
unsafe fn push_to_lua_stack(&self, state: &State) -> Result<()> {
|
unsafe fn push_to_lua_stack(&self, state: &State) -> Result<()> {
|
||||||
state.ensure_stack(1)?;
|
state.ensure_stack(1)?;
|
||||||
|
|
||||||
|
@ -314,7 +253,19 @@ impl PushToLuaStack for String {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PushToLuaStack for &str {
|
impl<'a> FromLuaStack<'a> for String {
|
||||||
|
unsafe fn from_lua_stack(state: &'a State) -> Result<Self> {
|
||||||
|
let s = state.state_ptr();
|
||||||
|
|
||||||
|
let cstr = lua::lua_tostring(s, -1);
|
||||||
|
lua::lua_pop(s, 1);
|
||||||
|
|
||||||
|
let cstr = CStr::from_ptr(cstr);
|
||||||
|
Ok(cstr.to_str().unwrap().to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> PushToLuaStack<'a> for &str {
|
||||||
unsafe fn push_to_lua_stack(&self, state: &State) -> Result<()> {
|
unsafe fn push_to_lua_stack(&self, state: &State) -> Result<()> {
|
||||||
state.ensure_stack(1)?;
|
state.ensure_stack(1)?;
|
||||||
|
|
||||||
|
@ -322,6 +273,54 @@ impl PushToLuaStack for &str {
|
||||||
let cstr = s.as_ptr() as *const i8;
|
let cstr = s.as_ptr() as *const i8;
|
||||||
lua::lua_pushstring(state.state_ptr(), cstr);
|
lua::lua_pushstring(state.state_ptr(), cstr);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Vec2 {
|
||||||
|
x: f32,
|
||||||
|
y: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Userdata for Vec2 {
|
||||||
|
fn build<'a>(builder: &mut UserdataBuilder<'a, Vec2>) -> crate::Result<()> {
|
||||||
|
builder.name("Vec2")
|
||||||
|
.field_getter("x", |_, this| Ok(this.x))
|
||||||
|
.field_getter("y", |_, this| Ok(this.y));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct UserdataProxy<T: Userdata>(PhantomData<T>);
|
||||||
|
|
||||||
|
impl<T: Userdata> UserdataProxy<T> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self(PhantomData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: Userdata> AsLua<'a> for UserdataProxy<T> {
|
||||||
|
fn as_lua(&self, lua: &'a State) -> crate::Result<Value<'a>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Userdata> Userdata for UserdataProxy<T> {
|
||||||
|
fn build<'a>(builder: &mut UserdataBuilder<'a, Self>) -> crate::Result<()> {
|
||||||
|
|
||||||
|
let mut other = UserdataBuilder::<T>::new();
|
||||||
|
T::build(&mut other)?;
|
||||||
|
|
||||||
|
builder.name(&other.name.unwrap());
|
||||||
|
|
||||||
|
for (lbl, getters) in other.field_getters.into_iter() {
|
||||||
|
let wrap = |state: &State, data: &Self| {
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
builder.field_getter(&lbl, wrap);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
75
src/state.rs
75
src/state.rs
|
@ -1,9 +1,15 @@
|
||||||
use core::ffi;
|
use core::ffi;
|
||||||
use std::{ffi::{CString, CStr}, mem, ptr::{self, NonNull}};
|
use std::{ffi::{CString, CStr}, mem, ptr::{self, NonNull}, str::Utf8Error};
|
||||||
|
|
||||||
use mlua_sys as lua;
|
use mlua_sys as lua;
|
||||||
|
|
||||||
use crate::{lua_error_guard, Error, FromLuaStack, FromLuaStackMulti, Function, LuaRef, PushToLuaStack, PushToLuaStackMulti, Result, Table};
|
use crate::{ensure_type, lua_error_guard, AnyUserdata, Error, FromLuaStack, FromLuaStackMulti, Function, LuaRef, PushToLuaStack, PushToLuaStackMulti, Result, StackGuard, Table, Userdata, UserdataBuilder, Value};
|
||||||
|
|
||||||
|
pub fn ptr_to_string(ptr: *const i8) -> std::result::Result<String, Utf8Error> {
|
||||||
|
let c = unsafe { CStr::from_ptr(ptr) };
|
||||||
|
let s= c.to_str()?;
|
||||||
|
Ok(s.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub enum StdLibrary {
|
pub enum StdLibrary {
|
||||||
|
@ -167,7 +173,7 @@ impl State {
|
||||||
unsafe {
|
unsafe {
|
||||||
let s = self.state_ptr();
|
let s = self.state_ptr();
|
||||||
lua::lua_rawgeti(s, lua::LUA_REGISTRYINDEX, lua::LUA_RIDX_GLOBALS);
|
lua::lua_rawgeti(s, lua::LUA_REGISTRYINDEX, lua::LUA_RIDX_GLOBALS);
|
||||||
Table::with_ref(self, LuaRef::from_stack(self)?, None)
|
Table::with_ref(self, LuaRef::from_stack(self)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,11 +186,11 @@ impl State {
|
||||||
let tyname = lua::lua_typename(s, ty);
|
let tyname = lua::lua_typename(s, ty);
|
||||||
let tyname = CStr::from_ptr(tyname);
|
let tyname = CStr::from_ptr(tyname);
|
||||||
let tyname = tyname.to_str().unwrap();
|
let tyname = tyname.to_str().unwrap();
|
||||||
println!("{}: {}", i, tyname);
|
println!("{}: {}", -(t + 1 - i), tyname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_function<'a, A, R, F>(&'a self, f: F) -> Result<Function<'a>>
|
pub fn create_function<'a, A, R, F>(&self, f: F) -> Result<Function>
|
||||||
where
|
where
|
||||||
A: FromLuaStackMulti<'a>,
|
A: FromLuaStackMulti<'a>,
|
||||||
R: PushToLuaStackMulti<'a>,
|
R: PushToLuaStackMulti<'a>,
|
||||||
|
@ -268,4 +274,63 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create userdata
|
||||||
|
pub fn create_userdata<T: Userdata + 'static>(&self, name: &str, data: T) -> Result<AnyUserdata> {
|
||||||
|
unsafe {
|
||||||
|
self.ensure_stack(2)?;
|
||||||
|
let _g = StackGuard::new(self);
|
||||||
|
let s = self.state_ptr();
|
||||||
|
|
||||||
|
let ptr = lua::lua_newuserdata(s, mem::size_of::<T>()).cast::<T>();
|
||||||
|
ptr::write(ptr, data);
|
||||||
|
|
||||||
|
let name_cstr = format!("{}\0", name);
|
||||||
|
let name_cstr = name_cstr.as_str();
|
||||||
|
let name_cstr = name_cstr.as_ptr() as *const i8;
|
||||||
|
|
||||||
|
// attempt to get the metatable
|
||||||
|
lua::lua_pushstring(s, name_cstr);
|
||||||
|
let ty = lua::lua_rawget(s, lua::LUA_REGISTRYINDEX);
|
||||||
|
|
||||||
|
if ty == lua::LUA_TNIL {
|
||||||
|
lua::lua_pop(s, 1); // remove nil
|
||||||
|
|
||||||
|
// if the metatable is not made yet, make it
|
||||||
|
let mt = self.create_userdata_metatable::<T>()?;
|
||||||
|
let mt = mt.get_metatable().unwrap(); // the table 100% has a metatable
|
||||||
|
mt.push_to_lua_stack(self)?;
|
||||||
|
} else if ty != lua::LUA_TTABLE {
|
||||||
|
return Err(Error::RegistryConflict(name.to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
lua::lua_setmetatable(s, -2);
|
||||||
|
|
||||||
|
AnyUserdata::from_lua_stack(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)?;
|
||||||
|
|
||||||
|
let getters = builder.field_getters;
|
||||||
|
let name = builder.name.unwrap();
|
||||||
|
|
||||||
|
let mt = self.create_meta_table(&name)?;
|
||||||
|
|
||||||
|
if !getters.is_empty() {
|
||||||
|
let index_fn = self.create_function(move |lua: &State, (ud, key): (AnyUserdata, String)| {
|
||||||
|
if let Some(getter) = getters.get(&key) {
|
||||||
|
let r = getter(lua, Value::Userdata(ud))?;
|
||||||
|
Ok(r)
|
||||||
|
} else {
|
||||||
|
Ok(Value::Nil)
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
|
||||||
|
mt.set_meta("__index", index_fn)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(mt)
|
||||||
|
}
|
||||||
}
|
}
|
72
src/table.rs
72
src/table.rs
|
@ -3,7 +3,7 @@ use std::{ffi::CStr, ops::Deref, sync::Arc};
|
||||||
|
|
||||||
use mlua_sys as lua;
|
use mlua_sys as lua;
|
||||||
|
|
||||||
use crate::{FromLuaStack, LuaRef, PushToLuaStack, Result, StackGuard, State};
|
use crate::{ensure_type, FromLuaStack, LuaRef, PushToLuaStack, Result, StackGuard, State};
|
||||||
|
|
||||||
pub(crate) struct MetaTableInfo {
|
pub(crate) struct MetaTableInfo {
|
||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
|
@ -13,8 +13,8 @@ pub(crate) struct MetaTableInfo {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Table<'a> {
|
pub struct Table<'a> {
|
||||||
state: &'a State,
|
state: &'a State,
|
||||||
lref: LuaRef,
|
pub(crate) lref: LuaRef,
|
||||||
meta: Option<LuaRef>, // Some if this table is a metatable
|
pub(crate) meta: Option<LuaRef>, // Some if this table is a metatable
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Table<'a> {
|
impl<'a> Table<'a> {
|
||||||
|
@ -38,12 +38,17 @@ impl<'a> Table<'a> {
|
||||||
pub fn new_meta_table(state: &'a State, name: &str) -> Result<Self> {
|
pub fn new_meta_table(state: &'a State, name: &str) -> Result<Self> {
|
||||||
let name_term = format!("{}\0", name);
|
let name_term = format!("{}\0", name);
|
||||||
let name_term_c = name_term.as_str().as_ptr() as *const i8;
|
let name_term_c = name_term.as_str().as_ptr() as *const i8;
|
||||||
let name_term_arc = Arc::new(name_term_c);
|
|
||||||
|
|
||||||
let (lref, meta_ref) = unsafe {
|
let (lref, meta_ref) = unsafe {
|
||||||
let _g = StackGuard::new(state);
|
let _g = StackGuard::new(state);
|
||||||
state.ensure_stack(2)?;
|
state.ensure_stack(2)?;
|
||||||
|
|
||||||
|
// create the table, this will be retrieved from
|
||||||
|
// stack after the metatable is created
|
||||||
|
let s = state.state_ptr();
|
||||||
|
lua::lua_newtable(s);
|
||||||
|
//let table_idx = lua::lua_gettop(s);
|
||||||
|
|
||||||
let s = state.state_ptr();
|
let s = state.state_ptr();
|
||||||
if lua::luaL_newmetatable(s, name_term_c) == 0 {
|
if lua::luaL_newmetatable(s, name_term_c) == 0 {
|
||||||
// lua::luaL_getmetatable does not return the type that was
|
// lua::luaL_getmetatable does not return the type that was
|
||||||
|
@ -55,11 +60,11 @@ impl<'a> Table<'a> {
|
||||||
return Err(crate::Error::RegistryConflict(name.to_string()));
|
return Err(crate::Error::RegistryConflict(name.to_string()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
lua::lua_pushvalue(s, lua::lua_gettop(s));
|
||||||
|
lua::lua_setmetatable(s, -3); // -3 here since the metatable was added twice
|
||||||
let meta = LuaRef::from_stack(state)?;
|
let meta = LuaRef::from_stack(state)?;
|
||||||
|
|
||||||
|
// retrieve the table created before the metatable
|
||||||
let s = state.state_ptr();
|
|
||||||
lua::lua_newtable(s);
|
|
||||||
(LuaRef::from_stack(state)?, meta)
|
(LuaRef::from_stack(state)?, meta)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -71,7 +76,7 @@ impl<'a> Table<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a table with a lua reference to one.
|
/// Construct a table with a lua reference to one.
|
||||||
pub fn with_ref(state: &'a State, lua_ref: LuaRef, name: Option<String>) -> Result<Self> {
|
pub fn with_ref(state: &'a State, lua_ref: LuaRef) -> Result<Self> {
|
||||||
let s = state.state_ptr();
|
let s = state.state_ptr();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -79,7 +84,7 @@ impl<'a> Table<'a> {
|
||||||
|
|
||||||
lua_ref.push_to_lua_stack(state)?;
|
lua_ref.push_to_lua_stack(state)?;
|
||||||
if lua::lua_istable(s, -1) == 0 {
|
if lua::lua_istable(s, -1) == 0 {
|
||||||
panic!("Index is not a table")
|
panic!("Provided reference is not a table")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,8 +100,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,
|
K: PushToLuaStack<'a>,
|
||||||
V: PushToLuaStack
|
V: PushToLuaStack<'a>
|
||||||
{
|
{
|
||||||
let s = self.state.state_ptr();
|
let s = self.state.state_ptr();
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -126,9 +131,9 @@ impl<'a> Table<'a> {
|
||||||
/// Get a value from the table.
|
/// Get a value from the table.
|
||||||
///
|
///
|
||||||
/// 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>(&'a self, key: K) -> Result<V>
|
pub fn get<K, V>(&self, key: K) -> Result<V>
|
||||||
where
|
where
|
||||||
K: PushToLuaStack,
|
K: PushToLuaStack<'a>,
|
||||||
V: FromLuaStack<'a>,
|
V: FromLuaStack<'a>,
|
||||||
{
|
{
|
||||||
let s = self.state.state_ptr();
|
let s = self.state.state_ptr();
|
||||||
|
@ -167,8 +172,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,
|
K: PushToLuaStack<'a>,
|
||||||
V: PushToLuaStack
|
V: PushToLuaStack<'a>
|
||||||
{
|
{
|
||||||
let s = self.state.state_ptr();
|
let s = self.state.state_ptr();
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -189,7 +194,7 @@ 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>(&'a self, key: K) -> Result<V>
|
||||||
where
|
where
|
||||||
K: PushToLuaStack,
|
K: PushToLuaStack<'a>,
|
||||||
V: FromLuaStack<'a>,
|
V: FromLuaStack<'a>,
|
||||||
{
|
{
|
||||||
let s = self.state.state_ptr();
|
let s = self.state.state_ptr();
|
||||||
|
@ -219,10 +224,14 @@ impl<'a> Table<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set something in the metatable
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
/// Panics 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,
|
K: PushToLuaStack<'a>,
|
||||||
V: PushToLuaStack
|
V: PushToLuaStack<'a>
|
||||||
{
|
{
|
||||||
let mt = self.meta.as_ref()
|
let mt = self.meta.as_ref()
|
||||||
.expect("this table is not a meta table!");
|
.expect("this table is not a meta table!");
|
||||||
|
@ -232,7 +241,6 @@ impl<'a> Table<'a> {
|
||||||
self.state.ensure_stack(3)?;
|
self.state.ensure_stack(3)?;
|
||||||
let _g = StackGuard::new(self.state);
|
let _g = StackGuard::new(self.state);
|
||||||
|
|
||||||
//lua::luaL_getmetatable(s, **cname);
|
|
||||||
mt.push_to_lua_stack(self.state)?;
|
mt.push_to_lua_stack(self.state)?;
|
||||||
key.push_to_lua_stack(self.state)?;
|
key.push_to_lua_stack(self.state)?;
|
||||||
val.push_to_lua_stack(self.state)?;
|
val.push_to_lua_stack(self.state)?;
|
||||||
|
@ -241,9 +249,17 @@ impl<'a> Table<'a> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a handle to the metatable of this table
|
||||||
|
pub fn get_metatable(&self) -> Option<Table> {
|
||||||
|
self.meta.clone()
|
||||||
|
.map(|r|
|
||||||
|
Table::with_ref(self.state, r).unwrap()
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PushToLuaStack for Table<'a> {
|
impl<'a> PushToLuaStack<'a> for Table<'a> {
|
||||||
unsafe fn push_to_lua_stack(&self, state: &State) -> Result<()> {
|
unsafe fn push_to_lua_stack(&self, state: &State) -> Result<()> {
|
||||||
// no need to ensure stack, the LuaRef does it for us
|
// no need to ensure stack, the LuaRef does it for us
|
||||||
self.lref.push_to_lua_stack(state)?;
|
self.lref.push_to_lua_stack(state)?;
|
||||||
|
@ -254,19 +270,7 @@ impl<'a> PushToLuaStack for Table<'a> {
|
||||||
|
|
||||||
impl<'a> FromLuaStack<'a> for Table<'a> {
|
impl<'a> FromLuaStack<'a> for Table<'a> {
|
||||||
unsafe fn from_lua_stack(state: &'a State) -> Result<Self> {
|
unsafe fn from_lua_stack(state: &'a State) -> Result<Self> {
|
||||||
let s = state.state_ptr();
|
ensure_type(state, lua::LUA_TTABLE, -1)?;
|
||||||
|
Table::with_ref(state, LuaRef::from_stack(state)?)
|
||||||
let ty = lua::lua_type(s, -1);
|
|
||||||
if ty == lua::LUA_TTABLE {
|
|
||||||
let t = Table::with_ref(state, LuaRef::from_stack(state)?, None);
|
|
||||||
|
|
||||||
t
|
|
||||||
} else {
|
|
||||||
let tyname = lua::lua_typename(s, ty);
|
|
||||||
let cstr = CStr::from_ptr(tyname);
|
|
||||||
let s = cstr.to_str()
|
|
||||||
.expect("Lua type has invalid bytes!");
|
|
||||||
Err(crate::Error::UnexpectedType("Table".to_string(), s.to_string()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,164 @@
|
||||||
|
use std::{collections::HashMap, marker::PhantomData, sync::Arc};
|
||||||
|
|
||||||
|
use crate::{ensure_type, AsLua, FromLua, FromLuaStack, LuaRef, PushToLuaStack, State, Table, Value};
|
||||||
|
|
||||||
|
use mlua_sys as lua;
|
||||||
|
|
||||||
|
//pub type FieldSetter<T> = fn(lua: &State, this: &T);
|
||||||
|
//pub type FieldGetter<T, U> = fn(lua: &State, this: &T, val: &U);
|
||||||
|
|
||||||
|
pub trait FieldSetter {
|
||||||
|
fn set_field(&self, val: Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait FieldGetter {
|
||||||
|
fn get_field(&self) -> Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserdataFn<'a> = Box<dyn Fn(&'a State, Value<'a>) -> crate::Result<Value<'a>>>;
|
||||||
|
|
||||||
|
pub struct UserdataBuilder<'a, T> {
|
||||||
|
pub(crate) name: Option<String>,
|
||||||
|
pub(crate) field_getters: HashMap<String, UserdataFn<'a>>,
|
||||||
|
_marker: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> UserdataBuilder<'a, T> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
name: None,
|
||||||
|
field_getters: HashMap::new(),
|
||||||
|
_marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&mut self, name: &str) -> &mut Self {
|
||||||
|
self.name = Some(name.to_string());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn field_getter<F, R>(&mut self, name: &str, f: F) -> &mut Self
|
||||||
|
where
|
||||||
|
F: Fn(&'a State, &T) -> crate::Result<R> + 'static,
|
||||||
|
R: AsLua<'a>,
|
||||||
|
{
|
||||||
|
let wrap = move |lua: &'a State, val: Value<'a>| {
|
||||||
|
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))
|
||||||
|
};
|
||||||
|
self.field_getters.insert(name.to_string(), Box::new(wrap));
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_meta_table(self, state: &'a State, table: &Table<'a>) -> crate::Result<()> {
|
||||||
|
//let this: Self = unsafe { std::mem::transmute(self) };
|
||||||
|
//let getters = *self.field_getters;
|
||||||
|
|
||||||
|
/* let index_fn = state.create_function(move |lua: &'a State, (ud, key): (AnyUserdata<'a>, String)| {
|
||||||
|
let ud_ref = ud.as_ref::<T>()?;
|
||||||
|
|
||||||
|
if let Some(getter) = self.field_getters.get(&key) {
|
||||||
|
let r = getter(lua, ome(ud_ref), Value::Nil)?;
|
||||||
|
|
||||||
|
let r = unsafe { std::mem::transmute(r) };
|
||||||
|
|
||||||
|
Ok(r)
|
||||||
|
} else {
|
||||||
|
//ud.get::<_, Value<'a>>(key)
|
||||||
|
Ok(Value::Nil)
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
|
||||||
|
table.set("__index", index_fn)?; */
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pub fn wrap_builder<U, F>(this: &mut UserdataBuilder<'a, T>, other: UserdataBuilder<'a, U>, to_proxied: F)
|
||||||
|
where
|
||||||
|
F: Fn(&'a T) -> &'a U + 'a,
|
||||||
|
{
|
||||||
|
let to_proxied = Arc::new(to_proxied);
|
||||||
|
for (lbl, getter) in other.field_getters.into_iter() {
|
||||||
|
let to_proxied_cl = to_proxied.clone();
|
||||||
|
let new_getter = move |lua: &'a State, this: Option<&T>, val: Value<'a>| {
|
||||||
|
let proxy = this.map(|t| to_proxied_cl(t));
|
||||||
|
getter(lua, proxy, val)
|
||||||
|
};
|
||||||
|
this.field_getters.insert(lbl, Box::new(new_getter));
|
||||||
|
}
|
||||||
|
} */
|
||||||
|
|
||||||
|
/* pub fn into_userdata(self, state: &'a State, data: T) -> crate::Result<Table<'a>> {
|
||||||
|
let name = self.name
|
||||||
|
.expect("No name was set for userdata!");
|
||||||
|
|
||||||
|
let getters = self.field_getters.clone();
|
||||||
|
let index_fn = state.create_function(move |lua: &'a State, (ud, key): (AnyUserdata<'a>, String)| {
|
||||||
|
let ud_ref = ud.as_ref::<T>()?;
|
||||||
|
|
||||||
|
if let Some(getter) = getters.get(&key) {
|
||||||
|
getter(lua, Some(ud_ref), Value::Nil)
|
||||||
|
} else {
|
||||||
|
//ud.get::<_, Value<'a>>(key)
|
||||||
|
Ok(Value::Nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
//todo!()
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let mt = state.create_meta_table(&name)?;
|
||||||
|
mt.set("__index", index_fn)?;
|
||||||
|
|
||||||
|
Ok(mt)
|
||||||
|
} */
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Userdata: Sized {
|
||||||
|
fn build<'a>(builder: &mut UserdataBuilder<'a, Self>) -> crate::Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A handle to some userdata on the stack
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct AnyUserdata<'a> {
|
||||||
|
lref: LuaRef,
|
||||||
|
state: &'a State,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> AnyUserdata<'a> {
|
||||||
|
pub fn from_ref(state: &'a State, lref: LuaRef) -> Self {
|
||||||
|
Self {
|
||||||
|
lref,
|
||||||
|
state,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_ref<T>(&self) -> crate::Result<&'a T> {
|
||||||
|
unsafe {
|
||||||
|
let s = self.state.state_ptr();
|
||||||
|
|
||||||
|
self.lref.push_to_lua_stack(self.state)?;
|
||||||
|
let cptr = lua::lua_touserdata(s, -1);
|
||||||
|
Ok(cptr.cast::<T>().as_ref().unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> FromLuaStack<'a> for AnyUserdata<'a> {
|
||||||
|
unsafe fn from_lua_stack(state: &'a State) -> crate::Result<Self> {
|
||||||
|
ensure_type(state, lua::LUA_TUSERDATA, -1)?;
|
||||||
|
|
||||||
|
Ok(AnyUserdata {
|
||||||
|
lref: LuaRef::from_stack(state)?,
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
use std::ffi::CStr;
|
||||||
|
|
||||||
|
use crate::State;
|
||||||
|
|
||||||
|
use mlua_sys as lua;
|
||||||
|
|
||||||
|
pub unsafe fn ensure_type(state: &State, typ: i32, idx: i32) -> crate::Result<()> {
|
||||||
|
let s = state.state_ptr();
|
||||||
|
|
||||||
|
let lua_type = lua::lua_type(s, idx);
|
||||||
|
|
||||||
|
if lua_type == typ {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
let exp_tyname = lua::lua_typename(s, typ);
|
||||||
|
let exp_cstr = CStr::from_ptr(exp_tyname);
|
||||||
|
let exp_s = exp_cstr.to_str()
|
||||||
|
.expect("Lua type has invalid bytes!");
|
||||||
|
|
||||||
|
let tyname = lua::lua_typename(s, lua_type);
|
||||||
|
let cstr = CStr::from_ptr(tyname);
|
||||||
|
let s = cstr.to_str()
|
||||||
|
.expect("Lua type has invalid bytes!");
|
||||||
|
|
||||||
|
println!("ty = {}, typ = {}", lua_type, typ);
|
||||||
|
|
||||||
|
Err(crate::Error::UnexpectedType(exp_s.to_string(), s.to_string()))
|
||||||
|
}
|
||||||
|
}
|
128
src/value.rs
128
src/value.rs
|
@ -1,19 +1,54 @@
|
||||||
use crate::{Function, Table, PushToLuaStack};
|
use std::ffi::CStr;
|
||||||
|
|
||||||
|
use crate::{AnyUserdata, FromLuaStack, Function, PushToLuaStack, State, Table};
|
||||||
|
|
||||||
use mlua_sys as lua;
|
use mlua_sys as lua;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub enum Value<'a> {
|
pub enum Value<'a> {
|
||||||
|
Nil,
|
||||||
Number(f64),
|
Number(f64),
|
||||||
String(String),
|
String(String),
|
||||||
Function(Function<'a>),
|
Function(Function<'a>),
|
||||||
Table(Table<'a>),
|
Table(Table<'a>),
|
||||||
|
Userdata(AnyUserdata<'a>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PushToLuaStack for Value<'a> {
|
impl<'a> Value<'a> {
|
||||||
|
pub fn is_nil(&self) -> bool {
|
||||||
|
matches!(self, Value::Nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn type_name(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Value::Nil => "Nil",
|
||||||
|
Value::Number(_) => "Number",
|
||||||
|
Value::String(_) => "String",
|
||||||
|
Value::Function(_) => "Function",
|
||||||
|
Value::Table(_) => "Table",
|
||||||
|
Value::Userdata(_) => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_userdata(&self) -> crate::Result<&AnyUserdata> {
|
||||||
|
match self {
|
||||||
|
Value::Userdata(ud) => Ok(ud),
|
||||||
|
_ => {
|
||||||
|
Err(crate::Error::UnexpectedType("Userdata".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: &crate::State) -> crate::Result<()> {
|
||||||
let s = state.state_ptr();
|
let s = state.state_ptr();
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
|
Value::Nil => {
|
||||||
|
state.ensure_stack(1)?;
|
||||||
|
lua::lua_pushnil(s);
|
||||||
|
}
|
||||||
Value::Number(n) => {
|
Value::Number(n) => {
|
||||||
state.ensure_stack(1)?;
|
state.ensure_stack(1)?;
|
||||||
lua::lua_pushnumber(s, *n);
|
lua::lua_pushnumber(s, *n);
|
||||||
|
@ -25,14 +60,91 @@ impl<'a> PushToLuaStack for Value<'a> {
|
||||||
let cstr = s.as_ptr() as *const i8;
|
let cstr = s.as_ptr() as *const i8;
|
||||||
lua::lua_pushstring(state.state_ptr(), cstr);
|
lua::lua_pushstring(state.state_ptr(), cstr);
|
||||||
}
|
}
|
||||||
Value::Function(f) => {
|
Value::Function(f) => f.push_to_lua_stack(state)?,
|
||||||
f.push_to_lua_stack(state)?;
|
Value::Table(t) => t.push_to_lua_stack(state)?,
|
||||||
},
|
Value::Userdata(ud) => ud.push_to_lua_stack(state)?,
|
||||||
Value::Table(t) => {
|
|
||||||
t.push_to_lua_stack(state)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> FromLuaStack<'a> for Value<'a> {
|
||||||
|
unsafe fn from_lua_stack(state: &'a State) -> crate::Result<Self> {
|
||||||
|
|
||||||
|
let s = state.state_ptr();
|
||||||
|
let ty = lua::lua_type(s, -1);
|
||||||
|
|
||||||
|
let val = match ty {
|
||||||
|
lua::LUA_TNIL => {
|
||||||
|
lua::lua_pop(s, 1);
|
||||||
|
|
||||||
|
Ok(Value::Nil)
|
||||||
|
},
|
||||||
|
lua::LUA_TNUMBER => {
|
||||||
|
let n = lua::lua_tonumber(s, -1);
|
||||||
|
lua::lua_pop(s, 1);
|
||||||
|
|
||||||
|
Ok(Value::Number(n))
|
||||||
|
}
|
||||||
|
lua::LUA_TSTRING => {
|
||||||
|
let cstr = lua::lua_tostring(s, -1);
|
||||||
|
lua::lua_pop(s, 1);
|
||||||
|
|
||||||
|
let cstr = CStr::from_ptr(cstr);
|
||||||
|
let lua_str = cstr.to_str().unwrap().to_string();
|
||||||
|
Ok(Value::String(lua_str))
|
||||||
|
},
|
||||||
|
lua::LUA_TFUNCTION => {
|
||||||
|
Function::from_lua_stack(state)
|
||||||
|
.map(|f| Value::Function(f))
|
||||||
|
},
|
||||||
|
lua::LUA_TTABLE => {
|
||||||
|
Table::from_lua_stack(state)
|
||||||
|
.map(|t| Value::Table(t))
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
let s = lua::lua_typename(s, ty);
|
||||||
|
let s = CStr::from_ptr(s);
|
||||||
|
let s = s.to_str().unwrap();
|
||||||
|
unimplemented!("Not yet able to get '{}' as a value from the stack", s);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait AsLua<'a> {
|
||||||
|
fn as_lua(&self, lua: &'a State) -> crate::Result<Value<'a>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait FromLua: Sized {
|
||||||
|
fn from_lua(lua: &State, val: Value) -> crate::Result<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* impl<'a> AsLua<'a> for Value<'a> {
|
||||||
|
fn as_lua(&self, lua: &'a State) -> crate::Result<Value<'a>> {
|
||||||
|
Ok(self.clone())
|
||||||
|
}
|
||||||
|
} */
|
||||||
|
|
||||||
|
/* impl<'a, T: AsLua<'a>> PushToLuaStack<'a> for T {
|
||||||
|
unsafe fn push_to_lua_stack(&self, state: &'a State) -> crate::Result<()> {
|
||||||
|
let v = self.as_lua(state)?;
|
||||||
|
v.push_to_lua_stack(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
impl<'a, T: FromLua> FromLuaStack<'a> for T {
|
||||||
|
unsafe fn from_lua_stack(state: &'a State) -> crate::Result<Self> {
|
||||||
|
let v = Value::from_lua_stack(state)?;
|
||||||
|
T::from_lua(state, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> AsLua<'a> for () {
|
||||||
|
fn as_lua(&self, lua: &'a State) -> crate::Result<Value<'a>> {
|
||||||
|
Ok(Value::Nil)
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
---
|
||||||
|
---Print a formatted string. Put `{}` where you want something to be formatted in its place.
|
||||||
|
---
|
||||||
|
---```lua
|
||||||
|
---local yummy_food = "chips"
|
||||||
|
---printf("Lets eat {} together!", yummy_food)
|
||||||
|
---```
|
||||||
|
---
|
||||||
|
---The items provided in the variable arguments must implement `tostring`!
|
||||||
|
---
|
||||||
|
---@param str string
|
||||||
|
---@param ... any
|
||||||
|
function printf(str, ...)
|
||||||
|
local fleft, fright = str:find("{}")
|
||||||
|
local formatted = ""
|
||||||
|
-- current vararg index
|
||||||
|
local arg = 1
|
||||||
|
|
||||||
|
while (fleft ~= nil and fright ~= nil) do
|
||||||
|
formatted = formatted .. str:sub(0, fleft - 1)
|
||||||
|
formatted = formatted .. tostring(select(arg, ...))
|
||||||
|
|
||||||
|
str = str:sub(fright + 1, str:len())
|
||||||
|
|
||||||
|
fleft, fright = str:find("{}")
|
||||||
|
arg = arg + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
formatted = formatted .. str
|
||||||
|
print(formatted)
|
||||||
|
end
|
||||||
|
|
||||||
|
---
|
||||||
|
---Recursively dumps a table as a string.
|
||||||
|
---
|
||||||
|
---@param obj table
|
||||||
|
---@return string
|
||||||
|
---@nodiscard
|
||||||
|
function dump_table(obj)
|
||||||
|
if type(obj) == 'table' then
|
||||||
|
local s = '{ '
|
||||||
|
for k,v in pairs(obj) do
|
||||||
|
if type(k) ~= 'number' then k = '"'..k..'"' end
|
||||||
|
s = s .. '['..k..'] = ' .. dump_table(v) .. ','
|
||||||
|
end
|
||||||
|
return s .. '} '
|
||||||
|
else
|
||||||
|
return tostring(obj)
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue