New apis and clippy fixes

This commit is contained in:
William Venner 2022-07-07 19:00:34 +01:00
parent 64ade67496
commit 85c1d6a82a
10 changed files with 126 additions and 39 deletions

2
Cargo.lock generated
View File

@ -109,7 +109,7 @@ dependencies = [
[[package]] [[package]]
name = "gmod" name = "gmod"
version = "15.0.2" version = "16.0.0"
dependencies = [ dependencies = [
"cfg_table", "cfg_table",
"cstr", "cstr",

View File

@ -1,6 +1,6 @@
[package] [package]
name = "gmod" name = "gmod"
version = "15.0.2" version = "16.0.0"
authors = ["William Venner <william@venner.io>"] authors = ["William Venner <william@venner.io>"]
edition = "2021" edition = "2021"
license = "MIT" license = "MIT"

View File

@ -1,5 +1,8 @@
//! [Available Lua Functions](https://docs.rs/gmod/latest/gmod/lua/struct.State.html) //! [Available Lua Functions](https://docs.rs/gmod/latest/gmod/lua/struct.State.html)
#![allow(clippy::missing_safety_doc)]
#![allow(clippy::result_unit_err)]
#![feature(c_unwind)] #![feature(c_unwind)]
#![feature(thread_id_value)] #![feature(thread_id_value)]
@ -255,11 +258,11 @@ pub struct OpenGmodLibraryErrs(pub std::collections::HashMap<&'static str, liblo
impl std::error::Error for OpenGmodLibraryErrs {} impl std::error::Error for OpenGmodLibraryErrs {}
impl std::fmt::Display for OpenGmodLibraryErrs { impl std::fmt::Display for OpenGmodLibraryErrs {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "")?; writeln!(f)?;
for (path, err) in &self.0 { for (path, err) in &self.0 {
writeln!(f, "{} = {}", path, err)?; writeln!(f, "{} = {}", path, err)?;
} }
writeln!(f, "")?; writeln!(f)?;
Ok(()) Ok(())
} }
} }

View File

@ -114,6 +114,7 @@ impl std::ops::DerefMut for LuaSharedInterface {
pub static mut LUA_SHARED: LuaSharedInterface = LuaSharedInterface(UnsafeCell::new(std::ptr::null_mut()), #[cfg(debug_assertions)] AtomicI64::new(-1)); pub static mut LUA_SHARED: LuaSharedInterface = LuaSharedInterface(UnsafeCell::new(std::ptr::null_mut()), #[cfg(debug_assertions)] AtomicI64::new(-1));
pub struct LuaShared { pub struct LuaShared {
pub(crate) library: &'static libloading::Library,
pub lual_newstate: Symbol<'static, unsafe extern "C-unwind" fn() -> LuaState>, 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_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_loadfile: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, path: LuaString) -> i32>,
@ -180,7 +181,7 @@ impl LuaShared {
fn import() -> Self { fn import() -> Self {
unsafe { unsafe {
let (library, path) = Self::find_lua_shared(); let (library, path) = Self::find_lua_shared();
let library = Box::leak(Box::new(library)); // Keep this library referenced forever let library = Box::leak(Box::new(library));
macro_rules! find_symbol { macro_rules! find_symbol {
( $symbol:literal ) => { ( $symbol:literal ) => {
@ -249,6 +250,7 @@ impl LuaShared {
lua_status: find_symbol!("lua_status"), lua_status: find_symbol!("lua_status"),
lua_xmove: find_symbol!("lua_xmove"), lua_xmove: find_symbol!("lua_xmove"),
lua_equal: find_symbol!("lua_equal"), lua_equal: find_symbol!("lua_equal"),
library,
} }
} }
} }

View File

@ -1,8 +1,5 @@
use std::{mem::MaybeUninit, borrow::Cow, ffi::c_void}; use std::{mem::MaybeUninit, borrow::Cow, ffi::c_void};
use crate::{userdata::TaggedUserData, lua::*};
use crate::lua::*;
use crate::userdata::TaggedUserData;
unsafe fn handle_pcall_ignore(lua: State) { unsafe fn handle_pcall_ignore(lua: State) {
crate::lua_stack_guard!(lua => { crate::lua_stack_guard!(lua => {
@ -219,7 +216,7 @@ impl LuaState {
handle_pcall_ignore(*self); handle_pcall_ignore(*self);
false false
} }
err @ _ => { err => {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
eprintln!("[gmod-rs] pcall_ignore unknown error: {}", err); eprintln!("[gmod-rs] pcall_ignore unknown error: {}", err);
false false
@ -316,11 +313,52 @@ impl LuaState {
} }
#[inline(always)] #[inline(always)]
/// Creates a closure, which can be used as a function with stored data (upvalues)
///
/// ## Example
///
/// ```ignore
/// #[lua_function]
/// unsafe fn foo(lua: gmod::lua::State) {
/// lua.get_closure_arg(1);
/// let hello = lua.get_string(-1);
/// println!("{}", hello);
/// }
///
/// lua.push_string("Hello, world!");
/// lua.push_closure(foo, 1);
/// ```
pub unsafe fn push_closure(&self, func: LuaFunction, n: i32) { pub unsafe fn push_closure(&self, func: LuaFunction, n: i32) {
debug_assert!(n <= 255, "Can't push more than 255 arguments into a closure"); debug_assert!(n <= 255, "Can't push more than 255 arguments into a closure");
(LUA_SHARED.lua_pushcclosure)(*self, func, n) (LUA_SHARED.lua_pushcclosure)(*self, func, n)
} }
#[inline(always)]
/// Pushes the `n`th closure argument onto the stack
///
/// ## Example
///
/// ```ignore
/// #[lua_function]
/// unsafe fn foo(lua: gmod::lua::State) {
/// lua.push_closure_arg(1);
/// let hello = lua.get_string(-1);
/// println!("{}", hello);
/// }
///
/// lua.push_string("Hello, world!");
/// lua.push_closure(foo, 1);
/// ```
pub unsafe fn push_closure_arg(&self, n: i32) {
self.push_value(self.upvalue_index(n));
}
#[inline(always)]
/// Equivalent to C `lua_upvalueindex` macro
pub const fn upvalue_index(&self, idx: i32) -> i32 {
LUA_GLOBALSINDEX - idx
}
#[inline(always)] #[inline(always)]
pub unsafe fn set_table(&self, index: i32) { pub unsafe fn set_table(&self, index: i32) {
(LUA_SHARED.lua_settable)(*self, index) (LUA_SHARED.lua_settable)(*self, index)
@ -393,8 +431,7 @@ impl LuaState {
} }
pub unsafe fn test_userdata(&self, index: i32, name: LuaString) -> bool { pub unsafe fn test_userdata(&self, index: i32, name: LuaString) -> bool {
if !(LUA_SHARED.lua_touserdata)(*self, index).is_null() { if !(LUA_SHARED.lua_touserdata)(*self, index).is_null() && self.get_metatable(index) != 0 {
if self.get_metatable(index) != 0 {
self.get_field(LUA_REGISTRYINDEX, name); self.get_field(LUA_REGISTRYINDEX, name);
let result = self.raw_equal(-1, -2); let result = self.raw_equal(-1, -2);
self.pop_n(2); self.pop_n(2);
@ -402,7 +439,6 @@ impl LuaState {
return true; return true;
} }
} }
}
false false
} }
@ -463,6 +499,7 @@ impl LuaState {
} }
#[inline(always)] #[inline(always)]
#[allow(clippy::len_without_is_empty)]
pub unsafe fn len(&self, index: i32) -> i32 { pub unsafe fn len(&self, index: i32) -> i32 {
(LUA_SHARED.lua_objlen)(*self, index) (LUA_SHARED.lua_objlen)(*self, index)
} }
@ -527,7 +564,7 @@ impl LuaState {
pub unsafe fn coroutine_resume_call(&self, narg: i32) { pub unsafe fn coroutine_resume_call(&self, narg: i32) {
match (LUA_SHARED.lua_resume)(*self, narg) { match (LUA_SHARED.lua_resume)(*self, narg) {
LUA_OK => {}, LUA_OK => {},
LUA_ERRRUN => self.error(self.get_string(-2).unwrap_or_else(|| Cow::Borrowed("Unknown error")).as_ref()), LUA_ERRRUN => self.error(self.get_string(-2).unwrap_or(Cow::Borrowed("Unknown error")).as_ref()),
LUA_ERRMEM => self.error("Out of memory"), LUA_ERRMEM => self.error("Out of memory"),
_ => self.error("Unknown internal Lua error") _ => self.error("Unknown internal Lua error")
} }
@ -542,7 +579,7 @@ impl LuaState {
handle_pcall_ignore(*self); handle_pcall_ignore(*self);
Err(()) Err(())
}, },
err @ _ => { err => {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
eprintln!("[gmod-rs] coroutine_resume_pcall_ignore unknown error: {}", err); eprintln!("[gmod-rs] coroutine_resume_pcall_ignore unknown error: {}", err);
Err(()) Err(())
@ -631,11 +668,9 @@ impl LuaState {
pub unsafe fn debug_getinfo_at(&self, level: i32, what: LuaString) -> Option<LuaDebug> { pub unsafe fn debug_getinfo_at(&self, level: i32, what: LuaString) -> Option<LuaDebug> {
let mut ar = MaybeUninit::uninit(); let mut ar = MaybeUninit::uninit();
if (LUA_SHARED.lua_getstack)(*self, level, ar.as_mut_ptr()) != 0 { if (LUA_SHARED.lua_getstack)(*self, level, ar.as_mut_ptr()) != 0 && (LUA_SHARED.lua_getinfo)(*self, what, ar.as_mut_ptr()) != 0 {
if (LUA_SHARED.lua_getinfo)(*self, what, ar.as_mut_ptr()) != 0 {
return Some(ar.assume_init()); return Some(ar.assume_init());
} }
}
None None
} }

View File

@ -14,6 +14,8 @@ pub use push::*;
mod returns; mod returns;
pub use returns::ValuesReturned; pub use returns::ValuesReturned;
mod raw_bind;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum LuaError { pub enum LuaError {
/// Out of memory /// Out of memory
@ -78,7 +80,7 @@ macro_rules! lua_stack_guard {
( $lua:ident => $code:block ) => {{ ( $lua:ident => $code:block ) => {{
#[cfg(debug_assertions)] { #[cfg(debug_assertions)] {
let top = $lua.get_top(); let top = $lua.get_top();
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! Expected the stack to have {} elements, but it has {}!", top, $lua.get_top()); panic!("Stack is dirty! Expected the stack to have {} elements, but it has {}!", top, $lua.get_top());

View File

@ -98,7 +98,7 @@ impl PushToLua for Vec<u8> {
impl PushToLua for &[u8] { impl PushToLua for &[u8] {
#[inline] #[inline]
unsafe fn push_to_lua(self, lua: crate::lua::State) { unsafe fn push_to_lua(self, lua: crate::lua::State) {
lua.push_binary_string(&self); lua.push_binary_string(self);
} }
} }
impl PushToLua for Duration { impl PushToLua for Duration {

45
gmod/src/lua/raw_bind.rs Normal file
View File

@ -0,0 +1,45 @@
use crate::lua::*;
pub trait CLuaFunction: Copy {}
macro_rules! impl_c_lua_function {
($($($arg:ident) *;)*) => {
$(
impl<$($arg, )* R> CLuaFunction for extern "C-unwind" fn($($arg),*) -> R {}
impl<$($arg, )* R> CLuaFunction for unsafe extern "C-unwind" fn($($arg),*) -> R {}
impl<$($arg, )* R> CLuaFunction for extern "C" fn($($arg),*) -> R {}
impl<$($arg, )* R> CLuaFunction for unsafe extern "C" fn($($arg),*) -> R {}
)*
};
}
impl_c_lua_function!(
;
T1;
T1 T2;
T1 T2 T3;
T1 T2 T3 T4;
T1 T2 T3 T4 T5;
T1 T2 T3 T4 T5 T6;
T1 T2 T3 T4 T5 T6 T7;
T1 T2 T3 T4 T5 T6 T7 T8;
T1 T2 T3 T4 T5 T6 T7 T8 T9;
T1 T2 T3 T4 T5 T6 T7 T8 T9 T10;
T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11;
T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12;
T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13;
T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14;
T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15;
T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15 T16;
);
impl State {
#[inline(always)]
/// Binds to a raw Lua C function.
///
/// If anything is missing from this library, you can use this function to bind it yourself.
///
/// Note, this may be a somewhat expensive operation, so storing its result in some way is recommended.
pub unsafe fn raw_bind<F: CLuaFunction>(&self, symbol: &[u8]) -> Result<F, libloading::Error> {
LUA_SHARED.library.get::<F>(symbol).map(|f| *f)
}
}

View File

@ -3,10 +3,10 @@ use std::{num::NonZeroI32, borrow::Cow};
#[repr(transparent)] #[repr(transparent)]
pub struct ValuesReturned(pub i32); pub struct ValuesReturned(pub i32);
impl Into<i32> for ValuesReturned { impl From<ValuesReturned> for i32 {
#[inline(always)] #[inline(always)]
fn into(self) -> i32 { fn from(v: ValuesReturned) -> Self {
self.0 v.0
} }
} }
@ -45,11 +45,11 @@ impl From<Option<NonZeroI32>> for ValuesReturned {
} }
pub trait DisplayLuaError { pub trait DisplayLuaError {
fn display_lua_error<'a>(&'a self) -> Cow<'a, str>; fn display_lua_error(&self) -> Cow<'_, str>;
} }
impl<E: std::fmt::Debug> DisplayLuaError for E { impl<E: std::fmt::Debug> DisplayLuaError for E {
#[inline(always)] #[inline(always)]
fn display_lua_error<'a>(&'a self) -> Cow<'a, str> { fn display_lua_error(&self) -> Cow<'_, str> {
Cow::Owned(format!("{:?}", self)) Cow::Owned(format!("{:?}", self))
} }
} }

View File

@ -100,7 +100,7 @@ macro_rules! userdata {
/// This will NOT perform a type check to ensure that the tagged userdata matches the user data you are coercing to. /// This will NOT perform a type check to ensure that the tagged userdata matches the user data you are coercing to.
/// ///
/// Coercing to the wrong type is undefined behaviour and is likely to crash your program. /// Coercing to the wrong type is undefined behaviour and is likely to crash your program.
pub unsafe fn coerce_unchecked<T: CoercibleUserData>(&self) -> &mut T { pub unsafe fn coerce_unchecked<'a, 'b, T: CoercibleUserData>(&'a self) -> &'b mut T {
&mut *(self.data as *mut T) &mut *(self.data as *mut T)
} }
} }