Add `Function::info()` to get information about functions.
Closes #149 and #7.
This commit is contained in:
parent
790df77965
commit
5133a9837a
|
@ -1,10 +1,13 @@
|
||||||
|
use std::mem;
|
||||||
use std::os::raw::c_int;
|
use std::os::raw::c_int;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
use crate::error::{Error, Result};
|
use crate::error::{Error, Result};
|
||||||
use crate::ffi;
|
use crate::ffi;
|
||||||
use crate::types::LuaRef;
|
use crate::types::LuaRef;
|
||||||
use crate::util::{assert_stack, check_stack, error_traceback, pop_error, StackGuard};
|
use crate::util::{
|
||||||
|
assert_stack, check_stack, error_traceback, pop_error, ptr_to_cstr_bytes, StackGuard,
|
||||||
|
};
|
||||||
use crate::value::{FromLuaMulti, ToLuaMulti};
|
use crate::value::{FromLuaMulti, ToLuaMulti};
|
||||||
|
|
||||||
#[cfg(feature = "async")]
|
#[cfg(feature = "async")]
|
||||||
|
@ -14,6 +17,18 @@ use {futures_core::future::LocalBoxFuture, futures_util::future};
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Function<'lua>(pub(crate) LuaRef<'lua>);
|
pub struct Function<'lua>(pub(crate) LuaRef<'lua>);
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct FunctionInfo {
|
||||||
|
pub name: Option<Vec<u8>>,
|
||||||
|
pub name_what: Option<Vec<u8>>,
|
||||||
|
pub what: Option<Vec<u8>>,
|
||||||
|
pub source: Option<Vec<u8>>,
|
||||||
|
pub short_src: Option<Vec<u8>>,
|
||||||
|
pub line_defined: i32,
|
||||||
|
#[cfg(not(feature = "luau"))]
|
||||||
|
pub last_line_defined: i32,
|
||||||
|
}
|
||||||
|
|
||||||
impl<'lua> Function<'lua> {
|
impl<'lua> Function<'lua> {
|
||||||
/// Calls the function, passing `args` as function arguments.
|
/// Calls the function, passing `args` as function arguments.
|
||||||
///
|
///
|
||||||
|
@ -209,6 +224,41 @@ impl<'lua> Function<'lua> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns information about the function.
|
||||||
|
///
|
||||||
|
/// Corresponds to the `>Sn` what mask for [`lua_getinfo`] when applied to the function.
|
||||||
|
///
|
||||||
|
/// [`lua_getinfo`]: https://www.lua.org/manual/5.4/manual.html#lua_getinfo
|
||||||
|
pub fn info(&self) -> FunctionInfo {
|
||||||
|
let lua = self.0.lua;
|
||||||
|
unsafe {
|
||||||
|
let _sg = StackGuard::new(lua.state);
|
||||||
|
assert_stack(lua.state, 1);
|
||||||
|
|
||||||
|
let mut ar: ffi::lua_Debug = mem::zeroed();
|
||||||
|
lua.push_ref(&self.0);
|
||||||
|
#[cfg(not(feature = "luau"))]
|
||||||
|
let res = ffi::lua_getinfo(lua.state, cstr!(">Sn"), &mut ar);
|
||||||
|
#[cfg(feature = "luau")]
|
||||||
|
let res = ffi::lua_getinfo(lua.state, -1, cstr!("sn"), &mut ar);
|
||||||
|
mlua_assert!(res != 0, "lua_getinfo failed with `>Sn`");
|
||||||
|
|
||||||
|
FunctionInfo {
|
||||||
|
name: ptr_to_cstr_bytes(ar.name).map(|s| s.to_vec()),
|
||||||
|
#[cfg(not(feature = "luau"))]
|
||||||
|
name_what: ptr_to_cstr_bytes(ar.namewhat).map(|s| s.to_vec()),
|
||||||
|
#[cfg(feature = "luau")]
|
||||||
|
name_what: None,
|
||||||
|
what: ptr_to_cstr_bytes(ar.what).map(|s| s.to_vec()),
|
||||||
|
source: ptr_to_cstr_bytes(ar.source).map(|s| s.to_vec()),
|
||||||
|
short_src: ptr_to_cstr_bytes(&ar.short_src as *const _).map(|s| s.to_vec()),
|
||||||
|
line_defined: ar.linedefined as i32,
|
||||||
|
#[cfg(not(feature = "luau"))]
|
||||||
|
last_line_defined: ar.lastlinedefined as i32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Dumps the function as a binary chunk.
|
/// Dumps the function as a binary chunk.
|
||||||
///
|
///
|
||||||
/// If `strip` is true, the binary representation may not include all debug information
|
/// If `strip` is true, the binary representation may not include all debug information
|
||||||
|
|
22
src/hook.rs
22
src/hook.rs
|
@ -1,11 +1,11 @@
|
||||||
use std::cell::UnsafeCell;
|
use std::cell::UnsafeCell;
|
||||||
use std::ffi::CStr;
|
|
||||||
#[cfg(not(feature = "luau"))]
|
#[cfg(not(feature = "luau"))]
|
||||||
use std::ops::{BitOr, BitOrAssign};
|
use std::ops::{BitOr, BitOrAssign};
|
||||||
use std::os::raw::{c_char, c_int};
|
use std::os::raw::c_int;
|
||||||
|
|
||||||
use crate::ffi::{self, lua_Debug};
|
use crate::ffi::{self, lua_Debug};
|
||||||
use crate::lua::Lua;
|
use crate::lua::Lua;
|
||||||
|
use crate::util::ptr_to_cstr_bytes;
|
||||||
|
|
||||||
/// Contains information about currently executing Lua code.
|
/// Contains information about currently executing Lua code.
|
||||||
///
|
///
|
||||||
|
@ -77,9 +77,9 @@ impl<'lua> Debug<'lua> {
|
||||||
);
|
);
|
||||||
|
|
||||||
DebugNames {
|
DebugNames {
|
||||||
name: ptr_to_str((*self.ar.get()).name),
|
name: ptr_to_cstr_bytes((*self.ar.get()).name),
|
||||||
#[cfg(not(feature = "luau"))]
|
#[cfg(not(feature = "luau"))]
|
||||||
name_what: ptr_to_str((*self.ar.get()).namewhat),
|
name_what: ptr_to_cstr_bytes((*self.ar.get()).namewhat),
|
||||||
#[cfg(feature = "luau")]
|
#[cfg(feature = "luau")]
|
||||||
name_what: None,
|
name_what: None,
|
||||||
}
|
}
|
||||||
|
@ -101,12 +101,12 @@ impl<'lua> Debug<'lua> {
|
||||||
);
|
);
|
||||||
|
|
||||||
DebugSource {
|
DebugSource {
|
||||||
source: ptr_to_str((*self.ar.get()).source),
|
source: ptr_to_cstr_bytes((*self.ar.get()).source),
|
||||||
short_src: ptr_to_str((*self.ar.get()).short_src.as_ptr()),
|
short_src: ptr_to_cstr_bytes((*self.ar.get()).short_src.as_ptr()),
|
||||||
line_defined: (*self.ar.get()).linedefined as i32,
|
line_defined: (*self.ar.get()).linedefined as i32,
|
||||||
#[cfg(not(feature = "luau"))]
|
#[cfg(not(feature = "luau"))]
|
||||||
last_line_defined: (*self.ar.get()).lastlinedefined as i32,
|
last_line_defined: (*self.ar.get()).lastlinedefined as i32,
|
||||||
what: ptr_to_str((*self.ar.get()).what),
|
what: ptr_to_cstr_bytes((*self.ar.get()).what),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -349,11 +349,3 @@ impl BitOrAssign for HookTriggers {
|
||||||
*self = *self | rhs;
|
*self = *self | rhs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn ptr_to_str<'a>(input: *const c_char) -> Option<&'a [u8]> {
|
|
||||||
if input.is_null() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(CStr::from_ptr(input).to_bytes())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -108,7 +108,7 @@ pub use crate::{ffi::lua_CFunction, ffi::lua_State};
|
||||||
|
|
||||||
pub use crate::chunk::{AsChunk, Chunk, ChunkMode};
|
pub use crate::chunk::{AsChunk, Chunk, ChunkMode};
|
||||||
pub use crate::error::{Error, ExternalError, ExternalResult, Result};
|
pub use crate::error::{Error, ExternalError, ExternalResult, Result};
|
||||||
pub use crate::function::Function;
|
pub use crate::function::{Function, FunctionInfo};
|
||||||
pub use crate::hook::{Debug, DebugEvent, DebugNames, DebugSource, DebugStack};
|
pub use crate::hook::{Debug, DebugEvent, DebugNames, DebugSource, DebugStack};
|
||||||
pub use crate::lua::{GCMode, Lua, LuaOptions};
|
pub use crate::lua::{GCMode, Lua, LuaOptions};
|
||||||
pub use crate::multi::Variadic;
|
pub use crate::multi::Variadic;
|
||||||
|
|
|
@ -4,13 +4,13 @@
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
AnyUserData as LuaAnyUserData, Chunk as LuaChunk, Error as LuaError,
|
AnyUserData as LuaAnyUserData, Chunk as LuaChunk, Error as LuaError,
|
||||||
ExternalError as LuaExternalError, ExternalResult as LuaExternalResult, FromLua, FromLuaMulti,
|
ExternalError as LuaExternalError, ExternalResult as LuaExternalResult, FromLua, FromLuaMulti,
|
||||||
Function as LuaFunction, GCMode as LuaGCMode, Integer as LuaInteger,
|
Function as LuaFunction, FunctionInfo as LuaFunctionInfo, GCMode as LuaGCMode,
|
||||||
LightUserData as LuaLightUserData, Lua, LuaOptions, MetaMethod as LuaMetaMethod,
|
Integer as LuaInteger, LightUserData as LuaLightUserData, Lua, LuaOptions,
|
||||||
MultiValue as LuaMultiValue, Nil as LuaNil, Number as LuaNumber, RegistryKey as LuaRegistryKey,
|
MetaMethod as LuaMetaMethod, MultiValue as LuaMultiValue, Nil as LuaNil, Number as LuaNumber,
|
||||||
Result as LuaResult, StdLib as LuaStdLib, String as LuaString, Table as LuaTable,
|
RegistryKey as LuaRegistryKey, Result as LuaResult, StdLib as LuaStdLib, String as LuaString,
|
||||||
TableExt as LuaTableExt, TablePairs as LuaTablePairs, TableSequence as LuaTableSequence,
|
Table as LuaTable, TableExt as LuaTableExt, TablePairs as LuaTablePairs,
|
||||||
Thread as LuaThread, ThreadStatus as LuaThreadStatus, ToLua, ToLuaMulti,
|
TableSequence as LuaTableSequence, Thread as LuaThread, ThreadStatus as LuaThreadStatus, ToLua,
|
||||||
UserData as LuaUserData, UserDataFields as LuaUserDataFields,
|
ToLuaMulti, UserData as LuaUserData, UserDataFields as LuaUserDataFields,
|
||||||
UserDataMetatable as LuaUserDataMetatable, UserDataMethods as LuaUserDataMethods,
|
UserDataMetatable as LuaUserDataMetatable, UserDataMethods as LuaUserDataMethods,
|
||||||
Value as LuaValue,
|
Value as LuaValue,
|
||||||
};
|
};
|
||||||
|
|
|
@ -992,6 +992,13 @@ pub(crate) unsafe fn get_destructed_userdata_metatable(state: *mut ffi::lua_Stat
|
||||||
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, key);
|
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn ptr_to_cstr_bytes<'a>(input: *const c_char) -> Option<&'a [u8]> {
|
||||||
|
if input.is_null() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(CStr::from_ptr(input).to_bytes())
|
||||||
|
}
|
||||||
|
|
||||||
static DESTRUCTED_USERDATA_METATABLE: u8 = 0;
|
static DESTRUCTED_USERDATA_METATABLE: u8 = 0;
|
||||||
static ERROR_PRINT_BUFFER_KEY: u8 = 0;
|
static ERROR_PRINT_BUFFER_KEY: u8 = 0;
|
||||||
static USERDATA_METATABLE_INDEX: u8 = 0;
|
static USERDATA_METATABLE_INDEX: u8 = 0;
|
||||||
|
|
|
@ -107,3 +107,57 @@ fn test_dump() -> Result<()> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_function_info() -> Result<()> {
|
||||||
|
let lua = Lua::new();
|
||||||
|
|
||||||
|
let globals = lua.globals();
|
||||||
|
lua.load(
|
||||||
|
r#"
|
||||||
|
function function1()
|
||||||
|
return function() end
|
||||||
|
end
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.set_name("source1")?
|
||||||
|
.exec()?;
|
||||||
|
|
||||||
|
let function1 = globals.get::<_, Function>("function1")?;
|
||||||
|
let function2 = function1.call::<_, Function>(())?;
|
||||||
|
let function3 = lua.create_function(|_, ()| Ok(()))?;
|
||||||
|
|
||||||
|
let function1_info = function1.info();
|
||||||
|
#[cfg(feature = "luau")]
|
||||||
|
assert_eq!(function1_info.name, Some(b"function1".to_vec()));
|
||||||
|
assert_eq!(function1_info.source, Some(b"source1".to_vec()));
|
||||||
|
assert_eq!(function1_info.line_defined, 2);
|
||||||
|
#[cfg(not(feature = "luau"))]
|
||||||
|
assert_eq!(function1_info.last_line_defined, 4);
|
||||||
|
assert_eq!(function1_info.what, Some(b"Lua".to_vec()));
|
||||||
|
|
||||||
|
let function2_info = function2.info();
|
||||||
|
assert_eq!(function2_info.name, None);
|
||||||
|
assert_eq!(function2_info.source, Some(b"source1".to_vec()));
|
||||||
|
assert_eq!(function2_info.line_defined, 3);
|
||||||
|
#[cfg(not(feature = "luau"))]
|
||||||
|
assert_eq!(function2_info.last_line_defined, 3);
|
||||||
|
assert_eq!(function2_info.what, Some(b"Lua".to_vec()));
|
||||||
|
|
||||||
|
let function3_info = function3.info();
|
||||||
|
assert_eq!(function3_info.name, None);
|
||||||
|
assert_eq!(function3_info.source, Some(b"=[C]".to_vec()));
|
||||||
|
assert_eq!(function3_info.line_defined, -1);
|
||||||
|
#[cfg(not(feature = "luau"))]
|
||||||
|
assert_eq!(function3_info.last_line_defined, -1);
|
||||||
|
assert_eq!(function3_info.what, Some(b"C".to_vec()));
|
||||||
|
|
||||||
|
let print_info = globals.get::<_, Function>("print")?.info();
|
||||||
|
#[cfg(feature = "luau")]
|
||||||
|
assert_eq!(print_info.name, Some(b"print".to_vec()));
|
||||||
|
assert_eq!(print_info.source, Some(b"=[C]".to_vec()));
|
||||||
|
assert_eq!(print_info.what, Some(b"C".to_vec()));
|
||||||
|
assert_eq!(print_info.line_defined, -1);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue