rglua/util/
mod.rs

1#![allow(unused)]
2
3/// Creates *const i8 from a &str
4/// This either takes a literal and appends a null char (\0) to it.
5/// or if it is an expression, tries to make a CString from it.
6/// Will panic if passed an expression that a CString could not be created from.
7/// # Examples
8/// ```rust
9/// use rglua::prelude::*;
10/// let a = b"Hello world!".as_ptr() as *const i8;
11/// let b = cstr!("Hello world!");
12/// unsafe { assert_eq!(*a, *b) };
13///
14/// let c = "Hello world!";
15/// let d = cstr!(c); // Macro doesn't know this is a literal, so it will try to make a CString
16/// unsafe { assert_eq!(*b, *d.as_ptr()) };
17/// ```
18#[macro_export]
19macro_rules! cstr {
20	($rstring:literal) => {
21		concat!($rstring, "\0").as_ptr() as *const i8
22	};
23	($rstring:expr) => {
24		std::ffi::CString::new($rstring).expect("Couldn't make CString from rust string")
25	};
26}
27
28/// Tries to create a *const i8 from a &str
29/// This either takes a literal and appends a null char (\0) to it.
30/// or if it is a value, makes a cstring and returns the pointer to it.
31/// # Examples
32/// ```rust, should_panic
33/// use rglua::prelude::*;
34/// let a = b"Hello world!".as_ptr() as *const i8;
35/// let b = try_cstr!("Hello world!");
36/// unsafe { assert_eq!(*a, *b) } ;
37///
38/// let c = "Invalid! 👎 \0"; // Cannot have nulls inside of it.
39/// let d = try_cstr!(c).unwrap();
40/// ```
41#[macro_export]
42macro_rules! try_cstr {
43	($rstring:literal) => {
44		concat!($rstring, "\0").as_ptr() as *const i8
45	};
46	($rstring:expr) => {{
47		std::ffi::CString::new($rstring)
48	}};
49}
50
51/// Tries to convert a const char* to a &str
52/// Will panic if the const char* is not valid utf-8
53/// # Examples
54/// ```rust
55/// use rglua::prelude::*;
56/// let cstr = cstr!("Hello World");
57/// let rust_str = rstr!(cstr);
58/// assert_eq!(rust_str, "Hello World");
59/// ```
60#[macro_export]
61macro_rules! rstr {
62	($cstring:expr) => {{
63		#[allow(unused_unsafe)]
64		let cstr = unsafe { std::ffi::CStr::from_ptr($cstring) };
65		cstr.to_str().expect("Couldn't unwrap CString")
66	}};
67}
68
69#[macro_export]
70/// Tries to convert a const char* to an &str
71/// # Examples
72/// ```rust
73/// use rglua::prelude::*;
74/// let cstr = cstr!("Hello World");
75/// let rstr = try_rstr!(cstr);
76/// assert!(rstr.is_ok()); // Should be perfectly valid to convert to utf8
77/// ```
78macro_rules! try_rstr {
79	($cstring:expr) => {{
80		#[allow(unused_unsafe)]
81		let cstr = unsafe { std::ffi::CStr::from_ptr($cstring) };
82		cstr.to_str()
83	}};
84}
85
86#[allow(unused_macros)]
87#[macro_export]
88/// Like println!, however it prints to the gmod server's console.
89/// First arg is the lua state.
90/// Rest are varargs.
91/// Can be either a variable storing a str literal, or a referenced String / str variable
92/// # Examples
93/// ```rust
94/// use rglua::prelude::*;
95/// fn gmod13_open(l: LuaState) {
96///     let world = "world";
97///     printgm!(l, "Hello {}!", world);
98/// }
99/// ```
100macro_rules! printgm {
101	($state:expr, $($x:expr),*) => {
102		{
103			let printargs = format!( $($x,)* );
104			if let Ok(fmt) = std::ffi::CString::new(printargs) {
105				$crate::lua::lua_getglobal( $state, $crate::cstr!("print") );
106				$crate::lua::lua_pushstring( $state, fmt.as_ptr() );
107				$crate::lua::lua_call( $state, 1, 0 );
108			}
109		}
110	};
111}
112
113/// Creates an array of LuaRegs for you to be used with luaL_register
114/// # Examples
115/// Basic usage
116/// ```rust
117/// use rglua::prelude::*;
118/// extern "C" fn max(l: LuaState) -> i32 { 0 }
119/// extern "C" fn min(l: LuaState) -> i32 { 0 }
120/// let my_library = reg! [
121///     "max" => max,
122///     "min" => min
123/// ];
124/// assert_eq!(my_library.len(), 3); // 2 functions + 1 internal null terminator
125/// unsafe { assert_eq!(my_library[0].name, cstr!("max")) }; // Internally this is turned into &[ LuaReg { name: cstr!("max"), func: max }, ... ];
126/// ```
127/// Returns a &[crate::types::LuaReg]
128#[macro_export]
129macro_rules! reg {
130	( $( $name:expr => $func:expr ),* ) => {
131		&[ $( $crate::types::LuaReg { name: $crate::cstr!($name), func: Some($func) } ),*, $crate::types::LuaReg { name: std::ptr::null(), func: None } ]
132	};
133}
134
135// get_from_interface using literal c strings.
136#[cfg(feature = "interfaces")]
137fn get_from_interface(
138	iface: &str,
139	factory: crate::interface::CreateInterfaceFn
140) -> Result<*mut (), crate::interface::Error> {
141	let mut status = 0;
142
143	let iface = try_cstr!(iface)?;
144	let result = factory(iface.as_ptr(), &mut status);
145
146	if status == 0 && !result.is_null() {
147		Ok(result as *mut ())
148	} else {
149		Err(crate::interface::Error::FactoryNotFound(
150			iface.to_string_lossy().to_string()
151		))
152	}
153}
154
155/// Quickly retrieves access to a source engine interface for you.
156/// You can either use it through iface!(file, name, typename) or iface!(name).
157/// # Examples
158/// ```rust
159/// use rglua::prelude::*;
160/// use rglua::interface::{EngineClient, self};
161/// #[gmod_open]
162/// fn entry(l: LuaState) -> Result<i32, interface::Error>  {
163///     let engine: &mut EngineClient = iface!("engine", "VEngineClient015", EngineClient)?;
164///     println!("Am I in game? {}", engine.IsInGame());
165///     Ok(0)
166/// }
167/// ```
168/// ```rust
169/// use rglua::prelude::*;
170/// use rglua::interface;
171/// #[gmod_open]
172/// fn entry(l: LuaState) -> Result<i32, interface::Error>  {
173///    let engine: &mut interface::EngineClient = iface!(EngineClient)?;
174///    println!("Am I in game? {}", engine.IsInGame());
175///    Ok(0)
176/// }
177/// ```
178#[macro_export]
179macro_rules! iface {
180	( LuaShared ) => {
181		iface!("lua_shared", "LUASHARED003", $crate::interface::LuaShared)
182	};
183	( EngineClient ) => {
184		iface!(
185			"engine",
186			"VEngineClient015",
187			$crate::interface::EngineClient
188		)
189	};
190	( EngineServer ) => {
191		iface!(
192			"engine",
193			"VEngineServer021",
194			$crate::interface::EngineServer
195		)
196	};
197	( MdlCache ) => {
198		iface!("datacache", "MDLCache004", $crate::interface::MdlCache)
199	};
200	( MaterialSystem ) => {
201		iface!(
202			"materialsystem",
203			"VMaterialSystem080",
204			$crate::interface::MaterialSystem
205		)
206	};
207	( Panel ) => {
208		iface!("vgui2", "VGUI_Panel009", $crate::interface::Panel)
209	};
210	( ConVar ) => {
211		iface!("vstdlib", "VEngineCvar007", $crate::interface::ConVar)
212	};
213
214	( $name:literal, $iface:literal, $ty:ty ) => {{
215		// Would use map and flatten but flatten is unstable. =(
216		match unsafe { $crate::interface::get_interface_handle($name) } {
217			Ok(handle) => {
218				let mut status = 0;
219
220				// Don't need to try_cstr since this is a literal.
221				let result = handle(cstr!($iface), &mut status);
222
223				if status == 0 && !result.is_null() {
224					let ptr = result as *mut $ty;
225					unsafe { ptr.as_mut() }
226						.ok_or($crate::interface::Error::IFaceMut(String::from($iface)))
227				} else {
228					Err($crate::interface::Error::CreateInterface(
229						status,
230						String::from($iface),
231					))
232				}
233			}
234			Err(why) => Err($crate::interface::Error::Libloading(why)),
235		}
236	}};
237}
238
239use crate::types::LuaState;
240/// Returns the current state of the lua stack without affecting it.
241/// Comes out in this format:
242/// ```text
243/// [1] 'number' = 5000
244/// [2] 'string' = "hello"
245/// [3] 'table' = 0x213542
246/// [4] 'function' = 0x138252
247/// [5] 'nil' = nil
248/// ```
249pub fn dump_stack(l: LuaState) -> Result<String, std::fmt::Error> {
250	use std::fmt::Write;
251
252	use crate::lua::*;
253
254	let mut buf = String::new();
255
256	let top = lua_gettop(l);
257	for i in 1..=top {
258		write!(&mut buf, "[{}] '{}' = ", i, rstr!(luaL_typename(l, i)));
259		match lua_type(l, i) {
260			TNUMBER => write!(&mut buf, "{}", lua_tonumber(l, i)),
261			TSTRING => write!(&mut buf, "{}", rstr!(lua_tostring(l, i))),
262			TBOOLEAN => write!(
263				&mut buf,
264				"{}",
265				if lua_toboolean(l, i) == 1 {
266					"true"
267				} else {
268					"false"
269				}
270			),
271			TNIL => write!(&mut buf, "nil"),
272			TNONE => write!(&mut buf, "none"),
273			TUSERDATA | TLIGHTUSERDATA => write!(&mut buf, "{:p}", lua_touserdata(l, i)),
274			TTHREAD => write!(&mut buf, "{:p}", lua_tothread(l, i)),
275			_ => write!(&mut buf, "Unknown type")
276		}?
277	}
278
279	Ok(buf)
280}