276 lines
13 KiB
Rust
276 lines
13 KiB
Rust
#[cfg(debug_assertions)]
|
|
use std::sync::atomic::AtomicI64;
|
|
|
|
use std::{cell::UnsafeCell, ffi::c_void};
|
|
|
|
use libloading::{Library, Symbol};
|
|
|
|
use super::{LuaError, State as LuaState, LuaDebug};
|
|
|
|
pub type LuaInt = isize;
|
|
pub type LuaSize = usize;
|
|
pub type LuaString = *const std::os::raw::c_char;
|
|
pub type LuaFunction = unsafe extern "C-unwind" fn(state: LuaState) -> i32;
|
|
pub type LuaNumber = f64;
|
|
pub type LuaReference = i32;
|
|
|
|
pub const LUA_REGISTRYINDEX: i32 = -10000;
|
|
pub const LUA_ENVIRONINDEX: i32 = -10001;
|
|
pub const LUA_GLOBALSINDEX: i32 = -10002;
|
|
|
|
pub const LUA_MULTRET: i32 = -1;
|
|
pub const LUA_NOREF: LuaReference = -2;
|
|
pub const LUA_REFNIL: LuaReference = -1;
|
|
|
|
pub const LUA_TNONE: i32 = -1;
|
|
pub const LUA_TNIL: i32 = 0;
|
|
pub const LUA_TBOOLEAN: i32 = 1;
|
|
pub const LUA_TLIGHTUSERDATA: i32 = 2;
|
|
pub const LUA_TNUMBER: i32 = 3;
|
|
pub const LUA_TSTRING: i32 = 4;
|
|
pub const LUA_TTABLE: i32 = 5;
|
|
pub const LUA_TFUNCTION: i32 = 6;
|
|
pub const LUA_TUSERDATA: i32 = 7;
|
|
pub const LUA_TTHREAD: i32 = 8;
|
|
|
|
pub const LUA_OK: i32 = 0;
|
|
pub const LUA_YIELD: i32 = 1;
|
|
pub const LUA_ERRRUN: i32 = 2;
|
|
pub const LUA_ERRSYNTAX: i32 = 3;
|
|
pub const LUA_ERRMEM: i32 = 4;
|
|
pub const LUA_ERRERR: i32 = 5;
|
|
pub const LUA_ERRFILE: i32 = LUA_ERRERR + 1;
|
|
|
|
pub const LUA_IDSIZE: usize = 60;
|
|
|
|
impl LuaError {
|
|
fn get_error_message(lua_state: LuaState) -> Option<String> {
|
|
unsafe { lua_state.get_string(-1).map(|str| str.into_owned()) }
|
|
}
|
|
|
|
pub(crate) fn from_lua_state(lua_state: LuaState, lua_int_error_code: i32) -> Self {
|
|
use super::LuaError::*;
|
|
match lua_int_error_code {
|
|
LUA_ERRMEM => MemoryAllocationError,
|
|
LUA_ERRERR => ErrorHandlerError,
|
|
LUA_ERRSYNTAX | LUA_ERRRUN | LUA_ERRFILE => {
|
|
let msg = LuaError::get_error_message(lua_state);
|
|
match lua_int_error_code {
|
|
LUA_ERRSYNTAX => SyntaxError(msg),
|
|
LUA_ERRRUN => RuntimeError(msg),
|
|
LUA_ERRFILE => FileError(msg),
|
|
_ => unreachable!(),
|
|
}
|
|
}
|
|
_ => Unknown(lua_int_error_code),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(not(debug_assertions), repr(transparent))]
|
|
pub struct LuaSharedInterface(pub(crate) UnsafeCell<*mut LuaShared>, #[cfg(debug_assertions)] AtomicI64);
|
|
impl LuaSharedInterface {
|
|
#[cfg(debug_assertions)]
|
|
pub(crate) fn debug_assertions(&self) {
|
|
assert!(!unsafe { *self.0.get() }.is_null(), "The Lua state has not been initialized yet. Add `#[gmod::gmod13_open]` to your module's gmod13_open function to fix this. You can also manually load the Lua state with `gmod::load_lua_state()` or `gmod::set_lua_state(*mut c_void)`");
|
|
|
|
let thread_id = u64::from(std::thread::current().id().as_u64()) as i64;
|
|
match self.1.compare_exchange(-1, thread_id, std::sync::atomic::Ordering::SeqCst, std::sync::atomic::Ordering::SeqCst) {
|
|
Ok(-1) => {}, // This is the first thread to use this Lua state.
|
|
Ok(_) => unreachable!(),
|
|
Err(remembered_thread_id) => assert_eq!(thread_id, remembered_thread_id, "Tried to access the Lua state from another thread! The Lua state is NOT thread-safe, and should only be accessed from the main thread.")
|
|
}
|
|
}
|
|
|
|
pub(super) unsafe fn load(&self) {
|
|
*self.0.get() = Box::leak(Box::new(LuaShared::import()));
|
|
}
|
|
|
|
pub(super) unsafe fn set(&self, ptr: *mut c_void) {
|
|
*self.0.get() = ptr as *mut LuaShared;
|
|
}
|
|
}
|
|
impl std::ops::Deref for LuaSharedInterface {
|
|
type Target = LuaShared;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
#[cfg(debug_assertions)]
|
|
self.debug_assertions();
|
|
|
|
unsafe { &**self.0.get() }
|
|
}
|
|
}
|
|
impl std::ops::DerefMut for LuaSharedInterface {
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
#[cfg(debug_assertions)]
|
|
self.debug_assertions();
|
|
|
|
unsafe { &mut **self.0.get_mut() }
|
|
}
|
|
}
|
|
|
|
pub static mut LUA_SHARED: LuaSharedInterface = LuaSharedInterface(UnsafeCell::new(std::ptr::null_mut()), #[cfg(debug_assertions)] AtomicI64::new(-1));
|
|
|
|
pub struct LuaShared {
|
|
pub lual_newstate: Symbol<'static, unsafe extern "C-unwind" fn() -> LuaState>,
|
|
pub lual_openlibs: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState)>,
|
|
pub lual_loadfile: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, path: LuaString) -> i32>,
|
|
pub lual_loadstring: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, path: LuaString) -> i32>,
|
|
pub lual_loadbuffer: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, buff: LuaString, sz: LuaSize, name: LuaString) -> i32>,
|
|
pub lua_getfield: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, index: i32, k: LuaString)>,
|
|
pub lua_pushvalue: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, index: i32)>,
|
|
pub lua_pushlightuserdata: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, data: *mut c_void)>,
|
|
pub lua_pushboolean: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, bool: i32)>,
|
|
pub lua_tolstring: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, index: i32, out_size: *mut LuaSize) -> LuaString>,
|
|
pub lua_pcall: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, nargs: i32, nresults: i32, errfunc: i32) -> i32>,
|
|
pub lua_remove: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, index: i32)>,
|
|
pub lua_gettop: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState) -> i32>,
|
|
pub lua_type: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, index: i32) -> i32>,
|
|
pub lua_typename: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, lua_type_id: i32) -> LuaString>,
|
|
pub lua_setfield: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, index: i32, k: LuaString)>,
|
|
pub lua_call: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, nargs: i32, nresults: i32)>,
|
|
pub lua_createtable: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, narr: i32, nrec: i32)>,
|
|
pub lua_settop: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, count: i32)>,
|
|
pub lua_replace: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, index: i32)>,
|
|
pub lua_pushlstring: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, data: LuaString, length: LuaSize)>,
|
|
pub lua_pushcclosure: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, func: LuaFunction, upvalues: i32)>,
|
|
pub lua_settable: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, index: i32)>,
|
|
pub lua_gettable: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, index: i32)>,
|
|
pub lua_error: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState) -> i32>,
|
|
pub lua_insert: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, index: i32)>,
|
|
pub lual_checkinteger: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, arg: i32) -> LuaInt>,
|
|
pub lual_checklstring: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, arg: i32, out_size: *mut LuaSize) -> LuaString>,
|
|
pub lua_toboolean: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, index: i32) -> i32>,
|
|
pub lual_checktype: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, index: i32, r#type: i32)>,
|
|
pub lua_setmetatable: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, index: i32) -> i32>,
|
|
pub lua_pushinteger: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, int: LuaInt)>,
|
|
pub lua_pushnumber: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, int: LuaNumber)>,
|
|
pub lua_pushnil: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState)>,
|
|
pub lual_checknumber: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, arg: i32) -> LuaNumber>,
|
|
pub lua_tointeger: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, index: i32) -> LuaInt>,
|
|
pub lua_tonumber: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, index: i32) -> LuaNumber>,
|
|
pub lual_checkudata: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, arg: i32, name: LuaString) -> *mut std::ffi::c_void>,
|
|
pub lual_ref: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, index: i32) -> i32>,
|
|
pub lual_unref: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, index: i32, r#ref: i32)>,
|
|
pub lua_objlen: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, index: i32) -> i32>,
|
|
pub lua_rawgeti: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, t: i32, index: i32)>,
|
|
pub lua_rawseti: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, t: i32, index: i32)>,
|
|
pub lua_getmetatable: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, index: i32) -> i32>,
|
|
pub lua_rawequal: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, a: i32, b: i32) -> i32>,
|
|
pub lua_touserdata: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, index: i32) -> *mut std::ffi::c_void>,
|
|
pub lua_getinfo: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, what: LuaString, ar: *mut LuaDebug) -> i32>,
|
|
pub lua_getstack: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, level: i32, ar: *mut LuaDebug) -> i32>,
|
|
pub lua_next: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, index: i32) -> i32>,
|
|
pub lua_topointer: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, index: i32) -> *const c_void>,
|
|
pub lua_newuserdata: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, size: usize) -> *mut c_void>,
|
|
pub lual_newmetatable: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, name: LuaString) -> i32>,
|
|
}
|
|
unsafe impl Sync for LuaShared {}
|
|
impl LuaShared {
|
|
fn import() -> Self {
|
|
unsafe {
|
|
let (library, path) = Self::find_lua_shared();
|
|
let library = Box::leak(Box::new(library)); // Keep this library referenced forever
|
|
|
|
macro_rules! find_symbol {
|
|
( $symbol:literal ) => {
|
|
Self::find_symbol(library, concat!($symbol, "\0").as_bytes())
|
|
};
|
|
}
|
|
|
|
Self {
|
|
lual_newstate: find_symbol!("luaL_newstate"),
|
|
lual_openlibs: find_symbol!("luaL_openlibs"),
|
|
lua_pushlightuserdata: find_symbol!("lua_pushlightuserdata"),
|
|
lual_checktype: find_symbol!("luaL_checktype"),
|
|
lual_loadfile: find_symbol!("luaL_loadfile"),
|
|
lual_loadstring: find_symbol!("luaL_loadstring"),
|
|
lual_loadbuffer: find_symbol!("luaL_loadbuffer"),
|
|
lua_getfield: find_symbol!("lua_getfield"),
|
|
lua_pushvalue: find_symbol!("lua_pushvalue"),
|
|
lua_pushboolean: find_symbol!("lua_pushboolean"),
|
|
lua_tolstring: find_symbol!("lua_tolstring"),
|
|
lua_pcall: find_symbol!("lua_pcall"),
|
|
lua_remove: find_symbol!("lua_remove"),
|
|
lua_gettop: find_symbol!("lua_gettop"),
|
|
lua_type: find_symbol!("lua_type"),
|
|
lua_typename: find_symbol!("lua_typename"),
|
|
lua_setfield: find_symbol!("lua_setfield"),
|
|
lua_call: find_symbol!("lua_call"),
|
|
lua_createtable: find_symbol!("lua_createtable"),
|
|
lua_settop: find_symbol!("lua_settop"),
|
|
lua_replace: find_symbol!("lua_replace"),
|
|
lua_pushlstring: find_symbol!("lua_pushlstring"),
|
|
lua_pushcclosure: find_symbol!("lua_pushcclosure"),
|
|
lua_settable: find_symbol!("lua_settable"),
|
|
lua_gettable: find_symbol!("lua_gettable"),
|
|
lua_error: find_symbol!("lua_error"),
|
|
lua_insert: find_symbol!("lua_insert"),
|
|
lual_checkinteger: find_symbol!("luaL_checkinteger"),
|
|
lual_checklstring: find_symbol!("luaL_checklstring"),
|
|
lua_toboolean: find_symbol!("lua_toboolean"),
|
|
lua_pushnumber: find_symbol!("lua_pushnumber"),
|
|
lua_pushinteger: find_symbol!("lua_pushinteger"),
|
|
lua_pushnil: find_symbol!("lua_pushnil"),
|
|
lual_checknumber: find_symbol!("luaL_checknumber"),
|
|
lua_tointeger: find_symbol!("lua_tointeger"),
|
|
lua_tonumber: find_symbol!("lua_tonumber"),
|
|
lual_checkudata: find_symbol!("luaL_checkudata"),
|
|
lual_ref: find_symbol!("luaL_ref"),
|
|
lual_unref: find_symbol!("luaL_unref"),
|
|
lua_setmetatable: find_symbol!("lua_setmetatable"),
|
|
lua_objlen: find_symbol!("lua_objlen"),
|
|
lua_rawgeti: find_symbol!("lua_rawgeti"),
|
|
lua_rawseti: find_symbol!("lua_rawseti"),
|
|
lua_getmetatable: find_symbol!("lua_getmetatable"),
|
|
lua_rawequal: find_symbol!("lua_rawequal"),
|
|
lua_touserdata: find_symbol!("lua_touserdata"),
|
|
lua_getinfo: find_symbol!("lua_getinfo"),
|
|
lua_getstack: find_symbol!("lua_getstack"),
|
|
lua_next: find_symbol!("lua_next"),
|
|
lua_topointer: find_symbol!("lua_topointer"),
|
|
lua_newuserdata: find_symbol!("lua_newuserdata"),
|
|
lual_newmetatable: find_symbol!("luaL_newmetatable"),
|
|
}
|
|
}
|
|
}
|
|
|
|
unsafe fn find_symbol<T>(library: &'static Library, name: &[u8]) -> Symbol<'static, T> {
|
|
match library.get(name) {
|
|
Ok(symbol) => symbol,
|
|
Err(err) => panic!("Failed to find symbol \"{}\"\n{:#?}", String::from_utf8_lossy(name), err),
|
|
}
|
|
}
|
|
|
|
#[cfg(all(target_os = "windows", target_pointer_width = "64"))]
|
|
pub unsafe fn find_lua_shared() -> (Library, &'static str) {
|
|
crate::open_library_raw!("bin/win64/lua_shared.dll")
|
|
.expect("Failed to load lua_shared.dll")
|
|
}
|
|
|
|
#[cfg(all(target_os = "windows", target_pointer_width = "32"))]
|
|
pub unsafe fn find_lua_shared() -> (Library, &'static str) {
|
|
crate::__private__gmod_rs__try_chained_open! {
|
|
crate::open_library_raw!("garrysmod/bin/lua_shared.dll"),
|
|
crate::open_library_raw!("bin/lua_shared.dll")
|
|
}
|
|
.expect("Failed to load lua_shared.dll")
|
|
}
|
|
|
|
#[cfg(all(target_os = "linux", target_pointer_width = "32"))]
|
|
pub unsafe fn find_lua_shared() -> (Library, &'static str) {
|
|
crate::__private__gmod_rs__try_chained_open! {
|
|
crate::open_library_raw!("garrysmod/bin/lua_shared_srv.so"),
|
|
crate::open_library_raw!("bin/linux32/lua_shared.so"),
|
|
crate::open_library_raw!("garrysmod/bin/lua_shared.so")
|
|
}
|
|
.expect("Failed to find lua_shared.so or lua_shared_srv.so")
|
|
}
|
|
|
|
#[cfg(all(target_os = "linux", target_pointer_width = "64"))]
|
|
pub unsafe fn find_lua_shared() -> (Library, &'static str) {
|
|
crate::open_library_raw!("bin/linux64/lua_shared.so")
|
|
.expect("Failed to find lua_shared.so")
|
|
}
|
|
}
|