Skip to content
This repository was archived by the owner on Nov 12, 2025. It is now read-only.

Commit bd5c02b

Browse files
committed
Add docs for everything, Make cstr, try_cstr properly return CString instead of dangling ptr
Wanted to make an elegant solution that would somehow make the pointer keep the value allocated, but I don't know enough about the standard library on how to do that. (I could std::mem::forget but that would just be awful) Added docs for interfaces, lua_shared functions, types, global constants. Includes more example code.
1 parent 4c76f24 commit bd5c02b

File tree

7 files changed

+129
-19
lines changed

7 files changed

+129
-19
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "rglua"
33
description = "Rust tooling for garrysmod development with the LuaJIT api"
4-
version = "0.7.0"
4+
version = "0.7.1"
55
authors = ["Vurv <[email protected]>"]
66
keywords = ["glua", "garrysmod", "lua", "gmod"]
77
readme = "README.md"

src/globals.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,15 @@ use crate::types::*;
33
pub mod Lua {
44
use super::c_int;
55

6+
/// Index of the lua registry. What you'd get from debug.getregistry()
67
pub static REGISTRYINDEX: c_int = -10000;
8+
/// Index of the lua environment.
9+
/// This is like getfenv() or _ENV in later lua versions
710
pub static ENVIRONINDEX: c_int = -10001;
11+
/// Index of _G
812
pub static GLOBALSINDEX: c_int = -10002;
913

14+
/// Number of returns to use in functions like lua_pcall to represent 0 or more.
1015
pub static MULTRET: c_int = -1;
1116

1217
pub static NUMTYPES: c_int = 9;

src/interface/mod.rs

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,25 @@ pub use lua::{ILuaInterface, CLuaShared};
1515
pub use panel::{IPanel};
1616

1717
use crate::try_cstr;
18-
use std::ffi::{c_void, CString};
18+
use std::ffi::c_void;
1919
use libloading::{Library, Symbol};
2020

2121
pub type CreateInterfaceFn = extern "system" fn(pName: *const i8, pReturnCode: *mut i32) -> *mut c_void;
2222

23-
/// # Safety
24-
/// This function is unsafe to transmute the internal libloading symbol to a proper createinterface function pointer.
23+
/// Gets a handle to provided source interface
24+
/// # Arguments
25+
/// * `file` - Filename of the interface dll, linked to gmod. For example "engine.dll"
26+
/// # Safety
27+
/// This function internally gets the symbol to the CreateInterface function and casts it to the desired interface provided
28+
/// So make sure you pass the correct interface type and a valid dll.
29+
/// # Examples
30+
/// ```rust, no_run
31+
/// use rglua::interface::get_interface_handle;
32+
/// unsafe {
33+
/// let vgui = get_interface_handle("vgui2.dll")
34+
/// .expect("Couldn't link to vgui2.dll");
35+
/// };
36+
/// ```
2537
pub unsafe fn get_interface_handle(file: &str) -> Result<CreateInterfaceFn, libloading::Error> {
2638
let lib = Library::new(file)?;
2739
let sym: Symbol<CreateInterfaceFn> = lib.get(b"CreateInterface\0")?;
@@ -39,6 +51,37 @@ pub enum InterfaceError {
3951
FactoryNotFound,
4052
}
4153

54+
/// Tries to get source interface from given interface name, and handle to it acquired from [get_interface_handle]
55+
/// # Arguments
56+
/// * `iface` - name of the interface to get, for example "VGUI_Panel009"
57+
/// * `factory` - handle to the interface, acquired from [get_interface_handle]
58+
/// # Examples
59+
/// Getting the raw PaintTraverse function from vgui:
60+
/// ```no_run
61+
/// // Wrappers to these interfaces are already provided but they do not give raw function pointers which is needed to detour / modify the functions
62+
/// // in any way, which you may want to do here, especially for painttraverse since you can safely run lua here if you queue it from a thread to avoid crashes.
63+
/// use rglua::interface::{get_interface_handle, get_from_interface, IPanel};
64+
/// type PaintTraverseFn = extern "fastcall" fn(&'static IPanel, usize, bool, bool);
65+
/// let handle = unsafe { get_interface_handle("vgui2.dll").unwrap() };
66+
///
67+
/// let vgui_interface = get_from_interface("VGUI_Panel009", handle)
68+
/// .unwrap() as *mut IPanel;
69+
///
70+
/// unsafe {
71+
/// // Use as_ref to access fields of the interface
72+
/// let panel_iface = vgui_interface
73+
/// .as_ref() // Unsafe as Rust doesn't know whether the interface is really valid or not
74+
/// .unwrap();
75+
///
76+
///
77+
/// // Transmute the function address from the offset into our known signature
78+
/// let paint_traverse: PaintTraverseFn = std::mem::transmute(
79+
/// (panel_iface.vtable as *mut *mut std::ffi::c_void)
80+
/// .offset(41) // vtable offset as seen in [interface/panel.rs]
81+
/// .read()
82+
/// );
83+
/// }
84+
/// ```
4285
pub fn get_from_interface(
4386
iface: &str,
4487
factory: CreateInterfaceFn,
@@ -47,7 +90,7 @@ pub fn get_from_interface(
4790

4891
let iface = try_cstr!(iface)?;
4992

50-
let result = factory(iface, &mut status);
93+
let result = factory(iface.as_ptr(), &mut status);
5194

5295
if status == 0 && !result.is_null() {
5396
Ok(result as *mut ())

src/interface/panel.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,7 @@ impl IPanel {
1111
pub fn GetName(&self, vguiPanel: u32) -> *const i8 {}
1212

1313
#[virtual_index(41)]
14+
/// PaintTraverse function, notorious for getting you banned from every other source engine game.
15+
/// Lua runs properly here, so maybe you'd want to detour this.
1416
pub fn PaintTraverse(&self, vguiPanel: u32, forceRepaint: bool, allowForce: bool) {}
1517
}

src/lua_shared/raw.rs

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ macro_rules! dyn_symbols {
1111
$(#[$outer:meta])*
1212
$vis:vis extern $abi:literal fn $name:ident ( $($arg:ident : $argty:ty),* $(,)? ) -> $ret:ty; $($rest:tt)*
1313
) => {
14+
$(#[$outer])*
1415
pub static $name: Lazy<extern $abi fn( $($arg: $argty),* ) -> $ret> = Lazy::new(|| unsafe {
1516
std::mem::transmute( LUA_SHARED_RAW.get::<extern $abi fn($($argty),*) -> $ret>( stringify!($name).as_bytes() ).unwrap() )
1617
});
@@ -26,6 +27,7 @@ macro_rules! lua_macros {
2627
$vis:vis fn $name:ident ( $($arg:ident : $argty:ty),* $(,)? ) -> $ret:ty $body:block; $($rest:tt)*
2728
) => {
2829
#[inline(always)]
30+
$(#[$outer])*
2931
$vis fn $name( $($arg: $argty),* ) -> $ret $body
3032
lua_macros!( $($rest)* );
3133
};
@@ -35,8 +37,6 @@ macro_rules! lua_macros {
3537

3638
// Create Lazy cells that'll find the functions at runtime when called.
3739
dyn_symbols! {
38-
pub extern "system" fn CreateInterface(pName: LuaString, pReturnCode: *mut c_int) -> *mut c_void;
39-
4040
pub extern "C" fn luaL_loadbufferx(
4141
L: LuaState,
4242
code: LuaString,
@@ -110,7 +110,10 @@ dyn_symbols! {
110110
pub extern "C" fn lua_pushinteger(L: LuaState, n: LuaInteger) -> ();
111111

112112
// Type checking getters
113+
/// Same as luaL_checknumber, but casts it to an integer.
113114
pub extern "C" fn luaL_checkinteger(L: LuaState, narg: c_int) -> LuaInteger;
115+
/// Checks whether the value at stack index 'narg' is a number and returns this number.
116+
/// If it is not a lua number, will throw an error to Lua.
114117
pub extern "C" fn luaL_checknumber(L: LuaState, narg: c_int) -> LuaNumber;
115118
pub extern "C" fn luaL_checklstring(L: LuaState, narg: c_int, len: SizeT) -> LuaString;
116119

@@ -125,7 +128,9 @@ dyn_symbols! {
125128
pub extern "C" fn lua_createtable(L: LuaState, narr: c_int, nrec: c_int) -> ();
126129

127130
// Destruction
128-
pub extern "C" fn lua_close(L: LuaState) -> (); // Destroys the lua state
131+
/// Destroys the given lua state.
132+
/// You *probably* don't want to do this, unless you just want to self destruct the server / your client.
133+
pub extern "C" fn lua_close(L: LuaState) -> ();
129134

130135
// JIT
131136
// Returns 1 for success, 0 for failure
@@ -148,6 +153,8 @@ dyn_symbols! {
148153
// Coroutines
149154
pub extern "C" fn lua_yield(L: LuaState, nresults: c_int) -> c_int;
150155
pub extern "C" fn lua_status(L: LuaState) -> c_int;
156+
/// Starts and resumes a coroutine in a given thread.
157+
/// Blame garry for the _real
151158
pub extern "C" fn lua_resume_real(L: LuaState, narg: c_int) -> c_int;
152159

153160
// Comparison
@@ -161,22 +168,32 @@ dyn_symbols! {
161168
pub extern "C" fn lua_error(L: LuaState) -> c_int;
162169

163170
// Libraries
171+
/// Opens the standard 'table' library for a lua state
164172
pub extern "C" fn luaopen_table(L: LuaState) -> c_int;
173+
/// Opens the standard 'string' library for a lua state
165174
pub extern "C" fn luaopen_string(L: LuaState) -> c_int;
175+
/// Opens the standard 'package' library for a lua state
166176
pub extern "C" fn luaopen_package(L: LuaState) -> c_int;
177+
/// Opens the standard 'os' library for a lua state
167178
pub extern "C" fn luaopen_os(L: LuaState) -> c_int;
179+
/// Opens the standard 'table' library for a lua state
168180
pub extern "C" fn luaopen_math(L: LuaState) -> c_int;
181+
/// Opens the standard 'table' library for a lua state
169182
pub extern "C" fn luaopen_jit(L: LuaState) -> c_int;
183+
/// Opens the standard 'table' library for a lua state
170184
pub extern "C" fn luaopen_debug(L: LuaState) -> c_int;
185+
/// Opens the standard 'table' library for a lua state
171186
pub extern "C" fn luaopen_bit(L: LuaState) -> c_int;
187+
/// Opens the standard 'table' library for a lua state
172188
pub extern "C" fn luaopen_base(L: LuaState) -> c_int;
189+
/// Opens the standard 'table' library for a lua state
173190
pub extern "C" fn luaL_openlibs(L: LuaState) -> ();
191+
/// Internally called by luaL_register, opens given list of LuaRegs with number of functions provided explicitly
174192
pub extern "C" fn luaL_openlib(L: LuaState, libname: LuaString, l: *const LuaReg, nup: c_int) -> ();
175193

176-
/// luaL_register
177194
/// When called with libname as nullptr, it simply registers all functions in the list l reg! into the table on the top of the stack.
178195
/// # Example
179-
/// ```rust
196+
/// ```rust, ignore
180197
/// let lib = reg! [
181198
/// "my_function" => my_function,
182199
/// "my_other_function" => my_other_function,
@@ -226,6 +243,7 @@ dyn_symbols! {
226243
) -> LuaString;
227244

228245
pub extern "C" fn lua_checkstack(L: LuaState, extra: c_int) -> c_int;
246+
/// Sets the error handler for the lua state.
229247
pub extern "C" fn lua_atpanic(L: LuaState, panicf: LuaCFunction) -> LuaCFunction;
230248
pub extern "C" fn lua_gettop(L: LuaState) -> c_int;
231249
pub extern "C" fn lua_remove(L: LuaState, index: c_int) -> ();
@@ -235,39 +253,51 @@ dyn_symbols! {
235253
pub extern "C" fn luaL_prepbuffer(b: *mut LuaBuffer) -> *mut i8;
236254

237255
// String methods
256+
/// Creates a copy of string 's' by replacing any occurrence of the string 'p' with the string 'r'
257+
/// Pushes the resulting string on the stack and returns it
238258
pub extern "C" fn luaL_gsub(s: LuaString, pattern: LuaString, replace: LuaString) -> LuaString;
239259
}
240260

241261
// Inline functions to mirror the C macros that come with the lua api
242262
lua_macros! {
263+
/// Pops n elements from the lua stack.
243264
pub fn lua_pop(L: LuaState, ind: c_int) -> () {
244265
lua_settop(L, -(ind) - 1);
245266
};
246267

268+
/// Gets a value from _G
269+
/// Internally calls lua_getfield with [crate::globals::Lua::GLOBALSINDEX]
247270
pub fn lua_getglobal(L: LuaState, name: LuaString) -> () {
248271
lua_getfield(L, GLOBALSINDEX, name);
249272
};
250273

274+
/// Sets a value in _G
275+
/// Internally calls lua_setfield with [crate::globals::Lua::GLOBALSINDEX]
251276
pub fn lua_setglobal(L: LuaState, name: LuaString) -> () {
252277
lua_setfield(L, GLOBALSINDEX, name);
253278
};
254279

280+
/// Pushes a "C" function to the stack
255281
pub fn lua_pushcfunction(L: LuaState, fnc: LuaCFunction) -> () {
256282
lua_pushcclosure(L, fnc, 0);
257283
};
258284

285+
/// Equivalent to lua_tolstring with len equal to 0
259286
pub fn lua_tostring(L: LuaState, idx: c_int) -> LuaString {
260287
lua_tolstring(L, idx, 0)
261288
};
262289

290+
/// Starts and resumes a coroutine in a given thread
263291
pub fn lua_resume(L: LuaState, narg: c_int) -> c_int {
264292
lua_resume_real(L, narg)
265293
};
266294

295+
/// Returns if the value at the given index is a C or Lua function.
267296
pub fn lua_isfunction(L: LuaState, n: c_int) -> bool {
268297
lua_type(L, n) == Lua::Type::Function
269298
};
270299

300+
/// Returns if the value at the given index is a table.
271301
pub fn lua_istable(L: LuaState, n: c_int) -> bool {
272302
lua_type(L, n) == Lua::Type::Table
273303
};
@@ -276,44 +306,59 @@ lua_macros! {
276306
lua_type(L, n) == Lua::Type::LUserData
277307
};
278308

309+
/// Returns if the value at the given index is nil.
310+
/// You might want to use [lua_isnoneornil] instead.
279311
pub fn lua_isnil(L: LuaState, n: c_int) -> bool {
280312
lua_type(L, n) == Lua::Type::Nil
281313
};
282314

315+
/// Returns if the value at the given index is a boolean.
283316
pub fn lua_isboolean(L: LuaState, n: c_int) -> bool {
284317
lua_type(L, n) == Lua::Type::Bool
285318
};
286319

320+
/// Returns if the value at the given index is a thread.
287321
pub fn lua_isthread(L: LuaState, n: c_int) -> bool {
288322
lua_type(L, n) == Lua::Type::Thread
289323
};
290324

325+
/// Returns if the value at the given index is none (element outside of stack / invalid)
291326
pub fn lua_isnone(L: LuaState, n: c_int) -> bool {
292327
lua_type(L, n) == Lua::Type::None
293328
};
294329

330+
/// Returns if the value at the given index is none (invalid) or nil.
295331
pub fn lua_isnoneornil(L: LuaState, n: c_int) -> bool {
296332
lua_type(L, n) <= 0
297333
};
298334

335+
/// Loads and pcalls a string of lua code
336+
/// Returns if the code was successfully executed
337+
/// Error will be left on the stack if the code failed to execute
299338
pub fn luaL_dostring(L: LuaState, str: LuaString) -> bool {
300339
luaL_loadstring(L, str) == 0 || lua_pcall(L, 0, Lua::MULTRET, 0) == 0
301340
};
302341

342+
/// Loads and pcalls a file's lua code
343+
/// Returns if the code was successfully executed
344+
/// Error will be left on the stack if the code failed to execute
303345
pub fn luaL_dofile(L: LuaState, filename: LuaString) -> bool {
304346
luaL_loadfile(L, filename) == 0 || lua_pcall(L, 0, Lua::MULTRET, 0) == 0
305347
};
306348

349+
/// Returns value at [crate::globals::Lua::REGISTRYINDEX] with name 'name'
307350
pub fn luaL_getmetatable(L: LuaState, name: LuaString) -> () {
308351
lua_getfield(L, Lua::REGISTRYINDEX, name);
309352
};
310353

354+
/// If a condition is false, throws an argument error at numarg
311355
pub fn luaL_argcheck(L: LuaState, cond: bool, numarg: c_int, extramsg: LuaString) -> () {
312356
if !cond {
313357
luaL_argerror(L, numarg, extramsg);
314358
}
315359
};
316360

361+
/// Returns the type name of object at index i
317362
pub fn luaL_typename(L: LuaState, i: c_int) -> LuaString {
318363
lua_typename(L, lua_type(L, i))
319364
};

src/types.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,20 @@ pub type LuaString = *const ffi::c_char; // const i8
66
pub type SizeT = usize;
77

88
// Lua Types below
9-
pub type LuaNumber = f64; // All lua numbers are doubles in Lua 5.1 (Glua)
9+
10+
/// All lua numbers < Lua 5.3 are doubles (float 64). GLua is no different as it runs on LuaJIT which mimics 5.1
11+
pub type LuaNumber = f64;
1012
pub type LuaInteger = isize;
1113

14+
/// This is not an actual lua state, in fact it's just a pointer to it.
15+
/// However you will never have ownership of a lua state here, so I opted to make the type follow suit.
1216
pub type LuaState = *mut c_void; // Raw Lua state.
17+
18+
/// Lua "C" Functions are C ABI functions that return the number returns that will be passed to the Lua stack.
1319
pub type LuaCFunction = extern "C" fn(LuaState) -> c_int;
1420

21+
/// luaL_Reg type, used for defining large amounts of functions with names to be -
22+
/// registered into lua with luaL_register / openlibs.
1523
#[repr(C)]
1624
pub struct LuaReg {
1725
pub name: *const i8, // c_schar

0 commit comments

Comments
 (0)