Add more bindings, add push to Lua trait
This commit is contained in:
parent
0a3141d6b8
commit
47492748f2
|
@ -135,7 +135,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "gmod"
|
||||
version = "11.0.2"
|
||||
version = "11.1.1"
|
||||
dependencies = [
|
||||
"cfg_table 1.0.0",
|
||||
"cstr",
|
||||
|
|
|
@ -8,4 +8,4 @@ publish = false
|
|||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
gmod = {version = "10.2.1", features = ["gmcl"], default-features = false}
|
||||
gmod = {version = "*", features = ["gmcl"], default-features = false}
|
|
@ -2,7 +2,7 @@
|
|||
name = "gmod-macros"
|
||||
version = "1.0.4"
|
||||
authors = ["William Venner <william@venner.io>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
description = "Proc macros for gmod-rs"
|
||||
repository = "https://github.com/WilliamVenner/gmod-rs"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
name = "gmod"
|
||||
version = "11.1.1"
|
||||
authors = ["William Venner <william@venner.io>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
description = "A swiss army knife for creating binary modules for Garry's Mod in Rust"
|
||||
repository = "https://github.com/WilliamVenner/gmod-rs"
|
||||
|
|
|
@ -164,6 +164,11 @@ pub struct LuaShared {
|
|||
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>,
|
||||
pub lua_resume: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, narg: i32) -> i32>,
|
||||
pub lua_newthread: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState) -> LuaState>,
|
||||
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_tothread: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, index: i32) -> LuaState>,
|
||||
}
|
||||
unsafe impl Sync for LuaShared {}
|
||||
impl LuaShared {
|
||||
|
@ -231,6 +236,11 @@ impl LuaShared {
|
|||
lua_topointer: find_symbol!("lua_topointer"),
|
||||
lua_newuserdata: find_symbol!("lua_newuserdata"),
|
||||
lual_newmetatable: find_symbol!("luaL_newmetatable"),
|
||||
lua_resume: find_symbol!("lua_resume_real"),
|
||||
lua_newthread: find_symbol!("lua_newthread"),
|
||||
lua_yield: find_symbol!("lua_yield"),
|
||||
lua_pushthread: find_symbol!("lua_pushthread"),
|
||||
lua_tothread: find_symbol!("lua_tothread"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -166,6 +166,16 @@ impl LuaState {
|
|||
(LUA_SHARED.lua_pushnil)(*self)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn push_thread(&self) -> i32 {
|
||||
(LUA_SHARED.lua_pushthread)(*self)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn to_thread(&self, index: i32) -> State {
|
||||
(LUA_SHARED.lua_tothread)(*self, index)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn pcall(&self, nargs: i32, nresults: i32, errfunc: i32) -> i32 {
|
||||
(LUA_SHARED.lua_pcall)(*self, nargs, nresults, errfunc)
|
||||
|
@ -177,19 +187,28 @@ impl LuaState {
|
|||
pub unsafe fn pcall_ignore(&self, nargs: i32, nresults: i32) -> bool {
|
||||
let res = self.pcall(nargs, nresults, 0);
|
||||
if res == LUA_ERRRUN {
|
||||
crate::lua_stack_guard!(self => {
|
||||
self.get_global(crate::lua_string!("ErrorNoHaltWithStack"));
|
||||
if self.is_nil(-1) {
|
||||
eprintln!("[ERROR] {:?}", self.get_string(-2));
|
||||
self.pop_n(2);
|
||||
return false;
|
||||
}
|
||||
self.push_value(-2);
|
||||
self.call(1, 0);
|
||||
self.pop();
|
||||
return false;
|
||||
} 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
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn load_string(&self, src: LuaString) -> Result<(), LuaError> {
|
||||
let lua_error_code = (LUA_SHARED.lual_loadstring)(*self, src);
|
||||
|
@ -450,9 +469,25 @@ impl LuaState {
|
|||
(LUA_SHARED.lua_touserdata)(*self, index)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn coroutine_new(&self) -> State {
|
||||
(LUA_SHARED.lua_newthread)(*self)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn coroutine_yield(&self, nresults: i32) -> i32 {
|
||||
(LUA_SHARED.lua_yield)(*self, nresults)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn coroutine_resume(&self, narg: i32) -> i32 {
|
||||
(LUA_SHARED.lua_resume)(*self, narg)
|
||||
}
|
||||
|
||||
/// 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.
|
||||
#[inline(always)]
|
||||
pub unsafe fn new_metatable(&self, name: LuaString) -> bool {
|
||||
(LUA_SHARED.lual_newmetatable)(*self, name) == 0
|
||||
}
|
||||
|
@ -480,6 +515,7 @@ impl LuaState {
|
|||
self.push_value(-2);
|
||||
self.set_metatable(-2);
|
||||
self.remove(self.get_top() - 1);
|
||||
self.remove(self.get_top() - 1);
|
||||
}
|
||||
|
||||
ptr.write(data);
|
||||
|
|
|
@ -6,6 +6,9 @@ pub use import::*;
|
|||
mod lua_state;
|
||||
pub use lua_state::LuaState as State;
|
||||
|
||||
mod push;
|
||||
pub use push::*;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum LuaError {
|
||||
/// Out of memory
|
||||
|
@ -73,7 +76,21 @@ macro_rules! lua_stack_guard {
|
|||
let ret = (|| $code)();
|
||||
if top != $lua.get_top() {
|
||||
$lua.dump_stack();
|
||||
panic!("Stack is dirty!");
|
||||
panic!("Stack is dirty! Expected the stack to have {} elements, but it has {}!", top, $lua.get_top());
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
$code
|
||||
}};
|
||||
|
||||
( $lua:ident => $elem:literal => $code:block ) => {{
|
||||
#[cfg(debug_assertions)] {
|
||||
let ret = (|| $code)();
|
||||
if $lua.get_top() != $elem {
|
||||
$lua.dump_stack();
|
||||
panic!("Stack is dirty! Expected the stack to have ", $elem, " (fixed size) elements, but it has {}!", $lua.get_top());
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
use std::time::{Duration, SystemTime};
|
||||
|
||||
pub trait PushToLua: Sized {
|
||||
/// Pushes this value to the Lua stack.
|
||||
unsafe fn push_to_lua(self, lua: crate::lua::State);
|
||||
}
|
||||
pub trait TryPushToLua: Sized {
|
||||
/// Checked `push_to_lua` for types that may not fit in an `i32`
|
||||
unsafe fn try_push_to_lua(self, lua: crate::lua::State) -> Result<(), Self>;
|
||||
}
|
||||
pub trait ForcePushToLua: Sized {
|
||||
/// `push_to_lua` but may result in loss of data
|
||||
unsafe fn force_push_to_lua(self, lua: crate::lua::State);
|
||||
}
|
||||
pub trait PushCollectionToLua: Sized {
|
||||
/// Pushes this collection to a table at the top of the Lua stack.
|
||||
///
|
||||
/// **You must create the table yourself**
|
||||
unsafe fn push_to_lua_table(self, lua: crate::lua::State);
|
||||
}
|
||||
|
||||
impl<P: PushToLua> TryPushToLua for P {
|
||||
#[inline]
|
||||
unsafe fn try_push_to_lua(self, lua: crate::lua::State) -> Result<(), Self> {
|
||||
self.push_to_lua(lua);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl<P: PushToLua>ForcePushToLua for P {
|
||||
#[inline]
|
||||
unsafe fn force_push_to_lua(self, lua: crate::lua::State) {
|
||||
self.push_to_lua(lua);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! push_primitives {
|
||||
{$($ty:ty => $fn:ident),*} => {$(
|
||||
impl PushToLua for $ty {
|
||||
#[inline]
|
||||
unsafe fn push_to_lua(self, lua: crate::lua::State) {
|
||||
lua.$fn(self as _);
|
||||
}
|
||||
}
|
||||
)*};
|
||||
}
|
||||
macro_rules! try_push_primitives {
|
||||
{$($ty:ty => $fn:ident / $forcefn:ident),*} => {$(
|
||||
impl TryPushToLua for $ty {
|
||||
#[inline]
|
||||
unsafe fn try_push_to_lua(self, lua: crate::lua::State) -> Result<(), Self> {
|
||||
lua.$fn(match self.try_into() {
|
||||
Ok(v) => v,
|
||||
Err(e) => return Err(self)
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl ForcePushToLua for $ty {
|
||||
#[inline]
|
||||
unsafe fn force_push_to_lua(self, lua: crate::lua::State) {
|
||||
lua.$forcefn(self as _);
|
||||
}
|
||||
}
|
||||
)*};
|
||||
}
|
||||
|
||||
push_primitives! {
|
||||
&str => push_string,
|
||||
bool => push_boolean,
|
||||
f64 => push_number,
|
||||
f32 => push_number,
|
||||
u8 => push_integer,
|
||||
i8 => push_integer,
|
||||
u16 => push_integer,
|
||||
i16 => push_integer,
|
||||
i32 => push_integer
|
||||
}
|
||||
try_push_primitives! {
|
||||
u32 => push_integer / push_number,
|
||||
i64 => push_integer / push_number,
|
||||
u64 => push_integer / push_number,
|
||||
u128 => push_integer / push_number,
|
||||
i128 => push_integer / push_number
|
||||
}
|
||||
|
||||
impl PushToLua for String {
|
||||
#[inline]
|
||||
unsafe fn push_to_lua(self, lua: crate::lua::State) {
|
||||
lua.push_string(&self);
|
||||
}
|
||||
}
|
||||
impl PushToLua for Vec<u8> {
|
||||
#[inline]
|
||||
unsafe fn push_to_lua(self, lua: crate::lua::State) {
|
||||
lua.push_binary_string(&self);
|
||||
}
|
||||
}
|
||||
impl PushToLua for &[u8] {
|
||||
#[inline]
|
||||
unsafe fn push_to_lua(self, lua: crate::lua::State) {
|
||||
lua.push_binary_string(&self);
|
||||
}
|
||||
}
|
||||
impl PushToLua for Duration {
|
||||
#[inline]
|
||||
unsafe fn push_to_lua(self, lua: crate::lua::State) {
|
||||
lua.push_number(self.as_secs_f64());
|
||||
}
|
||||
}
|
||||
impl<T: PushToLua> PushToLua for Option<T> {
|
||||
#[inline]
|
||||
unsafe fn push_to_lua(self, lua: crate::lua::State) {
|
||||
match self {
|
||||
Some(val) => val.push_to_lua(lua),
|
||||
None => lua.push_nil()
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<K: PushToLua, V: PushToLua> PushCollectionToLua for std::collections::BTreeMap<K, V> {
|
||||
#[inline]
|
||||
unsafe fn push_to_lua_table(self, lua: crate::lua::State) {
|
||||
for (k, v) in self {
|
||||
k.push_to_lua(lua);
|
||||
v.push_to_lua(lua);
|
||||
lua.set_table(-3);
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T: PushToLua> PushCollectionToLua for Vec<T> {
|
||||
#[inline]
|
||||
unsafe fn push_to_lua_table(self, lua: crate::lua::State) {
|
||||
iterator(lua, &mut self.into_iter())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryPushToLua for SystemTime {
|
||||
#[inline]
|
||||
unsafe fn try_push_to_lua(self, lua: crate::lua::State) -> Result<(), Self> {
|
||||
lua.push_number(self.duration_since(SystemTime::UNIX_EPOCH).map_err(|_| self)?.as_secs_f64());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Pushes all elements in an iterator to a Lua table at the top of the stack.
|
||||
///
|
||||
/// **You must create the table yourself**
|
||||
#[inline]
|
||||
pub unsafe fn iterator<T: PushToLua, I: Iterator<Item = T>>(lua: crate::lua::State, iter: &mut I) {
|
||||
for (i, val) in iter.enumerate() {
|
||||
lua.push_integer((i + 1) as _);
|
||||
val.push_to_lua(lua);
|
||||
lua.set_table(-3);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue