Code cleanup, separate things to other source files
This commit is contained in:
parent
ab99ff3c31
commit
80b9a4ef35
|
@ -17,16 +17,6 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cstr"
|
|
||||||
version = "0.2.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8aa998c33a6d3271e3678950a22134cd7dd27cef86dee1b611b5b14207d1d90b"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.152"
|
version = "0.2.152"
|
||||||
|
@ -37,7 +27,6 @@ checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
|
||||||
name = "lua-ffi"
|
name = "lua-ffi"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cstr",
|
|
||||||
"mlua-sys",
|
"mlua-sys",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
|
@ -6,6 +6,5 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cstr = "0.2.11"
|
|
||||||
mlua-sys = { version = "0.5.0", features = ["lua54"] }
|
mlua-sys = { version = "0.5.0", features = ["lua54"] }
|
||||||
thiserror = "1.0.56"
|
thiserror = "1.0.56"
|
||||||
|
|
|
@ -0,0 +1,200 @@
|
||||||
|
use mlua_sys as lua;
|
||||||
|
|
||||||
|
pub mod state;
|
||||||
|
use state::*;
|
||||||
|
|
||||||
|
pub mod table;
|
||||||
|
use table::*;
|
||||||
|
|
||||||
|
pub mod function;
|
||||||
|
use function::*;
|
||||||
|
|
||||||
|
pub mod value;
|
||||||
|
use value::*;
|
||||||
|
|
||||||
|
pub mod guard;
|
||||||
|
use guard::*;
|
||||||
|
|
||||||
|
pub mod userdata;
|
||||||
|
use userdata::*;
|
||||||
|
|
||||||
|
pub mod util;
|
||||||
|
use util::*;
|
||||||
|
|
||||||
|
pub mod chunk;
|
||||||
|
use chunk::*;
|
||||||
|
|
||||||
|
pub mod error;
|
||||||
|
use error::*;
|
||||||
|
|
||||||
|
pub mod lref;
|
||||||
|
use lref::*;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub mod tests;
|
||||||
|
|
||||||
|
/* fn main() -> Result<()> {
|
||||||
|
let lua = State::new();
|
||||||
|
lua.expose_libraries(&[StdLibrary::Debug, StdLibrary::Package]);
|
||||||
|
|
||||||
|
let globals = lua.globals()?;
|
||||||
|
|
||||||
|
let v1 = RefCell::new(Vec2 { x: 50.0, y: 5.0 });
|
||||||
|
let ud = lua.create_userdata(UserdataRef::from(v1.borrow()))?;
|
||||||
|
globals.set("v1", ud)?;
|
||||||
|
|
||||||
|
let v2 = Vec2 { x: 10.0, y: 15.0 };
|
||||||
|
let ud = lua.create_userdata(UserdataRef::from(&v2))?;
|
||||||
|
globals.set("v2", ud)?;
|
||||||
|
|
||||||
|
//lua.gc_stop()?;
|
||||||
|
let chunk = lua.load(
|
||||||
|
"text.lua",
|
||||||
|
r#"
|
||||||
|
require "util"
|
||||||
|
|
||||||
|
--if vec2 ~= nil then
|
||||||
|
print("v1: (" .. v1.x .. ", " .. v1.y .. ")")
|
||||||
|
--print("v2: (" .. v2.x .. ", " .. v2.y .. ")")
|
||||||
|
--end
|
||||||
|
|
||||||
|
--print("vec2.x = " .. vec2.x)
|
||||||
|
--print("vec2.y = " .. vec2.y)
|
||||||
|
"#,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
const MAX_RUNS: i32 = 400;
|
||||||
|
for i in 0..MAX_RUNS {
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
//print_refs(&lua).unwrap();
|
||||||
|
println!("i = {}", i);
|
||||||
|
globals.set("v1", Value::Nil)?;
|
||||||
|
lua.gc_collect()?;
|
||||||
|
|
||||||
|
let mut t = v1.borrow_mut();
|
||||||
|
t.x += 50.0;
|
||||||
|
t.y += 5.0;
|
||||||
|
drop(t);
|
||||||
|
|
||||||
|
let ud = lua.create_userdata(UserdataRef::from(v1.borrow()))?;
|
||||||
|
globals.raw_set("v1", ud)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
assert_eq!(lua::lua_gettop(lua.state_ptr()), 0); // ensure that nothing is left on the stack
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
} */
|
||||||
|
|
||||||
|
pub trait PushToLuaStack<'a> {
|
||||||
|
unsafe fn push_to_lua_stack(&self, state: &'a State) -> Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait FromLuaStack<'a>: Sized {
|
||||||
|
unsafe fn from_lua_stack(state: &'a State) -> Result<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> PushToLuaStack<'a> for () {
|
||||||
|
unsafe fn push_to_lua_stack(&self, _state: &'a State) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: PushToLuaStack<'a>> PushToLuaStack<'a> for Option<T> {
|
||||||
|
unsafe fn push_to_lua_stack(&self, state: &'a State) -> Result<()> {
|
||||||
|
if let Some(v) = self {
|
||||||
|
v.push_to_lua_stack(state)?;
|
||||||
|
} else {
|
||||||
|
unsafe {
|
||||||
|
lua::lua_pushnil(state.state_ptr());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implements PushToLuaStack for a number
|
||||||
|
macro_rules! impl_as_lua_number {
|
||||||
|
($ty: ident) => {
|
||||||
|
impl<'a> AsLua<'a> for $ty {
|
||||||
|
fn as_lua(&self, _lua: &'a State) -> crate::Result<Value<'a>> {
|
||||||
|
Ok(Value::Number(*self as f64))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> FromLua<'a> 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_as_lua_number!(i8);
|
||||||
|
impl_as_lua_number!(i16);
|
||||||
|
impl_as_lua_number!(i32);
|
||||||
|
impl_as_lua_number!(i64);
|
||||||
|
|
||||||
|
impl_as_lua_number!(u8);
|
||||||
|
impl_as_lua_number!(u16);
|
||||||
|
impl_as_lua_number!(u32);
|
||||||
|
impl_as_lua_number!(u64);
|
||||||
|
|
||||||
|
impl_as_lua_number!(f32);
|
||||||
|
impl_as_lua_number!(f64);
|
||||||
|
|
||||||
|
impl<'a> PushToLuaStack<'a> for String {
|
||||||
|
unsafe fn push_to_lua_stack(&self, state: &State) -> Result<()> {
|
||||||
|
state.ensure_stack(1)?;
|
||||||
|
|
||||||
|
self.as_str()
|
||||||
|
.push_to_lua_stack(state)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> FromLua<'a> for String {
|
||||||
|
fn from_lua(_lua: &State, val: Value) -> crate::Result<Self> {
|
||||||
|
val.as_string().cloned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> PushToLuaStack<'a> for &str {
|
||||||
|
unsafe fn push_to_lua_stack(&self, state: &State) -> Result<()> {
|
||||||
|
state.ensure_stack(1)?;
|
||||||
|
|
||||||
|
let s = format!("{}\0", self);
|
||||||
|
let cstr = s.as_ptr() as *const i8;
|
||||||
|
// lua copies the string, so its okay if the string pointer is dropped
|
||||||
|
lua::lua_pushstring(state.state_ptr(), cstr);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::{Error, PushToLuaStack, Result, State};
|
||||||
|
|
||||||
|
use mlua_sys as lua;
|
||||||
|
|
||||||
|
/// A LuaRef is a a handle to something in Lua.
|
||||||
|
///
|
||||||
|
/// These are created with `luaL_ref`, they can be created from anything on the top of the stack
|
||||||
|
/// with [`LuaRef::from_stack`]. The references are automatically freed with `luaL_unref` when
|
||||||
|
/// the inner Arc detects a single strong count.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct LuaRef<'a> {
|
||||||
|
lref: Arc<i32>,
|
||||||
|
state: &'a State,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Drop for LuaRef<'a> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
let s = self.state.state_ptr();
|
||||||
|
|
||||||
|
if Arc::strong_count(&self.lref) == 1 {
|
||||||
|
lua::luaL_unref(s, lua::LUA_REGISTRYINDEX, *self.lref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> LuaRef<'a> {
|
||||||
|
pub fn new(lua_ref: i32, state: &'a State) -> Self {
|
||||||
|
Self {
|
||||||
|
lref: Arc::new(lua_ref),
|
||||||
|
state,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a reference to what is at the top of the stack.
|
||||||
|
pub unsafe fn from_stack(state: &'a State) -> Result<Self> {
|
||||||
|
let s = state.state_ptr();
|
||||||
|
let r = lua::luaL_ref(s, lua::LUA_REGISTRYINDEX);
|
||||||
|
if r == lua::LUA_REFNIL {
|
||||||
|
Err(Error::Nil)
|
||||||
|
} else {
|
||||||
|
Ok(LuaRef::new(r, state))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> PushToLuaStack<'a> for LuaRef<'a> {
|
||||||
|
unsafe fn push_to_lua_stack(&self, state: &State) -> Result<()> {
|
||||||
|
let s = state.state_ptr();
|
||||||
|
|
||||||
|
state.ensure_stack(1)?;
|
||||||
|
let top = lua::lua_gettop(s);
|
||||||
|
let ty = lua::lua_rawgeti(s, lua::LUA_REGISTRYINDEX, *self.lref as i64);
|
||||||
|
let new_top = lua::lua_gettop(s);
|
||||||
|
|
||||||
|
if ty == lua::LUA_TNIL || ty == lua::LUA_TNONE || top == new_top {
|
||||||
|
return Err(Error::Nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
463
src/main.rs
463
src/main.rs
|
@ -1,463 +0,0 @@
|
||||||
use std::{
|
|
||||||
cell::{Ref, RefCell}, ffi::CStr, marker::PhantomData, mem, ops::Deref, sync::Arc
|
|
||||||
};
|
|
||||||
|
|
||||||
use mlua_sys as lua;
|
|
||||||
|
|
||||||
pub mod state;
|
|
||||||
use state::*;
|
|
||||||
|
|
||||||
pub mod table;
|
|
||||||
use table::*;
|
|
||||||
|
|
||||||
pub mod function;
|
|
||||||
use function::*;
|
|
||||||
|
|
||||||
pub mod value;
|
|
||||||
use value::*;
|
|
||||||
|
|
||||||
pub mod guard;
|
|
||||||
use guard::*;
|
|
||||||
|
|
||||||
pub mod userdata;
|
|
||||||
use userdata::*;
|
|
||||||
|
|
||||||
pub mod util;
|
|
||||||
use util::*;
|
|
||||||
|
|
||||||
pub mod chunk;
|
|
||||||
use chunk::*;
|
|
||||||
|
|
||||||
pub mod error;
|
|
||||||
use error::*;
|
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
|
||||||
let lua = State::new();
|
|
||||||
lua.expose_libraries(&[StdLibrary::Debug, StdLibrary::Package]);
|
|
||||||
|
|
||||||
let globals = lua.globals()?;
|
|
||||||
|
|
||||||
let v1 = RefCell::new(Vec2 { x: 50.0, y: 5.0 });
|
|
||||||
let ud = lua.create_userdata(UserdataRef::from(v1.borrow()))?;
|
|
||||||
globals.set("v1", ud)?;
|
|
||||||
|
|
||||||
let v2 = Vec2 { x: 10.0, y: 15.0 };
|
|
||||||
let ud = lua.create_userdata(UserdataRef::from(&v2))?;
|
|
||||||
globals.set("v2", ud)?;
|
|
||||||
|
|
||||||
//lua.gc_stop()?;
|
|
||||||
let chunk = lua.load(
|
|
||||||
"text.lua",
|
|
||||||
r#"
|
|
||||||
require "util"
|
|
||||||
|
|
||||||
--if vec2 ~= nil then
|
|
||||||
print("v1: (" .. v1.x .. ", " .. v1.y .. ")")
|
|
||||||
--print("v2: (" .. v2.x .. ", " .. v2.y .. ")")
|
|
||||||
--end
|
|
||||||
|
|
||||||
--print("vec2.x = " .. vec2.x)
|
|
||||||
--print("vec2.y = " .. vec2.y)
|
|
||||||
"#,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
const MAX_RUNS: i32 = 400;
|
|
||||||
for i in 0..MAX_RUNS {
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
//print_refs(&lua).unwrap();
|
|
||||||
println!("i = {}", i);
|
|
||||||
globals.set("v1", Value::Nil)?;
|
|
||||||
lua.gc_collect()?;
|
|
||||||
|
|
||||||
let mut t = v1.borrow_mut();
|
|
||||||
t.x += 50.0;
|
|
||||||
t.y += 5.0;
|
|
||||||
drop(t);
|
|
||||||
|
|
||||||
let ud = lua.create_userdata(UserdataRef::from(v1.borrow()))?;
|
|
||||||
globals.raw_set("v1", ud)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
assert_eq!(lua::lua_gettop(lua.state_ptr()), 0); // ensure that nothing is left on the stack
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Prints the types of the registry
|
|
||||||
pub fn print_refs(lua: &State) -> Result<()> {
|
|
||||||
unsafe {
|
|
||||||
let _g = StackGuard::new(&lua);
|
|
||||||
let s = lua.state_ptr();
|
|
||||||
|
|
||||||
Value::String(String::from("Hello World")).push_to_lua_stack(&lua)?;
|
|
||||||
let r = lua::luaL_ref(s, lua::LUA_REGISTRYINDEX);
|
|
||||||
|
|
||||||
for i in 0..r {
|
|
||||||
let ty = lua::lua_rawgeti(s, lua::LUA_REGISTRYINDEX, i as i64);
|
|
||||||
|
|
||||||
match ty {
|
|
||||||
lua::LUA_TUSERDATA => {
|
|
||||||
lua::lua_getmetatable(s, -1);
|
|
||||||
lua::lua_pushliteral(s, "__name");
|
|
||||||
lua::lua_rawget(s, -2);
|
|
||||||
|
|
||||||
let v = Value::from_lua_stack(&lua)?;
|
|
||||||
println!("{}: {}", i, v.as_string().unwrap());
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
let tyname = CStr::from_ptr(lua::lua_typename(s, ty));
|
|
||||||
let tyname = tyname.to_str().unwrap();
|
|
||||||
println!("{}: {}", i, tyname);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lua::lua_pop(s, 1);
|
|
||||||
}
|
|
||||||
lua::luaL_unref(s, lua::LUA_REGISTRYINDEX, r);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A LuaRef is a a handle to something in Lua.
|
|
||||||
///
|
|
||||||
/// These are created with `luaL_ref`, they can be created from anything on the top of the stack
|
|
||||||
/// with [`LuaRef::from_stack`]. The references are automatically freed with `luaL_unref` when
|
|
||||||
/// the inner Arc detects a single strong count.
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct LuaRef<'a> {
|
|
||||||
lref: Arc<i32>,
|
|
||||||
state: &'a State,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Drop for LuaRef<'a> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
unsafe {
|
|
||||||
let s = self.state.state_ptr();
|
|
||||||
|
|
||||||
if Arc::strong_count(&self.lref) == 1 {
|
|
||||||
lua::luaL_unref(s, lua::LUA_REGISTRYINDEX, *self.lref);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> LuaRef<'a> {
|
|
||||||
pub fn new(lua_ref: i32, state: &'a State) -> Self {
|
|
||||||
Self {
|
|
||||||
lref: Arc::new(lua_ref),
|
|
||||||
state,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a reference to what is at the top of the stack.
|
|
||||||
pub unsafe fn from_stack(state: &'a State) -> Result<Self> {
|
|
||||||
let s = state.state_ptr();
|
|
||||||
let r = lua::luaL_ref(s, lua::LUA_REGISTRYINDEX);
|
|
||||||
if r == lua::LUA_REFNIL {
|
|
||||||
Err(Error::Nil)
|
|
||||||
} else {
|
|
||||||
Ok(LuaRef::new(r, state))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> PushToLuaStack<'a> for LuaRef<'a> {
|
|
||||||
unsafe fn push_to_lua_stack(&self, state: &State) -> Result<()> {
|
|
||||||
let s = state.state_ptr();
|
|
||||||
|
|
||||||
state.ensure_stack(1)?;
|
|
||||||
let top = lua::lua_gettop(s);
|
|
||||||
let ty = lua::lua_rawgeti(s, lua::LUA_REGISTRYINDEX, *self.lref as i64);
|
|
||||||
let new_top = lua::lua_gettop(s);
|
|
||||||
|
|
||||||
if ty == lua::LUA_TNIL || ty == lua::LUA_TNONE || top == new_top {
|
|
||||||
return Err(Error::Nil);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait PushToLuaStack<'a> {
|
|
||||||
unsafe fn push_to_lua_stack(&self, state: &'a State) -> Result<()>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait FromLuaStack<'a>: Sized {
|
|
||||||
unsafe fn from_lua_stack(state: &'a State) -> Result<Self>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> PushToLuaStack<'a> for () {
|
|
||||||
unsafe fn push_to_lua_stack(&self, _state: &'a State) -> Result<()> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T: PushToLuaStack<'a>> PushToLuaStack<'a> for Option<T> {
|
|
||||||
unsafe fn push_to_lua_stack(&self, state: &'a State) -> Result<()> {
|
|
||||||
if let Some(v) = self {
|
|
||||||
v.push_to_lua_stack(state)?;
|
|
||||||
} else {
|
|
||||||
unsafe {
|
|
||||||
lua::lua_pushnil(state.state_ptr());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Implements PushToLuaStack for a number
|
|
||||||
macro_rules! impl_as_lua_number {
|
|
||||||
($ty: ident) => {
|
|
||||||
impl<'a> AsLua<'a> for $ty {
|
|
||||||
fn as_lua(&self, _lua: &'a State) -> crate::Result<Value<'a>> {
|
|
||||||
Ok(Value::Number(*self as f64))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> FromLua<'a> 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_as_lua_number!(i8);
|
|
||||||
impl_as_lua_number!(i16);
|
|
||||||
impl_as_lua_number!(i32);
|
|
||||||
impl_as_lua_number!(i64);
|
|
||||||
|
|
||||||
impl_as_lua_number!(u8);
|
|
||||||
impl_as_lua_number!(u16);
|
|
||||||
impl_as_lua_number!(u32);
|
|
||||||
impl_as_lua_number!(u64);
|
|
||||||
|
|
||||||
impl_as_lua_number!(f32);
|
|
||||||
impl_as_lua_number!(f64);
|
|
||||||
|
|
||||||
impl<'a> PushToLuaStack<'a> for String {
|
|
||||||
unsafe fn push_to_lua_stack(&self, state: &State) -> Result<()> {
|
|
||||||
state.ensure_stack(1)?;
|
|
||||||
|
|
||||||
let s = format!("{}\0", self);
|
|
||||||
let cstr = s.as_ptr() as *const i8;
|
|
||||||
lua::lua_pushstring(state.state_ptr(), cstr);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> FromLua<'a> for String {
|
|
||||||
fn from_lua(_lua: &State, val: Value) -> crate::Result<Self> {
|
|
||||||
val.as_string().cloned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> PushToLuaStack<'a> for &str {
|
|
||||||
unsafe fn push_to_lua_stack(&self, state: &State) -> Result<()> {
|
|
||||||
state.ensure_stack(1)?;
|
|
||||||
|
|
||||||
let s = format!("{}\0", self);
|
|
||||||
let cstr = s.as_ptr() as *const i8;
|
|
||||||
lua::lua_pushstring(state.state_ptr(), cstr);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub struct Vec3 {
|
|
||||||
x: f32,
|
|
||||||
y: f32,
|
|
||||||
z: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Userdata for Vec3 {
|
|
||||||
fn build<'a>(_state: &State, _builder: &mut UserdataBuilder<'a, Self>) -> crate::Result<()> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn name() -> String {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Vec2 {
|
|
||||||
x: f32,
|
|
||||||
y: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Userdata for Vec2 {
|
|
||||||
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))
|
|
||||||
.field_setter("x", |_, this, x: f32| this.x = x)
|
|
||||||
.field_setter("y", |_, this, y: f32| this.y = y)
|
|
||||||
.function("new", |lua, (x, y)| lua.create_userdata(Vec2 { x, y }))
|
|
||||||
// method test
|
|
||||||
.method("add", |lua, lhs: &Vec2, (rhs,): (Ref<Vec3>,)| {
|
|
||||||
let lx = lhs.x;
|
|
||||||
let ly = lhs.y;
|
|
||||||
|
|
||||||
let rx = rhs.x;
|
|
||||||
let ry = rhs.y;
|
|
||||||
|
|
||||||
lua.create_userdata(Vec2 {
|
|
||||||
x: lx + rx,
|
|
||||||
y: ly + ry,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.meta_method(MetaMethod::Add, |lua, lhs: &Vec2, (rhs,): (Ref<Vec2>,)| {
|
|
||||||
let lx = lhs.x;
|
|
||||||
let ly = lhs.y;
|
|
||||||
|
|
||||||
let rx = rhs.x;
|
|
||||||
let ry = rhs.y;
|
|
||||||
|
|
||||||
lua.create_userdata(Vec2 {
|
|
||||||
x: lx + rx,
|
|
||||||
y: ly + ry,
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn name() -> String {
|
|
||||||
"Vec2".to_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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>(state: &State, builder: &mut UserdataBuilder<'a, Self>) -> crate::Result<()> {
|
|
||||||
let mut other = UserdataBuilder::<T>::new();
|
|
||||||
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;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn name() -> String {
|
|
||||||
let name = format!("{}Proxy", T::name());
|
|
||||||
name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Borrow<'a, T> {
|
|
||||||
Wrapped(Ref<'a, T>),
|
|
||||||
Raw(&'a T),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T> Deref for Borrow<'a, T> {
|
|
||||||
type Target = T;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
match self {
|
|
||||||
Borrow::Wrapped(w) => w,
|
|
||||||
Borrow::Raw(w) => w,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct UserdataRef<'a, T: Userdata> {
|
|
||||||
ud_ptr: Borrow<'a, T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T: Userdata> From<&'a T> for UserdataRef<'static, T> {
|
|
||||||
fn from(value: &'a T) -> Self {
|
|
||||||
let ud = Borrow::Raw(value);
|
|
||||||
|
|
||||||
Self {
|
|
||||||
ud_ptr: unsafe {
|
|
||||||
mem::transmute(ud)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T: Userdata> From<Ref<'a, T>> for UserdataRef<'static, T> {
|
|
||||||
fn from(value: Ref<'a, T>) -> Self {
|
|
||||||
let ud = Borrow::Wrapped(value);
|
|
||||||
|
|
||||||
Self {
|
|
||||||
ud_ptr: unsafe {
|
|
||||||
mem::transmute(ud)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
use std::cell::Ref;
|
||||||
|
|
||||||
|
use crate::{MetaMethod, State, Userdata, UserdataBuilder};
|
||||||
|
|
||||||
|
pub struct Vec2 {
|
||||||
|
x: f32,
|
||||||
|
y: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Userdata for Vec2 {
|
||||||
|
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))
|
||||||
|
.field_setter("x", |_, this, x: f32| this.x = x)
|
||||||
|
.field_setter("y", |_, this, y: f32| this.y = y)
|
||||||
|
.function("new", |lua, (x, y)| lua.create_userdata(Vec2 { x, y }))
|
||||||
|
// method test
|
||||||
|
.method("add", |lua, lhs: &Vec2, (rhs,): (Ref<Vec2>,)| {
|
||||||
|
let lx = lhs.x;
|
||||||
|
let ly = lhs.y;
|
||||||
|
|
||||||
|
let rx = rhs.x;
|
||||||
|
let ry = rhs.y;
|
||||||
|
|
||||||
|
lua.create_userdata(Vec2 {
|
||||||
|
x: lx + rx,
|
||||||
|
y: ly + ry,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.meta_method(MetaMethod::Add, |lua, lhs: &Vec2, (rhs,): (Ref<Vec2>,)| {
|
||||||
|
let lx = lhs.x;
|
||||||
|
let ly = lhs.y;
|
||||||
|
|
||||||
|
let rx = rhs.x;
|
||||||
|
let ry = rhs.y;
|
||||||
|
|
||||||
|
lua.create_userdata(Vec2 {
|
||||||
|
x: lx + rx,
|
||||||
|
y: ly + ry,
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name() -> String {
|
||||||
|
"Vec2".to_string()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
use std::{cell::Ref, mem, ops::Deref};
|
||||||
|
|
||||||
|
use crate::{AnyUserdata, Result, State, Userdata, UserdataBuilder};
|
||||||
|
|
||||||
|
enum Borrow<'a, T> {
|
||||||
|
Wrapped(Ref<'a, T>),
|
||||||
|
Raw(&'a T),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Deref for Borrow<'a, T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
match self {
|
||||||
|
Borrow::Wrapped(w) => w,
|
||||||
|
Borrow::Raw(w) => w,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct UserdataRef<'a, T: Userdata> {
|
||||||
|
borrow: Borrow<'a, T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: Userdata> From<&'a T> for UserdataRef<'static, T> {
|
||||||
|
fn from(value: &'a T) -> Self {
|
||||||
|
let ud = Borrow::Raw(value);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
borrow: unsafe {
|
||||||
|
mem::transmute(ud)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: Userdata> From<Ref<'a, T>> for UserdataRef<'static, T> {
|
||||||
|
fn from(value: Ref<'a, T>) -> Self {
|
||||||
|
let ud = Borrow::Wrapped(value);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
borrow: unsafe {
|
||||||
|
mem::transmute(ud)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.borrow;
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,14 @@ use mlua_sys as lua;
|
||||||
pub mod unsafe_ud;
|
pub mod unsafe_ud;
|
||||||
pub use unsafe_ud::*;
|
pub use unsafe_ud::*;
|
||||||
|
|
||||||
|
pub mod proxy;
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use proxy::*;
|
||||||
|
|
||||||
|
pub mod borrow;
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use borrow::*;
|
||||||
|
|
||||||
/// 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 {
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
use crate::{AsLua, State, Userdata, UserdataBuilder, Value};
|
||||||
|
|
||||||
|
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>(state: &State, builder: &mut UserdataBuilder<'a, Self>) -> crate::Result<()> {
|
||||||
|
let mut other = UserdataBuilder::<T>::new();
|
||||||
|
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;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name() -> String {
|
||||||
|
let name = format!("{}Proxy", T::name());
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
40
src/util.rs
40
src/util.rs
|
@ -1,10 +1,10 @@
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
|
|
||||||
use crate::State;
|
use crate::{FromLuaStack, PushToLuaStack, StackGuard, State, Value};
|
||||||
|
|
||||||
use mlua_sys as lua;
|
use mlua_sys as lua;
|
||||||
|
|
||||||
pub unsafe fn ensure_type(state: &State, typ: i32, idx: i32) -> crate::Result<()> {
|
pub(crate) unsafe fn ensure_type(state: &State, typ: i32, idx: i32) -> crate::Result<()> {
|
||||||
let s = state.state_ptr();
|
let s = state.state_ptr();
|
||||||
|
|
||||||
let lua_type = lua::lua_type(s, idx);
|
let lua_type = lua::lua_type(s, idx);
|
||||||
|
@ -24,4 +24,40 @@ pub unsafe fn ensure_type(state: &State, typ: i32, idx: i32) -> crate::Result<()
|
||||||
|
|
||||||
Err(crate::Error::UnexpectedType(exp_s.to_string(), s.to_string()))
|
Err(crate::Error::UnexpectedType(exp_s.to_string(), s.to_string()))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Iterates through all entries in the registry and prints the types of each entry.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) fn print_registry(lua: &State) -> crate::Result<()> {
|
||||||
|
unsafe {
|
||||||
|
let _g = StackGuard::new(&lua);
|
||||||
|
let s = lua.state_ptr();
|
||||||
|
|
||||||
|
Value::String(String::from("Hello World")).push_to_lua_stack(&lua)?;
|
||||||
|
let r = lua::luaL_ref(s, lua::LUA_REGISTRYINDEX);
|
||||||
|
lua::luaL_unref(s, lua::LUA_REGISTRYINDEX, r);
|
||||||
|
|
||||||
|
for i in 0..r {
|
||||||
|
let ty = lua::lua_rawgeti(s, lua::LUA_REGISTRYINDEX, i as i64);
|
||||||
|
|
||||||
|
match ty {
|
||||||
|
lua::LUA_TUSERDATA => {
|
||||||
|
lua::lua_getmetatable(s, -1);
|
||||||
|
lua::lua_pushliteral(s, "__name");
|
||||||
|
lua::lua_rawget(s, -2);
|
||||||
|
|
||||||
|
let v = Value::from_lua_stack(&lua)?;
|
||||||
|
println!("{}: {}", i, v.as_string().unwrap());
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
let tyname = CStr::from_ptr(lua::lua_typename(s, ty));
|
||||||
|
let tyname = tyname.to_str().unwrap();
|
||||||
|
println!("{}: {}", i, tyname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lua::lua_pop(s, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
Loading…
Reference in New Issue