use std::ffi::{CStr, OsStr};
use std::path::PathBuf;
use bstr::ByteSlice;
use crate::lua::{self, FromLua, Function, Table, ToLua, Value, ffi};
#[repr(transparent)]
#[derive(Debug, PartialEq, Eq)]
pub struct State(pub(crate) *mut lua::ffi::lua_State);
impl State {
pub(crate) fn clone(&self) -> Self {
Self(self.0)
}
#[inline]
pub fn type_of(&self, index: i32) -> i32 {
ffi::lua_type(self.0, index)
}
pub fn type_name(&self, idx: i32) -> String {
let tp = self.type_of(idx);
let tp_str = {
let c_str = ffi::lua_typename(self.0, tp);
if c_str.is_null() {
eprintln!(
"[gmodx] Warning: lua_typename returned null for type {}",
tp
);
return "<null>".into();
}
unsafe { std::ffi::CStr::from_ptr(c_str) }
};
tp_str.to_string_lossy().into_owned()
}
pub fn globals(&self) -> Table {
ffi::lua_pushvalue(self.0, ffi::LUA_GLOBALSINDEX);
Table(Value::pop_from_stack(self))
}
#[inline]
pub fn set_global(&self, key: impl ToLua, value: impl ToLua) -> lua::Result<()> {
self.globals().set(self, key, value)
}
#[inline]
pub fn get_global<V: FromLua>(&self, key: impl ToLua) -> lua::Result<V> {
self.globals().get(self, key)
}
pub fn caller_source_path(&self) -> Option<PathBuf> {
let dbg_info = self.debug_getinfo_at(1, c"S")?;
let source = dbg_info.source?;
let bytes = source.as_bytes();
#[cfg(unix)]
{
use std::os::unix::ffi::OsStrExt;
Some(PathBuf::from(OsStr::from_bytes(bytes)))
}
#[cfg(not(unix))]
{
Some(PathBuf::from(bytes.to_str_lossy().as_ref()))
}
}
pub fn load_buffer(&self, buff: &[u8], name: &CStr) -> lua::Result<Function> {
let chunk = ffi::luaL_loadbuffer(
self.0,
buff.as_ptr() as *const i8,
buff.len(),
name.as_ptr(),
);
match chunk {
ffi::LUA_OK => Ok(Function(Value::pop_from_stack(self))),
res => Err(self.pop_error(res)),
}
}
#[cold]
pub fn dump_stack(&self) {
let _sg = self.stack_guard(); let top = ffi::lua_gettop(self.0);
println!("\n=== STACK DUMP ===");
println!("Stack size: {}", top);
for i in 1..=top {
let lua_type_name = self.type_name(i);
match lua_type_name.as_ref() {
"string" => println!("{}. {}: {:?}", i, lua_type_name, {
ffi::lua_pushvalue(self.0, i);
let str = lua::String::try_from_stack(self, -1).unwrap_or_default();
ffi::lua_pop(self.0, 1);
str
}),
"boolean" => println!("{}. {}: {:?}", i, lua_type_name, {
ffi::lua_pushvalue(self.0, i);
let bool = bool::try_from_stack(self, -1).unwrap_or_default();
ffi::lua_pop(self.0, 1);
bool
}),
"number" => println!("{}. {}: {:?}", i, lua_type_name, {
ffi::lua_pushvalue(self.0, i);
let n = f64::try_from_stack(self, -1).unwrap_or_default();
ffi::lua_pop(self.0, 1);
n
}),
_ => println!("{}. {}", i, lua_type_name),
}
}
println!();
}
}