Add more coroutine bindings and utility functions

This commit is contained in:
William Venner 2022-01-27 18:46:58 +00:00
parent fbbeb80934
commit 318f0e3475
2 changed files with 78 additions and 22 deletions

View File

@ -171,6 +171,8 @@ pub struct LuaShared {
pub lua_yield: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, nresults: i32) -> i32>, pub lua_yield: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, nresults: i32) -> i32>,
pub lua_pushthread: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState) -> i32>, pub lua_pushthread: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState) -> i32>,
pub lua_tothread: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, index: i32) -> LuaState>, pub lua_tothread: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, index: i32) -> LuaState>,
pub lua_status: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState) -> i32>,
pub lua_xmove: Symbol<'static, unsafe extern "C-unwind" fn(thread1: LuaState, thread2: LuaState, n: i32)>,
} }
unsafe impl Sync for LuaShared {} unsafe impl Sync for LuaShared {}
impl LuaShared { impl LuaShared {
@ -243,6 +245,8 @@ impl LuaShared {
lua_yield: find_symbol!("lua_yield"), lua_yield: find_symbol!("lua_yield"),
lua_pushthread: find_symbol!("lua_pushthread"), lua_pushthread: find_symbol!("lua_pushthread"),
lua_tothread: find_symbol!("lua_tothread"), lua_tothread: find_symbol!("lua_tothread"),
lua_status: find_symbol!("lua_status"),
lua_xmove: find_symbol!("lua_xmove"),
} }
} }
} }

View File

@ -4,6 +4,26 @@ use crate::lua::*;
use crate::userdata::TaggedUserData; use crate::userdata::TaggedUserData;
unsafe fn handle_pcall_ignore(lua: State) {
crate::lua_stack_guard!(lua => {
lua.get_global(crate::lua_string!("ErrorNoHaltWithStack"));
if lua.is_nil(-1) {
eprintln!("[ERROR] {:?}", lua.get_string(-2));
lua.pop();
} else {
#[cfg(debug_assertions)] {
lua.push_string(&format!("[pcall_ignore] {}", lua.get_string(-2).expect("Expected a string here")));
}
#[cfg(not(debug_assertions))] {
lua.push_value(-2);
}
lua.call(1, 0);
}
});
lua.pop();
}
#[repr(transparent)] #[repr(transparent)]
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct LuaState(pub *mut std::ffi::c_void); pub struct LuaState(pub *mut std::ffi::c_void);
@ -193,28 +213,17 @@ impl LuaState {
/// ///
/// Returns whether the execution was successful. /// Returns whether the execution was successful.
pub unsafe fn pcall_ignore(&self, nargs: i32, nresults: i32) -> bool { pub unsafe fn pcall_ignore(&self, nargs: i32, nresults: i32) -> bool {
let res = self.pcall(nargs, nresults, 0); match self.pcall(nargs, nresults, 0) {
if res == LUA_ERRRUN { LUA_OK => true,
crate::lua_stack_guard!(self => { LUA_ERRRUN => {
self.get_global(crate::lua_string!("ErrorNoHaltWithStack")); handle_pcall_ignore(*self);
if self.is_nil(-1) {
eprintln!("[ERROR] {:?}", self.get_string(-2));
self.pop();
} else {
#[cfg(debug_assertions)] {
self.push_string(&format!("[pcall_ignore] {}", self.get_string(-2).expect("Expected a string here")));
}
#[cfg(not(debug_assertions))] {
self.push_value(-2);
}
self.call(1, 0);
}
});
self.pop();
false false
} else { }
true err @ _ => {
#[cfg(debug_assertions)]
eprintln!("[gmod-rs] pcall_ignore unknown error: {}", err);
false
}
} }
} }
@ -483,15 +492,58 @@ impl LuaState {
} }
#[inline(always)] #[inline(always)]
#[must_use]
pub unsafe fn coroutine_yield(&self, nresults: i32) -> i32 { pub unsafe fn coroutine_yield(&self, nresults: i32) -> i32 {
(LUA_SHARED.lua_yield)(*self, nresults) (LUA_SHARED.lua_yield)(*self, nresults)
} }
#[inline(always)] #[inline(always)]
#[must_use]
pub unsafe fn coroutine_resume(&self, narg: i32) -> i32 { pub unsafe fn coroutine_resume(&self, narg: i32) -> i32 {
(LUA_SHARED.lua_resume)(*self, narg) (LUA_SHARED.lua_resume)(*self, narg)
} }
#[inline(always)]
/// Exchange values between different threads of the same global state.
///
/// This function pops `n` values from the stack `self`, and pushes them onto the stack `target_thread`.
pub unsafe fn coroutine_exchange(&self, target_thread: State, n: i32) {
(LUA_SHARED.lua_xmove)(*self, target_thread, n)
}
#[inline(always)]
/// See `call`
pub unsafe fn coroutine_resume_call(&self, narg: i32) {
match (LUA_SHARED.lua_resume)(*self, narg) {
LUA_OK => {},
LUA_ERRRUN => self.error(self.get_string(-2).unwrap_or_else(|| Cow::Borrowed("Unknown error")).as_ref()),
LUA_ERRMEM => self.error("Out of memory"),
_ => self.error("Unknown internal Lua error")
}
}
#[inline(always)]
/// See `pcall_ignore`
pub unsafe fn coroutine_resume_pcall_ignore(&self, narg: i32) -> Result<i32, ()> {
match (LUA_SHARED.lua_resume)(*self, narg) {
status @ (LUA_OK | LUA_YIELD) => Ok(status),
LUA_ERRRUN => {
handle_pcall_ignore(*self);
Err(())
},
err @ _ => {
#[cfg(debug_assertions)]
eprintln!("[gmod-rs] coroutine_resume_pcall_ignore unknown error: {}", err);
Err(())
}
}
}
#[inline(always)]
pub unsafe fn coroutine_status(&self) -> i32 {
(LUA_SHARED.lua_status)(*self)
}
/// Creates a new table in the registry with the given `name` as the key if it doesn't already exist, and pushes it onto the stack. /// Creates a new table in the registry with the given `name` as the key if it doesn't already exist, and pushes it onto the stack.
/// ///
/// Returns if the metatable was already present in the registry. /// Returns if the metatable was already present in the registry.