Add more bindings, add push to Lua trait
This commit is contained in:
parent
0a3141d6b8
commit
47492748f2
|
@ -135,7 +135,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gmod"
|
name = "gmod"
|
||||||
version = "11.0.2"
|
version = "11.1.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg_table 1.0.0",
|
"cfg_table 1.0.0",
|
||||||
"cstr",
|
"cstr",
|
||||||
|
|
|
@ -8,4 +8,4 @@ publish = false
|
||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
[dependencies]
|
[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"
|
name = "gmod-macros"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
authors = ["William Venner <william@venner.io>"]
|
authors = ["William Venner <william@venner.io>"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
description = "Proc macros for gmod-rs"
|
description = "Proc macros for gmod-rs"
|
||||||
repository = "https://github.com/WilliamVenner/gmod-rs"
|
repository = "https://github.com/WilliamVenner/gmod-rs"
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
name = "gmod"
|
name = "gmod"
|
||||||
version = "11.1.1"
|
version = "11.1.1"
|
||||||
authors = ["William Venner <william@venner.io>"]
|
authors = ["William Venner <william@venner.io>"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
description = "A swiss army knife for creating binary modules for Garry's Mod in Rust"
|
description = "A swiss army knife for creating binary modules for Garry's Mod in Rust"
|
||||||
repository = "https://github.com/WilliamVenner/gmod-rs"
|
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_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 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 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 {}
|
unsafe impl Sync for LuaShared {}
|
||||||
impl LuaShared {
|
impl LuaShared {
|
||||||
|
@ -231,6 +236,11 @@ impl LuaShared {
|
||||||
lua_topointer: find_symbol!("lua_topointer"),
|
lua_topointer: find_symbol!("lua_topointer"),
|
||||||
lua_newuserdata: find_symbol!("lua_newuserdata"),
|
lua_newuserdata: find_symbol!("lua_newuserdata"),
|
||||||
lual_newmetatable: find_symbol!("luaL_newmetatable"),
|
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)
|
(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)]
|
#[inline(always)]
|
||||||
pub unsafe fn pcall(&self, nargs: i32, nresults: i32, errfunc: i32) -> i32 {
|
pub unsafe fn pcall(&self, nargs: i32, nresults: i32, errfunc: i32) -> i32 {
|
||||||
(LUA_SHARED.lua_pcall)(*self, nargs, nresults, errfunc)
|
(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 {
|
pub unsafe fn pcall_ignore(&self, nargs: i32, nresults: i32) -> bool {
|
||||||
let res = self.pcall(nargs, nresults, 0);
|
let res = self.pcall(nargs, nresults, 0);
|
||||||
if res == LUA_ERRRUN {
|
if res == LUA_ERRRUN {
|
||||||
|
crate::lua_stack_guard!(self => {
|
||||||
self.get_global(crate::lua_string!("ErrorNoHaltWithStack"));
|
self.get_global(crate::lua_string!("ErrorNoHaltWithStack"));
|
||||||
if self.is_nil(-1) {
|
if self.is_nil(-1) {
|
||||||
eprintln!("[ERROR] {:?}", self.get_string(-2));
|
eprintln!("[ERROR] {:?}", self.get_string(-2));
|
||||||
self.pop_n(2);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
self.push_value(-2);
|
|
||||||
self.call(1, 0);
|
|
||||||
self.pop();
|
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
|
true
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub unsafe fn load_string(&self, src: LuaString) -> Result<(), LuaError> {
|
pub unsafe fn load_string(&self, src: LuaString) -> Result<(), LuaError> {
|
||||||
let lua_error_code = (LUA_SHARED.lual_loadstring)(*self, src);
|
let lua_error_code = (LUA_SHARED.lual_loadstring)(*self, src);
|
||||||
|
@ -450,9 +469,25 @@ impl LuaState {
|
||||||
(LUA_SHARED.lua_touserdata)(*self, index)
|
(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.
|
/// 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.
|
||||||
|
#[inline(always)]
|
||||||
pub unsafe fn new_metatable(&self, name: LuaString) -> bool {
|
pub unsafe fn new_metatable(&self, name: LuaString) -> bool {
|
||||||
(LUA_SHARED.lual_newmetatable)(*self, name) == 0
|
(LUA_SHARED.lual_newmetatable)(*self, name) == 0
|
||||||
}
|
}
|
||||||
|
@ -480,6 +515,7 @@ impl LuaState {
|
||||||
self.push_value(-2);
|
self.push_value(-2);
|
||||||
self.set_metatable(-2);
|
self.set_metatable(-2);
|
||||||
self.remove(self.get_top() - 1);
|
self.remove(self.get_top() - 1);
|
||||||
|
self.remove(self.get_top() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr.write(data);
|
ptr.write(data);
|
||||||
|
|
|
@ -6,6 +6,9 @@ pub use import::*;
|
||||||
mod lua_state;
|
mod lua_state;
|
||||||
pub use lua_state::LuaState as State;
|
pub use lua_state::LuaState as State;
|
||||||
|
|
||||||
|
mod push;
|
||||||
|
pub use push::*;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum LuaError {
|
pub enum LuaError {
|
||||||
/// Out of memory
|
/// Out of memory
|
||||||
|
@ -73,7 +76,21 @@ macro_rules! lua_stack_guard {
|
||||||
let ret = (|| $code)();
|
let ret = (|| $code)();
|
||||||
if top != $lua.get_top() {
|
if top != $lua.get_top() {
|
||||||
$lua.dump_stack();
|
$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
|
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