Initial commit
This commit is contained in:
commit
6a3f374c96
|
@ -0,0 +1,7 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = tab
|
||||||
|
indent_size = 4
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
|
@ -0,0 +1 @@
|
||||||
|
/target
|
|
@ -0,0 +1,270 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.0.70"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cstr"
|
||||||
|
version = "0.2.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c11a39d776a3b35896711da8a04dc1835169dcd36f710878187637314e47941b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ctor"
|
||||||
|
version = "0.1.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ccc0a48a9b826acdf4028595adc9db92caea352f7af011a3034acd172a52a0aa"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "detour"
|
||||||
|
version = "0.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f3c83fabcc3bc336e19320c13576ea708a15deec201d6b879b7ad1b92734d7b9"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"generic-array",
|
||||||
|
"lazy_static",
|
||||||
|
"libc",
|
||||||
|
"libudis86-sys",
|
||||||
|
"mmap-fixed",
|
||||||
|
"region",
|
||||||
|
"slice-pool",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-array"
|
||||||
|
version = "0.14.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gmod"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"cstr",
|
||||||
|
"ctor",
|
||||||
|
"detour",
|
||||||
|
"gmod-macros",
|
||||||
|
"lazy_static",
|
||||||
|
"libloading",
|
||||||
|
"skidscan",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gmod-macros"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "kernel32-sys"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.2.8",
|
||||||
|
"winapi-build",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.101"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libloading"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6f84d96438c15fcd6c3f244c8fce01d1e2b9c6b5623e9c711dc9286d8fc92d6a"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"winapi 0.3.9",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libudis86-sys"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "139bbf9ddb1bfc90c1ac64dd2923d9c957cd433cee7315c018125d72ab08a6b0"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mach"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mmap-fixed"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "27c1ae264d6343d3b4079549f6bc9e6d074dc4106cb1324c7753c6ce11d07b21"
|
||||||
|
dependencies = [
|
||||||
|
"kernel32-sys",
|
||||||
|
"libc",
|
||||||
|
"winapi 0.2.8",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.29"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-xid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "region"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "877e54ea2adcd70d80e9179344c97f93ef0dffd6b03e1f4529e6e83ab2fa9ae0"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"libc",
|
||||||
|
"mach",
|
||||||
|
"winapi 0.3.9",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "skidscan"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "89c52ddc5d6dde2bbb702e353d78c059cbbe07f15189ead0b7ac7da49b44bacc"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"skidscan-macros",
|
||||||
|
"winapi 0.3.9",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "skidscan-macros"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c98a622ae309bfbfe69e99bbf9e8ce23efc15817eda4bda1369bbb3eea668f83"
|
||||||
|
dependencies = [
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "slice-pool"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "733fc6e5f1bd3a8136f842c9bdea4e5f17c910c2fcc98c90c3aa7604ef5e2e7a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "1.0.76"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-xid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.14.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-xid"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.2.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-i686-pc-windows-gnu",
|
||||||
|
"winapi-x86_64-pc-windows-gnu",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-build"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
|
@ -0,0 +1,5 @@
|
||||||
|
[workspace]
|
||||||
|
members = [
|
||||||
|
"gmod",
|
||||||
|
"gmod-macros"
|
||||||
|
]
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 William Venner
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
|
@ -0,0 +1,3 @@
|
||||||
|
# ⚙ gmod-rs
|
||||||
|
|
||||||
|
A swiss army knife for creating binary modules for Garry's Mod in Rust.
|
|
@ -0,0 +1,16 @@
|
||||||
|
[package]
|
||||||
|
name = "gmod-macros"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["William Venner <william@venner.io>"]
|
||||||
|
edition = "2018"
|
||||||
|
license = "MIT"
|
||||||
|
description = "Proc macros for gmod-rs"
|
||||||
|
repository = "https://github.com/WilliamVenner/gmod-rs"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
proc-macro = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
proc-macro2 = "1"
|
||||||
|
syn = { version = "1", features = ["full"] }
|
||||||
|
quote = "1"
|
|
@ -0,0 +1,39 @@
|
||||||
|
#[macro_use]
|
||||||
|
extern crate syn;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate quote;
|
||||||
|
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
use quote::ToTokens;
|
||||||
|
use syn::{ReturnType, ItemFn};
|
||||||
|
|
||||||
|
fn check_lua_function(input: &mut ItemFn) {
|
||||||
|
assert!(input.sig.asyncness.is_none(), "Cannot be async");
|
||||||
|
assert!(input.sig.constness.is_none(), "Cannot be const");
|
||||||
|
assert!(input.sig.inputs.len() == 1, "There can only be one argument, and it should be a pointer to the Lua state (gmod::lua::State)");
|
||||||
|
assert!(matches!(&input.sig.output, ReturnType::Type(_, r#type) if r#type.to_token_stream().to_string() == "i32"), "The output must be an i32, representing the number of return values of the function");
|
||||||
|
assert!(input.sig.abi.is_none() || input.sig.abi.as_ref().and_then(|abi| abi.name.as_ref()).map(|abi| abi.value() == "C-unwind").unwrap_or(true), "Do not specify an ABI");
|
||||||
|
input.sig.abi = Some(syn::parse_quote!(extern "C-unwind"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn gmod13_open(_attr: TokenStream, tokens: TokenStream) -> TokenStream {
|
||||||
|
let mut input = parse_macro_input!(tokens as ItemFn);
|
||||||
|
check_lua_function(&mut input);
|
||||||
|
TokenStream::from(quote!(#[no_mangle] #input))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn gmod13_close(_attr: TokenStream, tokens: TokenStream) -> TokenStream {
|
||||||
|
let mut input = parse_macro_input!(tokens as ItemFn);
|
||||||
|
check_lua_function(&mut input);
|
||||||
|
TokenStream::from(quote!(#input))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn lua_function(_attr: TokenStream, tokens: TokenStream) -> TokenStream {
|
||||||
|
let mut input = parse_macro_input!(tokens as ItemFn);
|
||||||
|
check_lua_function(&mut input);
|
||||||
|
TokenStream::from(quote!(#input))
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
[package]
|
||||||
|
name = "gmod"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["William Venner <william@venner.io>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
libloading = "0"
|
||||||
|
detour = "0"
|
||||||
|
skidscan = "0"
|
||||||
|
cstr = "0"
|
||||||
|
lazy_static = "1"
|
||||||
|
ctor = "0"
|
||||||
|
gmod-macros = { version = "0.1.0", path = "../gmod-macros" }
|
|
@ -0,0 +1,11 @@
|
||||||
|
#![feature(c_unwind)]
|
||||||
|
|
||||||
|
pub use libloading;
|
||||||
|
pub use detour;
|
||||||
|
pub use skidscan as sigscan;
|
||||||
|
pub use cstr;
|
||||||
|
pub use ctor::{ctor as dllopen, dtor as dllclose};
|
||||||
|
pub use gmod_macros::*;
|
||||||
|
|
||||||
|
pub mod lua;
|
||||||
|
pub mod msgc;
|
|
@ -0,0 +1,215 @@
|
||||||
|
use libloading::{Library, Symbol};
|
||||||
|
|
||||||
|
macro_rules! find_library {
|
||||||
|
($path:literal) => {
|
||||||
|
Library::new($path).map(|lib| (lib, $path))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
use super::{LuaError, State as LuaState, lua_state::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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static::lazy_static! {
|
||||||
|
pub(super) static ref LUA_SHARED: LuaShared = LuaShared::import();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) struct LuaShared {
|
||||||
|
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 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_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 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>,
|
||||||
|
}
|
||||||
|
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_loadfile: find_symbol!("luaL_loadfile"),
|
||||||
|
lual_loadstring: find_symbol!("luaL_loadstring"),
|
||||||
|
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"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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"))]
|
||||||
|
unsafe fn find_lua_shared() -> (Library, &'static str) {
|
||||||
|
find_library!("bin/win64/lua_shared.dll")
|
||||||
|
.expect("Failed to load lua_shared.dll")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(target_os = "windows", target_pointer_width = "32"))]
|
||||||
|
unsafe fn find_lua_shared() -> (Library, &'static str) {
|
||||||
|
find_library!("garrysmod/bin/lua_shared.dll")
|
||||||
|
.or_else(|_| find_library!("bin/lua_shared.dll"))
|
||||||
|
.expect("Failed to load lua_shared.dll")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(target_os = "linux", target_pointer_width = "32"))]
|
||||||
|
unsafe fn find_lua_shared() -> (Library, &'static str) {
|
||||||
|
find_library!("garrysmod/bin/lua_shared_srv.so")
|
||||||
|
.or_else(|_| find_library!("bin/linux32/lua_shared.so"))
|
||||||
|
.expect("Failed to find lua_shared.so or lua_shared_srv.so")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(target_os = "linux", target_pointer_width = "64"))]
|
||||||
|
unsafe fn find_lua_shared() -> (Library, &'static str) {
|
||||||
|
find_library!("bin/linux64/lua_shared.so")
|
||||||
|
.expect("Failed to find lua_shared.so")
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,466 @@
|
||||||
|
use std::{mem::MaybeUninit, borrow::Cow, ffi::c_void};
|
||||||
|
|
||||||
|
use crate::lua::*;
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct LuaState(pub *mut std::ffi::c_void);
|
||||||
|
unsafe impl Send for LuaState {}
|
||||||
|
impl LuaState {
|
||||||
|
|
||||||
|
/// Returns the Lua string as a slice of bytes.
|
||||||
|
///
|
||||||
|
/// **WARNING:** This will CHANGE the type of the value at the given index to a string.
|
||||||
|
///
|
||||||
|
/// Returns None if the value at the given index is not convertible to a string.
|
||||||
|
pub unsafe fn get_binary_string(&self, index: i32) -> Option<&[u8]> {
|
||||||
|
let mut len: usize = 0;
|
||||||
|
let ptr = (LUA_SHARED.lua_tolstring)(*self, index, &mut len);
|
||||||
|
|
||||||
|
if ptr.is_null() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(std::slice::from_raw_parts(ptr as *const u8, len))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the Lua string as a Rust UTF-8 String.
|
||||||
|
///
|
||||||
|
/// **WARNING:** This will CHANGE the type of the value at the given index to a string.
|
||||||
|
///
|
||||||
|
/// Returns None if the value at the given index is not convertible to a string.
|
||||||
|
///
|
||||||
|
/// This is a lossy operation, and will replace any invalid UTF-8 sequences with the Unicode replacement character. See the documentation for `String::from_utf8_lossy` for more information.
|
||||||
|
///
|
||||||
|
/// If you need raw data, use `get_binary_string`.
|
||||||
|
pub unsafe fn get_string(&self, index: i32) -> Option<std::borrow::Cow<'_, str>> {
|
||||||
|
let mut len: usize = 0;
|
||||||
|
let ptr = (LUA_SHARED.lua_tolstring)(*self, index, &mut len);
|
||||||
|
|
||||||
|
if ptr.is_null() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let bytes = std::slice::from_raw_parts(ptr as *const u8, len);
|
||||||
|
|
||||||
|
Some(String::from_utf8_lossy(bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the name of the type of the value at the given index.
|
||||||
|
pub unsafe fn get_type(&self, index: i32) -> &str {
|
||||||
|
let lua_type = (LUA_SHARED.lua_type)(*self, index);
|
||||||
|
let lua_type_str_ptr = (LUA_SHARED.lua_typename)(*self, lua_type);
|
||||||
|
let lua_type_str = std::ffi::CStr::from_ptr(lua_type_str_ptr);
|
||||||
|
unsafe { std::str::from_utf8_unchecked(lua_type_str.to_bytes()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn get_top(&self) -> i32 {
|
||||||
|
(LUA_SHARED.lua_gettop)(*self)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
/// Pops the stack, inserts the value into the registry table, and returns the registry index of the value.
|
||||||
|
///
|
||||||
|
/// Use `from_reference` with the reference index to push the value back onto the stack.
|
||||||
|
///
|
||||||
|
/// Use `dereference` to free the reference from the registry table.
|
||||||
|
pub unsafe fn reference(&self) -> LuaReference {
|
||||||
|
(LUA_SHARED.lual_ref)(*self, LUA_REGISTRYINDEX)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn dereference(&self, r#ref: LuaReference) {
|
||||||
|
(LUA_SHARED.lual_unref)(*self, LUA_REGISTRYINDEX, r#ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn from_reference(&self, r#ref: LuaReference) {
|
||||||
|
self.raw_geti(LUA_REGISTRYINDEX, r#ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn is_nil(&self, index: i32) -> bool {
|
||||||
|
(LUA_SHARED.lua_type)(*self, index) == LUA_TNIL
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn is_function(&self, index: i32) -> bool {
|
||||||
|
(LUA_SHARED.lua_type)(*self, index) == LUA_TFUNCTION
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn is_table(&self, index: i32) -> bool {
|
||||||
|
(LUA_SHARED.lua_type)(*self, index) == LUA_TTABLE
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn is_boolean(&self, index: i32) -> bool {
|
||||||
|
(LUA_SHARED.lua_type)(*self, index) == LUA_TBOOLEAN
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn remove(&self, index: i32) {
|
||||||
|
(LUA_SHARED.lua_remove)(*self, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn push_value(&self, index: i32) {
|
||||||
|
(LUA_SHARED.lua_pushvalue)(*self, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn get_field(&self, index: i32, k: LuaString) {
|
||||||
|
(LUA_SHARED.lua_getfield)(*self, index, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn push_boolean(&self, boolean: bool) {
|
||||||
|
(LUA_SHARED.lua_pushboolean)(*self, if boolean { 1 } else { 0 })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn push_integer(&self, int: LuaInt) {
|
||||||
|
(LUA_SHARED.lua_pushinteger)(*self, int)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn push_number(&self, num: LuaNumber) {
|
||||||
|
(LUA_SHARED.lua_pushnumber)(*self, num)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn push_nil(&self) {
|
||||||
|
(LUA_SHARED.lua_pushnil)(*self)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn pcall(&self, nargs: i32, nresults: i32, errfunc: i32) -> i32 {
|
||||||
|
(LUA_SHARED.lua_pcall)(*self, nargs, nresults, errfunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn load_string(&self, src: LuaString) -> Result<(), LuaError> {
|
||||||
|
let lua_error_code = (LUA_SHARED.lual_loadstring)(*self, src);
|
||||||
|
if lua_error_code == 0 {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(LuaError::from_lua_state(*self, lua_error_code))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn load_file(&self, path: LuaString) -> Result<(), LuaError> {
|
||||||
|
let lua_error_code = (LUA_SHARED.lual_loadfile)(*self, path);
|
||||||
|
if lua_error_code == 0 {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(LuaError::from_lua_state(*self, lua_error_code))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn pop(&self) {
|
||||||
|
self.pop_n(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn pop_n(&self, count: i32) {
|
||||||
|
self.set_top(-count - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn set_top(&self, index: i32) {
|
||||||
|
(LUA_SHARED.lua_settop)(*self, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn lua_type(&self, index: i32) -> i32 {
|
||||||
|
(LUA_SHARED.lua_type)(*self, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn lua_type_name(&self, lua_type_id: i32) -> Cow<'_, str> {
|
||||||
|
let type_str_ptr = (LUA_SHARED.lua_typename)(*self, lua_type_id);
|
||||||
|
let type_str = std::ffi::CStr::from_ptr(type_str_ptr);
|
||||||
|
type_str.to_string_lossy()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn replace(&self, index: i32) {
|
||||||
|
(LUA_SHARED.lua_replace)(*self, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn push_globals(&self) {
|
||||||
|
(LUA_SHARED.lua_pushvalue)(*self, LUA_GLOBALSINDEX)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn push_string(&self, data: &str) {
|
||||||
|
(LUA_SHARED.lua_pushlstring)(*self, data.as_ptr() as LuaString, data.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn push_binary_string(&self, data: &[u8]) {
|
||||||
|
(LUA_SHARED.lua_pushlstring)(*self, data.as_ptr() as LuaString, data.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn push_function(&self, func: LuaFunction) {
|
||||||
|
(LUA_SHARED.lua_pushcclosure)(*self, func, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn set_table(&self, index: i32) {
|
||||||
|
(LUA_SHARED.lua_settable)(*self, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn set_field(&self, index: i32, k: LuaString) {
|
||||||
|
(LUA_SHARED.lua_setfield)(*self, index, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn get_global(&self, name: LuaString) {
|
||||||
|
(LUA_SHARED.lua_getfield)(*self, LUA_GLOBALSINDEX, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn set_global(&self, name: LuaString) {
|
||||||
|
(LUA_SHARED.lua_setfield)(*self, LUA_GLOBALSINDEX, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn call(&self, nargs: i32, nresults: i32) {
|
||||||
|
(LUA_SHARED.lua_call)(*self, nargs, nresults)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn insert(&self, index: i32) {
|
||||||
|
(LUA_SHARED.lua_insert)(*self, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new table and pushes it to the stack.
|
||||||
|
/// seq_n is a hint as to how many sequential elements the table may have.
|
||||||
|
/// hash_n is a hint as to how many non-sequential/hashed elements the table may have.
|
||||||
|
/// Lua may use these hints to preallocate memory.
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn create_table(&self, seq_n: i32, hash_n: i32) {
|
||||||
|
(LUA_SHARED.lua_createtable)(*self, seq_n, hash_n)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new table and pushes it to the stack without memory preallocation hints.
|
||||||
|
/// Equivalent to `create_table(0, 0)`
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn new_table(&self) {
|
||||||
|
(LUA_SHARED.lua_createtable)(*self, 0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn get_table(&self, index: i32) {
|
||||||
|
(LUA_SHARED.lua_gettable)(*self, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn check_binary_string(&self, arg: i32) -> &[u8] {
|
||||||
|
let mut len: usize = 0;
|
||||||
|
let ptr = (LUA_SHARED.lual_checklstring)(*self, arg, &mut len);
|
||||||
|
std::slice::from_raw_parts(ptr as *const u8, len)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn check_string(&self, arg: i32) -> Cow<'_, str> {
|
||||||
|
let mut len: usize = 0;
|
||||||
|
let ptr = (LUA_SHARED.lual_checklstring)(*self, arg, &mut len);
|
||||||
|
String::from_utf8_lossy(std::slice::from_raw_parts(ptr as *const u8, len))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn check_userdata(&self, arg: i32, name: LuaString) -> *const c_void {
|
||||||
|
(LUA_SHARED.lual_checkudata)(*self, arg, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn test_userdata(&self, index: i32, name: LuaString) -> bool {
|
||||||
|
if !(LUA_SHARED.lua_touserdata)(*self, index).is_null() {
|
||||||
|
if self.get_metatable(index) != 0 {
|
||||||
|
self.get_field(LUA_REGISTRYINDEX, name);
|
||||||
|
let result = self.raw_equal(-1, -2);
|
||||||
|
self.pop_n(2);
|
||||||
|
if result {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn raw_equal(&self, a: i32, b: i32) -> bool {
|
||||||
|
(LUA_SHARED.lua_rawequal)(*self, a, b) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn get_metatable(&self, index: i32) -> i32 {
|
||||||
|
(LUA_SHARED.lua_getmetatable)(*self, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn check_integer(&self, arg: i32) -> LuaInt {
|
||||||
|
(LUA_SHARED.lual_checkinteger)(*self, arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn check_number(&self, arg: i32) -> f64 {
|
||||||
|
(LUA_SHARED.lual_checknumber)(*self, arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn to_integer(&self, index: i32) -> LuaInt {
|
||||||
|
(LUA_SHARED.lua_tointeger)(*self, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn to_number(&self, index: i32) -> f64 {
|
||||||
|
(LUA_SHARED.lua_tonumber)(*self, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn get_boolean(&self, index: i32) -> bool {
|
||||||
|
(LUA_SHARED.lua_toboolean)(*self, index) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn set_metatable(&self, index: i32) -> i32 {
|
||||||
|
(LUA_SHARED.lua_setmetatable)(*self, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn len(&self, index: i32) -> i32 {
|
||||||
|
(LUA_SHARED.lua_objlen)(*self, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn raw_geti(&self, t: i32, index: i32) {
|
||||||
|
(LUA_SHARED.lua_rawgeti)(*self, t, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn raw_seti(&self, t: i32, index: i32) {
|
||||||
|
(LUA_SHARED.lua_rawseti)(*self, t, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn next(&self, index: i32) -> i32 {
|
||||||
|
(LUA_SHARED.lua_next)(*self, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn error<S: AsRef<str>>(&self, msg: S) -> ! {
|
||||||
|
self.push_string(msg.as_ref());
|
||||||
|
(LUA_SHARED.lua_error)(*self);
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn debug_get_info(&self, what: LuaString) -> Option<LuaDebug> {
|
||||||
|
let mut ar = MaybeUninit::uninit();
|
||||||
|
if (LUA_SHARED.lua_getinfo)(*self, what, ar.as_mut_ptr()) != 0 {
|
||||||
|
Some(ar.assume_init())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn debug_get_invocation_info(&self, level: i32, what: LuaString) -> Option<LuaDebug> {
|
||||||
|
let mut ar = MaybeUninit::uninit();
|
||||||
|
if (LUA_SHARED.lua_getstack)(*self, level, ar.as_mut_ptr()) != 0 {
|
||||||
|
if (LUA_SHARED.lua_getinfo)(*self, what, ar.as_mut_ptr()) != 0 {
|
||||||
|
return Some(ar.assume_init());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
pub unsafe fn dump_stack(&self) {
|
||||||
|
let top = self.get_top();
|
||||||
|
println!("\n=== STACK DUMP ===");
|
||||||
|
println!("Stack size: {}", top);
|
||||||
|
for i in 1..=top {
|
||||||
|
let lua_type = self.lua_type(i);
|
||||||
|
let lua_type_name = self.lua_type_name(lua_type);
|
||||||
|
match lua_type_name.as_ref() {
|
||||||
|
"string" => println!("{}. {}: {:?}", i, lua_type_name, {
|
||||||
|
self.push_value(i);
|
||||||
|
let str = self.get_string(-1);
|
||||||
|
self.pop();
|
||||||
|
str
|
||||||
|
}),
|
||||||
|
_ => println!("{}. {}", i, lua_type_name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
pub unsafe fn dump_val(&self, index: i32) -> String {
|
||||||
|
let lua_type_name = self.lua_type_name(self.lua_type(index));
|
||||||
|
match lua_type_name.as_ref() {
|
||||||
|
"string" => {
|
||||||
|
self.push_value(index);
|
||||||
|
let str = self.get_string(-1);
|
||||||
|
self.pop();
|
||||||
|
format!("{:?}", str.unwrap().into_owned())
|
||||||
|
},
|
||||||
|
"boolean" => {
|
||||||
|
self.push_value(index);
|
||||||
|
let boolean = self.get_boolean(index);
|
||||||
|
self.pop();
|
||||||
|
format!("{}", boolean)
|
||||||
|
},
|
||||||
|
"number" => {
|
||||||
|
self.push_value(index);
|
||||||
|
let n = self.to_number(index);
|
||||||
|
self.pop();
|
||||||
|
format!("{}", n)
|
||||||
|
},
|
||||||
|
_ => lua_type_name.into_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::Deref for LuaState {
|
||||||
|
type Target = *mut std::ffi::c_void;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct LuaDebug {
|
||||||
|
pub event: i32,
|
||||||
|
pub name: LuaString,
|
||||||
|
pub namewhat: LuaString,
|
||||||
|
pub what: LuaString,
|
||||||
|
pub source: LuaString,
|
||||||
|
pub currentline: i32,
|
||||||
|
pub nups: i32,
|
||||||
|
pub linedefined: i32,
|
||||||
|
pub lastlinedefined: i32,
|
||||||
|
pub short_src: [std::os::raw::c_char; LUA_IDSIZE],
|
||||||
|
i_ci: i32
|
||||||
|
}
|
||||||
|
impl std::fmt::Debug for LuaDebug {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
unsafe {
|
||||||
|
f.debug_struct("LuaDebug")
|
||||||
|
.field("event", &self.event)
|
||||||
|
.field("name", &std::ffi::CStr::from_ptr(self.name))
|
||||||
|
.field("namewhat", &std::ffi::CStr::from_ptr(self.namewhat))
|
||||||
|
.field("what", &std::ffi::CStr::from_ptr(self.what))
|
||||||
|
.field("source", &std::ffi::CStr::from_ptr(self.source))
|
||||||
|
.field("currentline", &self.currentline)
|
||||||
|
.field("nups", &self.nups)
|
||||||
|
.field("linedefined", &self.linedefined)
|
||||||
|
.field("lastlinedefined", &self.lastlinedefined)
|
||||||
|
.field("short_src", &std::ffi::CStr::from_ptr(self.short_src.as_ptr()))
|
||||||
|
.field("i_ci", &self.i_ci)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
#![allow(unused)]
|
||||||
|
|
||||||
|
mod import;
|
||||||
|
pub use import::*;
|
||||||
|
|
||||||
|
mod lua_state;
|
||||||
|
pub use lua_state::LuaState as State;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum LuaError {
|
||||||
|
/// Out of memory
|
||||||
|
///
|
||||||
|
/// `LUA_ERRMEM`
|
||||||
|
MemoryAllocationError,
|
||||||
|
|
||||||
|
/// A syntax error occurred in the passed Lua source code.
|
||||||
|
///
|
||||||
|
/// `LUA_ERRSYNTAX`
|
||||||
|
SyntaxError(Option<String>),
|
||||||
|
|
||||||
|
/// Lua failed to load the given file.
|
||||||
|
///
|
||||||
|
/// `LUA_ERRFILE`
|
||||||
|
FileError(Option<String>),
|
||||||
|
|
||||||
|
/// A runtime error occurred.
|
||||||
|
///
|
||||||
|
/// `LUA_ERRRUN`
|
||||||
|
RuntimeError(Option<String>),
|
||||||
|
|
||||||
|
/// An error occurred while running the error handler function.
|
||||||
|
///
|
||||||
|
/// `LUA_ERRERR`
|
||||||
|
ErrorHandlerError,
|
||||||
|
|
||||||
|
/// Unknown Lua error code
|
||||||
|
Unknown(i32),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts a string literal to a Lua-compatible NUL terminated string at compile time.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! lua_string {
|
||||||
|
( $str:literal ) => {
|
||||||
|
::gmod::cstr::cstr!($str).as_ptr()
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
#![allow(non_upper_case_globals)]
|
||||||
|
|
||||||
|
use std::os::raw::c_char;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn printf_escape<S: AsRef<str>>(str: S) -> String {
|
||||||
|
str.as_ref().replace('\\', "\\\\").replace('%', "%%")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Color {
|
||||||
|
r: u8,
|
||||||
|
g: u8,
|
||||||
|
b: u8,
|
||||||
|
a: u8
|
||||||
|
}
|
||||||
|
impl Color {
|
||||||
|
#[inline]
|
||||||
|
pub const fn new(r: u8, g: u8, b: u8) -> Color {
|
||||||
|
Color { r, g, b, a: 255 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static::lazy_static! {
|
||||||
|
pub static ref ConColorMsg: libloading::Symbol<'static, unsafe extern "C" fn(&Color, *const c_char, ...)> = unsafe {
|
||||||
|
#[cfg(all(target_os = "windows", target_pointer_width = "64"))]
|
||||||
|
let lib = libloading::Library::new("bin/win64/tier0.dll").expect("Failed to open tier0.dll");
|
||||||
|
|
||||||
|
#[cfg(all(target_os = "windows", target_pointer_width = "32"))]
|
||||||
|
let lib = libloading::Library::new("bin/tier0.dll").or_else(|_| libloading::Library::new("bin/win32/tier0.dll")).expect("Failed to open tier0.dll");
|
||||||
|
|
||||||
|
#[cfg(all(target_os = "linux", target_pointer_width = "64"))]
|
||||||
|
let lib = libloading::Library::new("bin/linux64/libtier0.so").expect("Failed to open libtier0.so");
|
||||||
|
|
||||||
|
#[cfg(all(target_os = "linux", target_pointer_width = "32"))]
|
||||||
|
let lib = libloading::Library::new("bin/libtier0_srv.so").or_else(|_| libloading::Library::new("bin/linux32/libtier0.so")).expect("Failed to open libtier0.so");
|
||||||
|
|
||||||
|
let lib = Box::leak(Box::new(lib));
|
||||||
|
{
|
||||||
|
#[cfg(all(target_os = "windows", target_pointer_width = "64"))] {
|
||||||
|
lib.get(b"?ConColorMsg@@YAXAEBVColor@@PEBDZZ\0")
|
||||||
|
}
|
||||||
|
#[cfg(all(target_os = "windows", target_pointer_width = "32"))] {
|
||||||
|
match lib.get(b"?ConColorMsg@@YAXABVColor@@PBDZZ\0") {
|
||||||
|
Ok(symbol) => Ok(symbol),
|
||||||
|
Err(_) => lib.get(b"?ConColorMsg@@YAXABVColor@@PBDZZ\0")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(all(target_os = "linux", target_pointer_width = "64"))] {
|
||||||
|
lib.get(b"_Z11ConColorMsgRK5ColorPKcz\0")
|
||||||
|
}
|
||||||
|
#[cfg(all(target_os = "linux", target_pointer_width = "32"))] {
|
||||||
|
match lib.get(b"_Z11ConColorMsgRK5ColorPKcz\0") {
|
||||||
|
Ok(symbol) => Ok(symbol),
|
||||||
|
Err(_) => lib.get(b"_Z11ConColorMsgRK5ColorPKcz\0")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.expect("Failed to get ConColorMsg")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! colormsg {
|
||||||
|
($($($arg:expr)+),+) => {
|
||||||
|
$(::gmod::msgc::colormsg!(@print $($arg)+));+
|
||||||
|
};
|
||||||
|
|
||||||
|
(@print [$r:literal, $g:literal, $b:literal] $fmt:literal % ($($arg:tt),+)) => {
|
||||||
|
::gmod::msgc::ConColorMsg(
|
||||||
|
&::gmod::msgc::Color::new($r, $g, $b),
|
||||||
|
::gmod::msgc::printf_escape(format!(concat!($fmt, '\0'), $($arg),+)).as_ptr() as *const _,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
(@print [$r:literal, $g:literal, $b:literal] $str:literal) => {
|
||||||
|
::gmod::msgc::ConColorMsg(
|
||||||
|
&::gmod::msgc::Color::new($r, $g, $b),
|
||||||
|
::gmod::msgc::printf_escape(concat!($str, '\0')).as_ptr() as *const _,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
[toolchain]
|
||||||
|
channel = "nightly"
|
Loading…
Reference in New Issue