2024-01-26 04:47:30 +00:00
|
|
|
use std::{ffi::CStr, str::Utf8Error, sync::Arc};
|
2024-01-22 03:53:53 +00:00
|
|
|
|
|
|
|
use lua::{lua_typename, lua_type};
|
|
|
|
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::*;
|
|
|
|
|
2024-01-26 04:47:30 +00:00
|
|
|
pub mod guard;
|
|
|
|
use guard::*;
|
|
|
|
|
|
|
|
/* struct RustFn {
|
|
|
|
|
|
|
|
} */
|
|
|
|
|
|
|
|
/* 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())
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-01-22 03:53:53 +00:00
|
|
|
fn main() -> Result<()> {
|
|
|
|
let lua = State::new();
|
|
|
|
lua.expose_libraries(&[StdLibrary::Debug]);
|
|
|
|
|
2024-01-26 04:47:30 +00:00
|
|
|
let globals = lua.globals()?;
|
|
|
|
|
|
|
|
let a = |lua: &State, (num,): (i32,)| -> Result<i32> {
|
|
|
|
println!("Rust got number from lua: {}", num);
|
|
|
|
Ok(999)
|
|
|
|
};
|
|
|
|
|
|
|
|
let f = lua.create_function(a)?;
|
|
|
|
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 mt = lua.create_meta_table("Vec2")?;
|
|
|
|
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)?;
|
|
|
|
|
2024-01-22 03:53:53 +00:00
|
|
|
let tbl = lua.create_table()?;
|
|
|
|
tbl.set("x", 10)?;
|
|
|
|
|
2024-01-26 04:47:30 +00:00
|
|
|
//let globals = lua.globals()?;
|
2024-01-22 03:53:53 +00:00
|
|
|
globals.set("X", tbl)?;
|
|
|
|
|
|
|
|
lua.execute(r#"
|
|
|
|
--[[function dump_table(tbl)
|
|
|
|
for k, v in pairs(tbl) do
|
|
|
|
if type(v) == "table" then
|
|
|
|
dump_table(v)
|
|
|
|
elseif type(v) == "function" then
|
|
|
|
|
|
|
|
else
|
|
|
|
print(k .. "=" .. tostring(v))
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
for k, v in pairs(_G) do
|
|
|
|
--print("Found global named " .. k)
|
|
|
|
|
|
|
|
if k == "X" then
|
|
|
|
--dump_table(v)
|
|
|
|
end
|
|
|
|
end]]--
|
|
|
|
|
|
|
|
function multiply_print(a, b)
|
2024-01-26 04:47:30 +00:00
|
|
|
print(a .. " * " .. b .. " = " .. a*b)
|
2024-01-22 03:53:53 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function multiply_ret(a, b)
|
|
|
|
return a * b
|
|
|
|
end
|
2024-01-26 04:47:30 +00:00
|
|
|
|
|
|
|
function say_number(a)
|
|
|
|
print("Lua says " .. a)
|
|
|
|
end
|
|
|
|
|
|
|
|
cool_num = 50
|
|
|
|
|
|
|
|
local res = native_test(50)
|
|
|
|
print("Lua got " .. res .. " back from rust!")
|
|
|
|
|
|
|
|
print("Pos1 is (" .. pos1.x .. ", " .. pos1.y .. ")")
|
|
|
|
print("Pos2 is (" .. pos2.x .. ", " .. pos2.y .. ")")
|
|
|
|
|
|
|
|
local add_pos = pos1 + pos2
|
|
|
|
print("Pos1 + pos2 is (" .. add_pos.x .. ", " .. add_pos.y .. ")")
|
2024-01-22 03:53:53 +00:00
|
|
|
"#).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!");
|
|
|
|
|
2024-01-24 01:28:19 +00:00
|
|
|
unsafe {
|
|
|
|
assert_eq!(lua::lua_gettop(lua.state_ptr()), 0); // ensure that nothing is left on the stack
|
|
|
|
}
|
|
|
|
|
2024-01-22 03:53:53 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct LuaRef(Arc<i32>);
|
|
|
|
|
|
|
|
impl From<i32> for LuaRef {
|
|
|
|
fn from(value: i32) -> Self {
|
|
|
|
Self(Arc::new(value))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl LuaRef {
|
|
|
|
/// Creates a reference to what is at the top of the stack.
|
|
|
|
pub unsafe fn from_stack(state: &State) -> Result<Self> {
|
|
|
|
let s = state.state_ptr();
|
2024-01-26 04:47:30 +00:00
|
|
|
let t = lua::lua_gettop(s);
|
2024-01-22 03:53:53 +00:00
|
|
|
|
|
|
|
let r = lua::luaL_ref(s, lua::LUA_REGISTRYINDEX);
|
2024-01-26 04:47:30 +00:00
|
|
|
let t = lua::lua_gettop(s);
|
2024-01-22 03:53:53 +00:00
|
|
|
if r == lua::LUA_REFNIL {
|
|
|
|
Err(Error::Nil)
|
|
|
|
} else {
|
|
|
|
Ok(LuaRef::from(r))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PushToLuaStack for LuaRef {
|
|
|
|
unsafe fn push_to_lua_stack(&self, state: &State) -> Result<()> {
|
|
|
|
let s = state.state_ptr();
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
state.ensure_stack(1)?;
|
2024-01-26 04:47:30 +00:00
|
|
|
let top = lua::lua_gettop(s);
|
|
|
|
let ty = lua::lua_rawgeti(s, lua::LUA_REGISTRYINDEX, *self.0 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);
|
|
|
|
}
|
2024-01-22 03:53:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, thiserror::Error)]
|
|
|
|
pub enum Error {
|
|
|
|
/// An error returned from lua
|
2024-01-26 04:47:30 +00:00
|
|
|
#[error("Lua runtime error: {0}")]
|
2024-01-22 03:53:53 +00:00
|
|
|
Runtime(String),
|
|
|
|
/// Ran into a not enough memory error when trying to grow the lua stack.
|
2024-01-26 04:47:30 +00:00
|
|
|
#[error("Ran out of memory when attempting to use `lua_checkstack`")]
|
2024-01-22 03:53:53 +00:00
|
|
|
Oom,
|
|
|
|
#[error("Ran into a nill value on the stack")]
|
|
|
|
Nil,
|
|
|
|
#[error("Unexpected type, expected {0} but got {1}")]
|
2024-01-26 04:47:30 +00:00
|
|
|
UnexpectedType(String, String),
|
|
|
|
#[error("Bad argument provided to {func:?}! Argument #{arg_index} (name: {arg_name:?}), cause: {error}")]
|
|
|
|
BadArgument {
|
|
|
|
func: Option<String>,
|
|
|
|
arg_index: i32,
|
|
|
|
arg_name: Option<String>,
|
|
|
|
/// the error that describes what was wrong for this argument
|
|
|
|
error: Arc<Error>
|
|
|
|
},
|
|
|
|
#[error("There is already a registry entry with the key {0}")]
|
|
|
|
RegistryConflict(String)
|
2024-01-22 03:53:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Error {
|
|
|
|
pub fn runtime(msg: &str) -> Self {
|
|
|
|
Self::Runtime(msg.to_string())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn unexpected_type(expected: &str, got: &str) -> Self {
|
|
|
|
Self::UnexpectedType(expected.to_string(), got.to_string())
|
|
|
|
}
|
2024-01-26 04:47:30 +00:00
|
|
|
|
|
|
|
/// Throw the error in lua.
|
|
|
|
///
|
|
|
|
/// This method never returns
|
|
|
|
pub unsafe fn throw_lua(self, lua: *mut lua::lua_State) -> ! {
|
|
|
|
let msg = format!("{}", self);
|
|
|
|
let msg_c = msg.as_ptr() as *const i8;
|
|
|
|
lua::luaL_error(lua, msg_c);
|
|
|
|
panic!("never gets here");
|
|
|
|
}
|
2024-01-22 03:53:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// A result for use with lua functions
|
|
|
|
type Result<T> = core::result::Result<T, Error>;
|
|
|
|
|
|
|
|
pub trait PushToLuaStack {
|
|
|
|
unsafe fn push_to_lua_stack(&self, state: &State) -> Result<()>;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait FromLuaStack<'a>: Sized {
|
|
|
|
unsafe fn from_lua_stack(state: &'a State) -> Result<Self>;
|
|
|
|
}
|
|
|
|
|
2024-01-26 04:47:30 +00:00
|
|
|
/* impl<'a> FromLuaStack<'a> for () {
|
|
|
|
unsafe fn from_lua_stack(state: &'a State) -> Result<Self> {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
} */
|
|
|
|
|
2024-01-22 03:53:53 +00:00
|
|
|
/// Implements PushToLuaStack for a number
|
|
|
|
macro_rules! impl_push_to_lua_stack_number {
|
|
|
|
($ty: ident) => {
|
|
|
|
impl PushToLuaStack for $ty {
|
|
|
|
unsafe fn push_to_lua_stack(&self, state: &State) -> Result<()> {
|
|
|
|
state.ensure_stack(1)?;
|
|
|
|
lua::lua_pushnumber(state.state_ptr(), *self as f64);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> FromLuaStack<'a> for i32 {
|
|
|
|
unsafe fn from_lua_stack(state: &'a State) -> Result<Self> {
|
|
|
|
let s = state.state_ptr();
|
|
|
|
|
|
|
|
if lua::lua_isnumber(s, -1) == 1 {
|
2024-01-24 01:28:19 +00:00
|
|
|
let v = lua::lua_tonumber(s, -1) as i32;
|
2024-01-26 04:47:30 +00:00
|
|
|
lua::lua_pop(s, 1);
|
2024-01-24 01:28:19 +00:00
|
|
|
Ok(v)
|
2024-01-22 03:53:53 +00:00
|
|
|
} 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_push_to_lua_stack_number!(i8);
|
|
|
|
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<()> {
|
|
|
|
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 PushToLuaStack 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(())
|
|
|
|
}
|
|
|
|
}
|