221 lines
5.4 KiB
Rust
221 lines
5.4 KiB
Rust
|
use std::{sync::Arc, ffi::CStr};
|
||
|
|
||
|
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::*;
|
||
|
|
||
|
fn main() -> Result<()> {
|
||
|
let lua = State::new();
|
||
|
lua.expose_libraries(&[StdLibrary::Debug]);
|
||
|
|
||
|
let tbl = lua.create_table()?;
|
||
|
tbl.set("x", 10)?;
|
||
|
|
||
|
let globals = lua.globals()?;
|
||
|
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]]--
|
||
|
|
||
|
print("x is " .. X.x)
|
||
|
|
||
|
cool_num = 50
|
||
|
|
||
|
function say_number(num)
|
||
|
print("I'm lua and I said " .. num)
|
||
|
end
|
||
|
|
||
|
function multiply_print(a, b)
|
||
|
print(a .. " * " .. b .. " = " .. a * b)
|
||
|
end
|
||
|
|
||
|
function multiply_ret(a, b)
|
||
|
return a * b
|
||
|
end
|
||
|
"#).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!");
|
||
|
|
||
|
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();
|
||
|
|
||
|
let r = lua::luaL_ref(s, lua::LUA_REGISTRYINDEX);
|
||
|
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)?;
|
||
|
lua::lua_rawgeti(s, lua::LUA_REGISTRYINDEX, *self.0 as i64);
|
||
|
}
|
||
|
|
||
|
Ok(())
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#[derive(Debug, thiserror::Error)]
|
||
|
pub enum Error {
|
||
|
#[error("Lua runtime error: {0}")]
|
||
|
/// An error returned from lua
|
||
|
Runtime(String),
|
||
|
#[error("Ran out of memory when attempting to use `lua_checkstack`")]
|
||
|
/// Ran into a not enough memory error when trying to grow the lua stack.
|
||
|
Oom,
|
||
|
#[error("Ran into a nill value on the stack")]
|
||
|
Nil,
|
||
|
#[error("Unexpected type, expected {0} but got {1}")]
|
||
|
UnexpectedType(String, String)
|
||
|
}
|
||
|
|
||
|
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())
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// 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>;
|
||
|
}
|
||
|
|
||
|
/// 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 {
|
||
|
Ok(lua::lua_tonumber(s, -1) as i32)
|
||
|
} 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(())
|
||
|
}
|
||
|
}
|