elua/src/main.rs

221 lines
5.4 KiB
Rust
Raw Normal View History

2024-01-22 03:53:53 +00:00
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(())
}
}