2024-11-24 16:20:45 +03:00
|
|
|
use std::{
|
|
|
|
cell::Cell,
|
|
|
|
ffi::{c_char, c_int, CStr},
|
2024-11-24 23:12:35 +03:00
|
|
|
mem, slice,
|
2024-11-24 16:20:45 +03:00
|
|
|
};
|
|
|
|
|
2024-11-24 23:12:35 +03:00
|
|
|
use eyre::{bail, Context, OptionExt};
|
2024-11-21 18:50:10 +03:00
|
|
|
|
|
|
|
use crate::{
|
|
|
|
lua_bindings::{lua_CFunction, lua_State, LUA_GLOBALSINDEX},
|
|
|
|
LUA,
|
|
|
|
};
|
2024-11-21 17:08:03 +03:00
|
|
|
|
2024-11-24 16:20:45 +03:00
|
|
|
thread_local! {
|
|
|
|
static CURRENT_LUA_STATE: Cell<Option<LuaState>> = Cell::default();
|
|
|
|
}
|
|
|
|
|
2024-11-21 17:08:03 +03:00
|
|
|
#[derive(Clone, Copy)]
|
2024-11-25 02:33:02 +03:00
|
|
|
pub struct LuaState {
|
2024-11-21 18:50:10 +03:00
|
|
|
lua: *mut lua_State,
|
|
|
|
}
|
2024-11-21 17:08:03 +03:00
|
|
|
|
|
|
|
impl LuaState {
|
2024-11-25 02:33:02 +03:00
|
|
|
pub fn new(lua: *mut lua_State) -> Self {
|
2024-11-21 18:50:10 +03:00
|
|
|
Self { lua }
|
|
|
|
}
|
|
|
|
|
2024-11-24 16:20:45 +03:00
|
|
|
/// Returns a lua state that is considered "current". Usually set when we get called from noita.
|
2024-11-25 02:33:02 +03:00
|
|
|
pub fn current() -> eyre::Result<Self> {
|
2024-11-24 16:20:45 +03:00
|
|
|
CURRENT_LUA_STATE
|
|
|
|
.get()
|
|
|
|
.ok_or_eyre("No current lua state available")
|
|
|
|
}
|
|
|
|
|
2024-11-25 02:33:02 +03:00
|
|
|
pub fn make_current(self) {
|
2024-11-24 16:20:45 +03:00
|
|
|
CURRENT_LUA_STATE.set(Some(self));
|
|
|
|
}
|
|
|
|
|
2024-11-21 18:50:10 +03:00
|
|
|
pub(crate) fn raw(&self) -> *mut lua_State {
|
|
|
|
self.lua
|
2024-11-21 17:08:03 +03:00
|
|
|
}
|
|
|
|
|
2024-11-25 02:33:02 +03:00
|
|
|
pub fn to_integer(&self, index: i32) -> isize {
|
2024-11-21 18:50:10 +03:00
|
|
|
unsafe { LUA.lua_tointeger(self.lua, index) }
|
|
|
|
}
|
|
|
|
|
2024-11-25 02:33:02 +03:00
|
|
|
pub fn to_number(&self, index: i32) -> f64 {
|
2024-11-24 23:12:35 +03:00
|
|
|
unsafe { LUA.lua_tonumber(self.lua, index) }
|
|
|
|
}
|
|
|
|
|
2024-11-25 02:33:02 +03:00
|
|
|
pub fn to_bool(&self, index: i32) -> bool {
|
2024-11-24 23:12:35 +03:00
|
|
|
unsafe { LUA.lua_toboolean(self.lua, index) > 0 }
|
|
|
|
}
|
|
|
|
|
2024-11-25 02:33:02 +03:00
|
|
|
pub fn to_string(&self, index: i32) -> eyre::Result<String> {
|
2024-11-24 23:12:35 +03:00
|
|
|
let mut size = 0;
|
|
|
|
let buf = unsafe { LUA.lua_tolstring(self.lua, index, &mut size) };
|
|
|
|
if buf.is_null() {
|
|
|
|
bail!("Expected a string, but got a null pointer");
|
|
|
|
}
|
|
|
|
let slice = unsafe { slice::from_raw_parts(buf as *const u8, size) };
|
|
|
|
|
|
|
|
Ok(String::from_utf8(slice.to_owned())
|
|
|
|
.context("Attempting to get lua string, expecting it to be utf-8")?)
|
|
|
|
}
|
|
|
|
|
2024-11-25 02:33:02 +03:00
|
|
|
pub fn to_cfunction(&self, index: i32) -> lua_CFunction {
|
2024-11-21 18:50:10 +03:00
|
|
|
unsafe { LUA.lua_tocfunction(self.lua, index) }
|
|
|
|
}
|
|
|
|
|
2024-11-25 02:33:02 +03:00
|
|
|
pub fn push_number(&self, val: f64) {
|
2024-11-24 23:12:35 +03:00
|
|
|
unsafe { LUA.lua_pushnumber(self.lua, val) };
|
|
|
|
}
|
|
|
|
|
2024-11-25 02:33:02 +03:00
|
|
|
pub fn push_integer(&self, val: isize) {
|
2024-11-24 23:12:35 +03:00
|
|
|
unsafe { LUA.lua_pushinteger(self.lua, val) };
|
|
|
|
}
|
|
|
|
|
2024-11-25 02:33:02 +03:00
|
|
|
pub fn push_bool(&self, val: bool) {
|
2024-11-24 23:12:35 +03:00
|
|
|
unsafe { LUA.lua_pushboolean(self.lua, val as i32) };
|
|
|
|
}
|
|
|
|
|
2024-11-25 02:33:02 +03:00
|
|
|
pub fn push_string(&self, s: &str) {
|
2024-11-24 16:20:45 +03:00
|
|
|
unsafe {
|
2024-11-24 23:12:35 +03:00
|
|
|
LUA.lua_pushlstring(self.lua, s.as_bytes().as_ptr() as *const c_char, s.len());
|
2024-11-24 16:20:45 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-25 02:33:02 +03:00
|
|
|
pub fn push_nil(&self) {
|
|
|
|
unsafe { LUA.lua_pushnil(self.lua) }
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn call(&self, nargs: i32, nresults: i32) {
|
2024-11-24 23:12:35 +03:00
|
|
|
unsafe { LUA.lua_call(self.lua, nargs, nresults) };
|
|
|
|
}
|
|
|
|
|
2024-11-25 02:33:02 +03:00
|
|
|
pub fn get_global(&self, name: &CStr) {
|
2024-11-21 18:50:10 +03:00
|
|
|
unsafe { LUA.lua_getfield(self.lua, LUA_GLOBALSINDEX, name.as_ptr()) };
|
|
|
|
}
|
|
|
|
|
2024-11-25 02:33:02 +03:00
|
|
|
pub fn pop_last(&self) {
|
2024-11-21 18:50:10 +03:00
|
|
|
unsafe { LUA.lua_settop(self.lua, -2) };
|
2024-11-21 17:08:03 +03:00
|
|
|
}
|
2024-11-25 02:33:02 +03:00
|
|
|
pub fn pop_last_n(&self, n: i32) {
|
|
|
|
unsafe { LUA.lua_settop(self.lua, -1 - (n)) };
|
|
|
|
}
|
2024-11-24 16:20:45 +03:00
|
|
|
|
|
|
|
/// Raise an error with message `s`
|
|
|
|
///
|
|
|
|
/// This takes String so that it gets deallocated properly, as this functions doesn't return.
|
|
|
|
unsafe fn raise_error(&self, s: String) -> ! {
|
|
|
|
self.push_string(&s);
|
|
|
|
mem::drop(s);
|
|
|
|
unsafe { LUA.lua_error(self.lua) };
|
|
|
|
// lua_error does not return.
|
|
|
|
unreachable!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) trait LuaFnRet {
|
|
|
|
fn do_return(self, lua: LuaState) -> c_int;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Function intends to return several values that it has on stack.
|
|
|
|
pub(crate) struct ValuesOnStack(pub(crate) c_int);
|
|
|
|
|
|
|
|
impl LuaFnRet for ValuesOnStack {
|
|
|
|
fn do_return(self, _lua: LuaState) -> c_int {
|
|
|
|
self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl LuaFnRet for () {
|
|
|
|
fn do_return(self, _lua: LuaState) -> c_int {
|
|
|
|
0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<R: LuaFnRet> LuaFnRet for eyre::Result<R> {
|
|
|
|
fn do_return(self, lua: LuaState) -> c_int {
|
|
|
|
match self {
|
|
|
|
Ok(ok) => ok.do_return(lua),
|
|
|
|
Err(err) => unsafe {
|
|
|
|
lua.raise_error(format!("Error in ewext call: {:?}", err));
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
2024-11-21 17:08:03 +03:00
|
|
|
}
|