Turn more comments into doc comments, improve debuggability
This commit is contained in:
parent
58e5c7b18b
commit
061f84f702
|
@ -39,4 +39,5 @@ cfg-if = "1.0"
|
||||||
pkg-config = "0.3.17"
|
pkg-config = "0.3.17"
|
||||||
lua-src = { version = ">= 546.0.0, < 550.0.0", optional = true }
|
lua-src = { version = ">= 546.0.0, < 550.0.0", optional = true }
|
||||||
luajit-src = { version = ">= 210.4.0, < 220.0.0", optional = true }
|
luajit-src = { version = ">= 210.4.0, < 220.0.0", optional = true }
|
||||||
luau0-src = { version = "0.5.10", optional = true }
|
#luau0-src = { version = "0.5.10", optional = true }
|
||||||
|
luau0-src = { path = "../../luau-src-rs", optional = true }
|
||||||
|
|
|
@ -7,16 +7,16 @@
|
||||||
|
|
||||||
use std::os::raw::c_int;
|
use std::os::raw::c_int;
|
||||||
|
|
||||||
#[cfg(any(feature = "lua54", doc))]
|
#[cfg(any(feature = "lua54"))]
|
||||||
pub use lua54::*;
|
pub use lua54::*;
|
||||||
|
|
||||||
#[cfg(any(feature = "lua53", doc))]
|
#[cfg(any(feature = "lua53"))]
|
||||||
pub use lua53::*;
|
pub use lua53::*;
|
||||||
|
|
||||||
#[cfg(any(feature = "lua52", doc))]
|
#[cfg(any(feature = "lua52"))]
|
||||||
pub use lua52::*;
|
pub use lua52::*;
|
||||||
|
|
||||||
#[cfg(any(feature = "lua51", feature = "luajit", doc))]
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||||
pub use lua51::*;
|
pub use lua51::*;
|
||||||
|
|
||||||
#[cfg(any(feature = "luau", doc))]
|
#[cfg(any(feature = "luau", doc))]
|
||||||
|
|
|
@ -30,6 +30,9 @@ unsafe fn compat53_findfield(L: *mut lua_State, objidx: c_int, level: c_int) ->
|
||||||
if level == 0 || lua_istable(L, -1) == 0 {
|
if level == 0 || lua_istable(L, -1) == 0 {
|
||||||
return 0; // not found
|
return 0; // not found
|
||||||
}
|
}
|
||||||
|
if lua_checkstack(L, 3) == 0 {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
lua_pushnil(L); // start 'next' loop
|
lua_pushnil(L); // start 'next' loop
|
||||||
while lua_next(L, -2) != 0 {
|
while lua_next(L, -2) != 0 {
|
||||||
|
@ -42,9 +45,8 @@ unsafe fn compat53_findfield(L: *mut lua_State, objidx: c_int, level: c_int) ->
|
||||||
return 1;
|
return 1;
|
||||||
} else if compat53_findfield(L, objidx, level - 1) != 0 {
|
} else if compat53_findfield(L, objidx, level - 1) != 0 {
|
||||||
// try recursively
|
// try recursively
|
||||||
lua_remove(L, -2); // remove table (but keep name)
|
|
||||||
lua_pushliteral(L, ".");
|
lua_pushliteral(L, ".");
|
||||||
lua_insert(L, -2); // place '.' between the two names
|
lua_replace(L, -2); // remove table (but keep name), place '.' between the two names
|
||||||
lua_concat(L, 3);
|
lua_concat(L, 3);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -57,8 +59,9 @@ unsafe fn compat53_findfield(L: *mut lua_State, objidx: c_int, level: c_int) ->
|
||||||
unsafe fn compat53_pushglobalfuncname(
|
unsafe fn compat53_pushglobalfuncname(
|
||||||
L: *mut lua_State,
|
L: *mut lua_State,
|
||||||
level: c_int,
|
level: c_int,
|
||||||
ar: *mut lua_Debug,
|
ar: &mut lua_Debug,
|
||||||
) -> c_int {
|
) -> c_int {
|
||||||
|
debug_assert_ne!(lua_checkstack(L, 2), 0);
|
||||||
let top = lua_gettop(L);
|
let top = lua_gettop(L);
|
||||||
// push function
|
// push function
|
||||||
lua_getinfo(L, level, cstr!("f"), ar);
|
lua_getinfo(L, level, cstr!("f"), ar);
|
||||||
|
@ -73,10 +76,11 @@ unsafe fn compat53_pushglobalfuncname(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn compat53_pushfuncname(L: *mut lua_State, level: c_int, ar: *mut lua_Debug) {
|
unsafe fn compat53_pushfuncname(L: *mut lua_State, level: c_int, ar: &mut lua_Debug) {
|
||||||
if !(*ar).name.is_null() {
|
debug_assert_ne!(lua_checkstack(L, 1), 0);
|
||||||
|
if !ar.name.is_null() {
|
||||||
// is there a name?
|
// is there a name?
|
||||||
lua_pushfstring(L, cstr!("function '%s'"), (*ar).name);
|
lua_pushfstring(L, cstr!("function '%s'"), ar.name);
|
||||||
} else if compat53_pushglobalfuncname(L, level, ar) != 0 {
|
} else if compat53_pushglobalfuncname(L, level, ar) != 0 {
|
||||||
lua_pushfstring(L, cstr!("function '%s'"), lua_tostring(L, -1));
|
lua_pushfstring(L, cstr!("function '%s'"), lua_tostring(L, -1));
|
||||||
lua_remove(L, -2); // remove name
|
lua_remove(L, -2); // remove name
|
||||||
|
@ -85,6 +89,17 @@ unsafe fn compat53_pushfuncname(L: *mut lua_State, level: c_int, ar: *mut lua_De
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn compat53_pushfuncname_heap(_L: *mut lua_State, _level: c_int, ar: &mut lua_Debug, buf: &mut String) {
|
||||||
|
use std::fmt::Write;
|
||||||
|
|
||||||
|
if !ar.name.is_null() {
|
||||||
|
// is there a name?
|
||||||
|
_ = write!(buf, "function {:?}", CStr::from_ptr(ar.name));
|
||||||
|
} else {
|
||||||
|
buf.push('?');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// lua ported functions
|
// lua ported functions
|
||||||
//
|
//
|
||||||
|
@ -416,10 +431,22 @@ pub unsafe fn luaL_traceback(
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
debug_assert_ne!(lua_checkstack(L, 1), 0);
|
||||||
|
|
||||||
|
//let stack_req = if msg.is_null() { 0 } else { 1 } + 4 * (mark+1);
|
||||||
|
let stack_req = if msg.is_null() { 0 } else { 1 } + 4;
|
||||||
|
|
||||||
|
if lua_checkstack(L, stack_req) == 0 {
|
||||||
|
lua_pushliteral(L, "[not enough stack space]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if !msg.is_null() {
|
if !msg.is_null() {
|
||||||
lua_pushfstring(L, cstr!("%s\n"), msg);
|
lua_pushfstring(L, cstr!("%s\n"), msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
lua_pushliteral(L, "stack traceback:");
|
lua_pushliteral(L, "stack traceback:");
|
||||||
|
|
||||||
while lua_getinfo(L1, level, cstr!(""), &mut ar) != 0 {
|
while lua_getinfo(L1, level, cstr!(""), &mut ar) != 0 {
|
||||||
if level + 1 == mark {
|
if level + 1 == mark {
|
||||||
// too many levels?
|
// too many levels?
|
||||||
|
@ -440,6 +467,51 @@ pub unsafe fn luaL_traceback(
|
||||||
lua_concat(L, lua_gettop(L) - top);
|
lua_concat(L, lua_gettop(L) - top);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub unsafe fn luaL_traceback_heap(
|
||||||
|
L: *mut lua_State,
|
||||||
|
L1: *mut lua_State,
|
||||||
|
msg: Option<String>,
|
||||||
|
mut level: c_int,
|
||||||
|
) -> String {
|
||||||
|
use std::fmt::Write;
|
||||||
|
|
||||||
|
let mut ar: lua_Debug = mem::zeroed();
|
||||||
|
let numlevels = lua_stackdepth(L);
|
||||||
|
let mark = if numlevels > COMPAT53_LEVELS1 + COMPAT53_LEVELS2 {
|
||||||
|
COMPAT53_LEVELS1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut buf = msg.unwrap_or_default();
|
||||||
|
if !buf.is_empty() {
|
||||||
|
buf.push('\n');
|
||||||
|
}
|
||||||
|
buf.push_str("stack traceback:");
|
||||||
|
while lua_getinfo(L1, level, cstr!(""), &mut ar) != 0 {
|
||||||
|
if level + 1 == mark {
|
||||||
|
// too many levels?
|
||||||
|
buf.push_str("\n\t..."); // add a '...'
|
||||||
|
level = numlevels - COMPAT53_LEVELS2; // and skip to last ones
|
||||||
|
} else {
|
||||||
|
lua_getinfo(L1, level, cstr!("sln"), &mut ar);
|
||||||
|
let src = CStr::from_ptr(ar.short_src);
|
||||||
|
if let Ok(src) = src.to_str() {
|
||||||
|
_ = write!(buf, "\n\t{}:", src);
|
||||||
|
} else {
|
||||||
|
_ = write!(buf, "\n\t{:?}:", src);
|
||||||
|
}
|
||||||
|
if ar.currentline > 0 {
|
||||||
|
_ = write!(buf, "{}:", ar.currentline);
|
||||||
|
}
|
||||||
|
buf.push_str(" in ");
|
||||||
|
compat53_pushfuncname_heap(L, level, &mut ar, &mut buf);
|
||||||
|
}
|
||||||
|
level += 1;
|
||||||
|
}
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
|
||||||
pub unsafe fn luaL_tolstring(L: *mut lua_State, mut idx: c_int, len: *mut usize) -> *const c_char {
|
pub unsafe fn luaL_tolstring(L: *mut lua_State, mut idx: c_int, len: *mut usize) -> *const c_char {
|
||||||
idx = lua_absindex(L, idx);
|
idx = lua_absindex(L, idx);
|
||||||
if luaL_callmeta(L, idx, cstr!("__tostring")) == 0 {
|
if luaL_callmeta(L, idx, cstr!("__tostring")) == 0 {
|
||||||
|
@ -508,7 +580,7 @@ pub unsafe fn luaL_requiref(
|
||||||
luaL_getsubtable(L, LUA_REGISTRYINDEX, cstr!("_LOADED"));
|
luaL_getsubtable(L, LUA_REGISTRYINDEX, cstr!("_LOADED"));
|
||||||
if lua_getfield(L, -1, modname) == LUA_TNIL {
|
if lua_getfield(L, -1, modname) == LUA_TNIL {
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
lua_pushcfunction(L, openf);
|
lua_pushcfunction(L, openf, b"open\0".as_ptr().cast());
|
||||||
lua_pushstring(L, modname);
|
lua_pushstring(L, modname);
|
||||||
lua_call(L, 1, 1);
|
lua_call(L, 1, 1);
|
||||||
lua_pushvalue(L, -1);
|
lua_pushvalue(L, -1);
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
const MASK_WHITE0: u8 = 0b1;
|
||||||
|
const MASK_WHITE1: u8 = 0b10;
|
||||||
|
const MASK_WHITE: u8 = MASK_WHITE0 | MASK_WHITE1;
|
||||||
|
const MASK_BLACK: u8 = 0b100;
|
||||||
|
const MASK_FIXED: u8 = 0b1000;
|
||||||
|
|
||||||
|
/// Possible states of the Garbage Collector
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
#[repr(u8)]
|
||||||
|
enum GCState {
|
||||||
|
Pause = 0,
|
||||||
|
Propagate = 1,
|
||||||
|
PropagateAgain = 2,
|
||||||
|
Atomic = 3,
|
||||||
|
Sweep = 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn is_black(o: GCObjectPtr) -> bool {
|
||||||
|
(&*o.0).gch.marked & MASK_BLACK != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn is_white(o: GCObjectPtr) -> bool {
|
||||||
|
(&*o.0).gch.marked & MASK_WHITE != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/*#[inline(always)]
|
||||||
|
unsafe fn is_dead(g: *mut global_State, o: *mut GCObject) -> bool {
|
||||||
|
(&*o).gch.marked & (MASK_WHITE | MASK_FIXED) == otherwhite(g) & MASK_WHITE
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn otherwhite(g: *mut global_State) -> u8 {
|
||||||
|
(&*g).currentwhite ^ MASK_WHITE
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn black2gray(o: *mut GCObject) {
|
||||||
|
(&mut *o).gch.marked &= !MASK_BLACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn luaC_barrierback(L: *mut lua_State, o: *mut GCObject, gclist: *mut *mut GCObject) {
|
||||||
|
let g = (&*L).global;
|
||||||
|
debug_assert!(is_black(o) && !is_dead(g, o) != 0);
|
||||||
|
debug_assert_ne!(g.gcstate, GCState::Pause);
|
||||||
|
|
||||||
|
black2gray(o); // make object gray (again)
|
||||||
|
*gclist = (&*g).grayagain;
|
||||||
|
(&mut *g).grayagain = o;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
pub fn luaC_barrierback(L: *mut lua_State, o: GCObjectPtr, gclist: *mut *mut GCObject);
|
||||||
|
|
||||||
|
pub fn luaC_barriertable(L: *mut lua_State, t: *mut Table, v: GCObjectPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn luaC_threadbarrier(L: *mut lua_State) {
|
||||||
|
if is_black(L.into()) {
|
||||||
|
luaC_barrierback(L, L.into(), &mut (&mut *L).gc_list as *mut _);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn luaC_barriert(L: *mut lua_State, t: *mut Table, v: *mut TValue) {
|
||||||
|
if (*v).is_collectable() {
|
||||||
|
debug_assert_eq!((*v).tt, (*(*v).value.gc).gch.tt.into(), "types do not match");
|
||||||
|
let v = (*v).value.gc.into();
|
||||||
|
if is_black(v) && is_white(v) {
|
||||||
|
luaC_barriertable(L, t, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,263 @@
|
||||||
|
use std::ffi::{c_char, c_float, c_int, c_void};
|
||||||
|
use std::mem::ManuallyDrop;
|
||||||
|
use std::ptr::NonNull;
|
||||||
|
|
||||||
|
use crate::{lua_CFunction, lua_Continuation, lua_Integer, lua_Number, GCObject, LUA_TTABLE, LUA_TNIL, LUA_TNUMBER, LUA_TLIGHTUSERDATA, LUA_TSTRING};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "luau-vector4"))]
|
||||||
|
pub const LUA_VECTOR_SIZE: usize = 3;
|
||||||
|
#[cfg(feature = "luau-vector4")]
|
||||||
|
pub const LUA_VECTOR_SIZE: usize = 4;
|
||||||
|
|
||||||
|
pub const LUA_EXTRA_SIZE: usize = LUA_VECTOR_SIZE - 2;
|
||||||
|
|
||||||
|
opaque! {
|
||||||
|
pub type LuaNode;
|
||||||
|
|
||||||
|
pub type Proto;
|
||||||
|
|
||||||
|
pub type TString;
|
||||||
|
|
||||||
|
pub type Udata;
|
||||||
|
|
||||||
|
pub type UpVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type StkId = *mut TValue;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct GCheader {
|
||||||
|
pub tt: u8,
|
||||||
|
pub marked: u8,
|
||||||
|
pub memcat: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub union Value {
|
||||||
|
pub gc: *mut GCObject,
|
||||||
|
/// Light user data
|
||||||
|
pub p: *mut c_void,
|
||||||
|
/// Number
|
||||||
|
pub n: lua_Number,
|
||||||
|
pub b: c_int,
|
||||||
|
/// Vector
|
||||||
|
///
|
||||||
|
/// `v[0]`, `v[1]` live here; `v[2]`, possibly `v[3]` lives in TValue::extra
|
||||||
|
pub v: [c_float; 2],
|
||||||
|
bits: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for Value {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
write!(f, "{:b}", unsafe { self.bits })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct TValue {
|
||||||
|
pub value: Value,
|
||||||
|
pub extra: [c_int; LUA_EXTRA_SIZE],
|
||||||
|
pub tt: c_int,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TValue {
|
||||||
|
#[inline(always)]
|
||||||
|
fn check_type(&self, tt: c_int) {
|
||||||
|
debug_assert_eq!(self.tt, tt, "Wrong type");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn as_table(&self) -> *mut Table {
|
||||||
|
self.check_type(LUA_TTABLE);
|
||||||
|
unsafe { self.value.gc.cast() }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn as_light_user_data(&self) -> *mut c_void {
|
||||||
|
self.check_type(LUA_TLIGHTUSERDATA);
|
||||||
|
unsafe { self.value.p }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn as_number(&self) -> lua_Number {
|
||||||
|
self.check_type(LUA_TNUMBER);
|
||||||
|
unsafe { self.value.n }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The only check if for rounding error, not type.
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn try_as_integer(&self) -> Option<c_int> {
|
||||||
|
let n = self.as_number();
|
||||||
|
let n_int = n as lua_Integer;
|
||||||
|
if (n - n_int as lua_Number).abs() < lua_Number::EPSILON {
|
||||||
|
Some(n_int)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn as_integer(&self) -> lua_Integer {
|
||||||
|
self.as_number() as lua_Integer
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn is_collectable(&self) -> bool {
|
||||||
|
self.tt >= LUA_TSTRING
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Closure {
|
||||||
|
pub tt: u8,
|
||||||
|
pub marked: u8,
|
||||||
|
pub memcat: u8,
|
||||||
|
|
||||||
|
pub is_c: u8,
|
||||||
|
pub n_upvals: u8,
|
||||||
|
pub stack_size: u8,
|
||||||
|
pub preload: u8,
|
||||||
|
|
||||||
|
pub gc_list: *mut GCObject,
|
||||||
|
pub env: *mut Table,
|
||||||
|
|
||||||
|
pub body: ClosureBody,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Closure {
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn is_c(&self) -> bool {
|
||||||
|
self.is_c != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for Closure {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
f.debug_struct("Closure")
|
||||||
|
.field("tt", &self.tt)
|
||||||
|
.field("marked", &self.marked)
|
||||||
|
.field("memcat", &self.memcat)
|
||||||
|
|
||||||
|
.field("is_c", &self.is_c)
|
||||||
|
.field("n_upvals", &self.n_upvals)
|
||||||
|
.field("stack_size", &self.stack_size)
|
||||||
|
.field("preload", &self.preload)
|
||||||
|
|
||||||
|
.field("gc_List", &self.gc_list)
|
||||||
|
.field("env", &self.env)
|
||||||
|
|
||||||
|
.field("body", if self.is_c() {
|
||||||
|
unsafe { &self.body.c }
|
||||||
|
} else {
|
||||||
|
unsafe { &self.body.l }
|
||||||
|
})
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub union ClosureBody {
|
||||||
|
pub c: ManuallyDrop<ClosureC>,
|
||||||
|
pub l: ManuallyDrop<ClosureL>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct ClosureC {
|
||||||
|
pub f: lua_CFunction,
|
||||||
|
pub cont: lua_Continuation,
|
||||||
|
pub debugname: *const c_char,
|
||||||
|
pub upvals: [TValue; 1],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for ClosureC {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
f.debug_struct("ClosureC")
|
||||||
|
.field("f", &self.f)
|
||||||
|
.field("cont", &self.cont)
|
||||||
|
.field("debugname", unsafe { &std::ffi::CStr::from_ptr(self.debugname) })
|
||||||
|
.field("upvals", &std::ptr::addr_of!(self.upvals))
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct ClosureL {
|
||||||
|
pub p: *mut Proto,
|
||||||
|
pub uprefs: [TValue; 1],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for ClosureL {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
f.debug_struct("ClosureL")
|
||||||
|
.field("p", &self.p)
|
||||||
|
.field("uprefs", &std::ptr::addr_of!(self.uprefs))
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Table {
|
||||||
|
pub tt: u8,
|
||||||
|
pub marked: u8,
|
||||||
|
pub memcat: u8,
|
||||||
|
|
||||||
|
/// 1<<p means tagmethod(p) is not present
|
||||||
|
pub tmcache: u8,
|
||||||
|
/// sandboxing feature to prohibit writes to table
|
||||||
|
pub readonly: bool,
|
||||||
|
/// environment doesn't share globals with other scripts
|
||||||
|
pub safeenv: bool,
|
||||||
|
/// log2 of size of `node' array
|
||||||
|
pub l_size_node: u8,
|
||||||
|
/// (1<<lsizenode)-1, truncated to 8 bits
|
||||||
|
pub node_mask8: u8,
|
||||||
|
|
||||||
|
/// size of `array' array
|
||||||
|
pub size_array: c_int,
|
||||||
|
/// lastfree: any free position is before this position
|
||||||
|
/// aboundary: negated 'boundary' of `array' array; iff aboundary < 0
|
||||||
|
pub lastfree_or_aboundary: c_int,
|
||||||
|
|
||||||
|
|
||||||
|
pub metatable: Option<NonNull<Table>>,
|
||||||
|
/// array part
|
||||||
|
pub array: Option<NonNull<TValue>>,
|
||||||
|
/// dict part. If there is no node, the value will be the address of [`crate::luaH_dummynode`].
|
||||||
|
pub node: NonNull<LuaNode>,
|
||||||
|
pub gc_list: *mut GCObject,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Table {
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn array(&self) -> &[TValue] {
|
||||||
|
debug_assert!(self.size_array >= 0);
|
||||||
|
debug_assert_eq!(self.array.is_none(), self.size_array == 0, "inconsistent array properties: null pointer with non-zero length");
|
||||||
|
match (self.array, self.size_array) {
|
||||||
|
(None, 0) => &[],
|
||||||
|
// in debug_assertions this will be caught, otherwise, allow the optimizer to ignore it
|
||||||
|
(Some(_), 0) | (None, _) => std::hint::unreachable_unchecked(),
|
||||||
|
(Some(ptr), len) => std::slice::from_raw_parts(ptr.as_ptr(), len as _)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn array_mut(&mut self) -> &mut [TValue] {
|
||||||
|
debug_assert!(self.size_array >= 0);
|
||||||
|
debug_assert_eq!(self.array.is_none(), self.size_array == 0, "inconsistent array properties: null pointer with non-zero length");
|
||||||
|
match (self.array, self.size_array) {
|
||||||
|
(None, 0) => &mut [],
|
||||||
|
// in debug_assertions this will be caught, otherwise, allow the optimizer to ignore it
|
||||||
|
(Some(_), 0) | (None, _) => std::hint::unreachable_unchecked(),
|
||||||
|
(Some(ptr), len) => std::slice::from_raw_parts_mut(ptr.as_ptr(), len as _)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn array_lsize(&self) -> usize {
|
||||||
|
self.array().iter().rposition(|v| v.tt != LUA_TNIL).map(|i| i+1).unwrap_or(0)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,216 @@
|
||||||
|
use std::ffi::{c_void, c_int, c_ushort, c_uint};
|
||||||
|
use std::mem::ManuallyDrop;
|
||||||
|
use std::ptr::{addr_of_mut, NonNull};
|
||||||
|
|
||||||
|
use crate::{Closure, GCheader, Proto, StkId, Table, TString, TValue, Udata, UpVal};
|
||||||
|
|
||||||
|
opaque! {
|
||||||
|
pub type global_State;
|
||||||
|
|
||||||
|
pub type Instruction;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
pub static luaO_nilobject_: TValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn luaO_nilobject() -> NonNull<TValue> {
|
||||||
|
unsafe { NonNull::new_unchecked(std::ptr::addr_of!(luaO_nilobject_).cast_mut()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Union of all collectible objects
|
||||||
|
#[repr(C)]
|
||||||
|
pub union GCObject
|
||||||
|
{
|
||||||
|
pub gch: ManuallyDrop<GCheader>,
|
||||||
|
pub ts: ManuallyDrop<TString>,
|
||||||
|
pub u: ManuallyDrop<Udata>,
|
||||||
|
pub cl: ManuallyDrop<Closure>,
|
||||||
|
pub h: ManuallyDrop<Table>,
|
||||||
|
pub p: ManuallyDrop<Proto>,
|
||||||
|
pub uv: ManuallyDrop<UpVal>,
|
||||||
|
/// thread
|
||||||
|
pub th: ManuallyDrop<lua_State>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for GCObject {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
write!(f, "GCObject({:?})", unsafe { self.gch })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct GCObjectPtr(pub *mut GCObject);
|
||||||
|
|
||||||
|
impl GCObjectPtr {
|
||||||
|
pub fn hdr(self) -> *mut GCheader {
|
||||||
|
unsafe { addr_of_mut!(*(*self.0).gch) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<GCObjectPtr> for *mut GCObject {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(value: GCObjectPtr) -> Self {
|
||||||
|
value.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<*mut GCObject> for GCObjectPtr {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(value: *mut GCObject) -> Self {
|
||||||
|
Self(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<*mut GCheader> for GCObjectPtr {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(value: *mut GCheader) -> Self {
|
||||||
|
unsafe { GCObjectPtr(std::mem::transmute(value)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<*mut TString> for GCObjectPtr {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(value: *mut TString) -> Self {
|
||||||
|
unsafe { GCObjectPtr(std::mem::transmute(value)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<*mut Udata> for GCObjectPtr {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(value: *mut Udata) -> Self {
|
||||||
|
unsafe { GCObjectPtr(std::mem::transmute(value)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<*mut Closure> for GCObjectPtr {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(value: *mut Closure) -> Self {
|
||||||
|
unsafe { GCObjectPtr(std::mem::transmute(value)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<*mut Table> for GCObjectPtr {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(value: *mut Table) -> Self {
|
||||||
|
unsafe { GCObjectPtr(std::mem::transmute(value)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<*mut Proto> for GCObjectPtr {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(value: *mut Proto) -> Self {
|
||||||
|
unsafe { GCObjectPtr(std::mem::transmute(value)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<*mut UpVal> for GCObjectPtr {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(value: *mut UpVal) -> Self {
|
||||||
|
unsafe { GCObjectPtr(std::mem::transmute(value)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<*mut lua_State> for GCObjectPtr {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(value: *mut lua_State) -> Self {
|
||||||
|
unsafe { GCObjectPtr(std::mem::transmute(value)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See docs at <https://github.com/Roblox/luau/blob/a02eb78c96f695a4287e7dd1beaccab3642c35f3/VM/src/lstate.h#L29-L29>
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct CallInfo {
|
||||||
|
/// base for this function.
|
||||||
|
pub base: StkId,
|
||||||
|
/// function index in the stack
|
||||||
|
pub func: StkId,
|
||||||
|
/// top for this function
|
||||||
|
///
|
||||||
|
/// Seems to indicate the allocated stack size, not used.
|
||||||
|
pub top: StkId,
|
||||||
|
|
||||||
|
pub saved_pc: *const Instruction,
|
||||||
|
|
||||||
|
/// expected number of results from this function
|
||||||
|
pub n_results: c_int,
|
||||||
|
|
||||||
|
/// call frame flags, see LUA_CALLINFO_*
|
||||||
|
pub flags: c_uint,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// should the interpreter return after returning from this callinfo? first frame must have this set
|
||||||
|
pub const LUA_CALLINFO_RETURN: c_uint = 1 << 0;
|
||||||
|
/// should the error thrown during execution get handled by continuation from this callinfo? func must be C
|
||||||
|
pub const LUA_CALLINFO_HANDLE: c_uint = 1 << 1;
|
||||||
|
/// should this function be executed using execution callback for native code
|
||||||
|
pub const LUA_CALLINFO_NATIVE: c_uint = 1 << 2;
|
||||||
|
|
||||||
|
/// A raw Lua state associated with a thread.
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct lua_State {
|
||||||
|
pub tt: u8,
|
||||||
|
pub marked: u8,
|
||||||
|
pub memcat: u8,
|
||||||
|
|
||||||
|
pub status: u8,
|
||||||
|
|
||||||
|
/// memory category that is used for new GC object allocations
|
||||||
|
pub active_memcat: u8,
|
||||||
|
|
||||||
|
/// thread is currently executing, stack may be mutated without barriers
|
||||||
|
pub is_active: bool,
|
||||||
|
/// call debugstep hook after each instruction
|
||||||
|
pub single_step: bool,
|
||||||
|
|
||||||
|
|
||||||
|
/// first free slot in the stack
|
||||||
|
pub top: StkId,
|
||||||
|
/// base of current function
|
||||||
|
pub base: StkId,
|
||||||
|
pub global: *mut global_State,
|
||||||
|
/// call info for current function
|
||||||
|
pub ci: *mut CallInfo,
|
||||||
|
/// last free slot in the stack
|
||||||
|
pub stack_last: StkId,
|
||||||
|
/// stack base
|
||||||
|
pub stack: StkId,
|
||||||
|
|
||||||
|
|
||||||
|
/// points after end of ci array
|
||||||
|
pub end_ci: *mut CallInfo,
|
||||||
|
/// array of [`CallInfo`]s
|
||||||
|
pub base_ci: *mut CallInfo,
|
||||||
|
|
||||||
|
|
||||||
|
/// The current allocated size of the entire thread stack.
|
||||||
|
pub stack_size: c_int,
|
||||||
|
/// size of array [`base_ci']
|
||||||
|
pub size_ci: c_int,
|
||||||
|
|
||||||
|
|
||||||
|
/// number of nested C calls
|
||||||
|
pub n_c_calls: c_ushort,
|
||||||
|
/// nested C calls when resuming coroutine
|
||||||
|
pub base_c_calls: c_ushort,
|
||||||
|
|
||||||
|
/// when table operations or `INDEX`/`NEWINDEX` is invoked from Luau, what is the expected slot for lookup?
|
||||||
|
pub cached_slot: c_int,
|
||||||
|
|
||||||
|
/// table of globals
|
||||||
|
pub globals: *mut Table,
|
||||||
|
/// list of open upvalues in this stack
|
||||||
|
pub open_upval: *mut UpVal,
|
||||||
|
pub gc_list: *mut GCObject,
|
||||||
|
|
||||||
|
/// when invoked from Luau using `NAMECALL`, what method do we need to invoke?
|
||||||
|
pub namecall: *mut TString,
|
||||||
|
|
||||||
|
pub userdata: *mut c_void,
|
||||||
|
|
||||||
|
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
use crate::LuaNode;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
pub static luaH_dummynode: LuaNode;
|
||||||
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
//! Contains definitions from `lua.h`.
|
//! Contains definitions from `lua.h`.
|
||||||
|
|
||||||
use std::marker::{PhantomData, PhantomPinned};
|
|
||||||
use std::os::raw::{c_char, c_double, c_float, c_int, c_uint, c_void};
|
use std::os::raw::{c_char, c_double, c_float, c_int, c_uint, c_void};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
|
@ -31,13 +30,9 @@ pub const LUA_ERRRUN: c_int = 2;
|
||||||
pub const LUA_ERRSYNTAX: c_int = 3;
|
pub const LUA_ERRSYNTAX: c_int = 3;
|
||||||
pub const LUA_ERRMEM: c_int = 4;
|
pub const LUA_ERRMEM: c_int = 4;
|
||||||
pub const LUA_ERRERR: c_int = 5;
|
pub const LUA_ERRERR: c_int = 5;
|
||||||
|
pub const LUA_BREAK: c_int = 6;
|
||||||
|
|
||||||
/// A raw Lua state associated with a thread.
|
pub use super::lstate::lua_State;
|
||||||
#[repr(C)]
|
|
||||||
pub struct lua_State {
|
|
||||||
_data: [u8; 0],
|
|
||||||
_marker: PhantomData<(*mut u8, PhantomPinned)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Basic types
|
// Basic types
|
||||||
|
@ -381,25 +376,19 @@ pub unsafe fn lua_pushliteral(L: *mut lua_State, s: &'static str) {
|
||||||
lua_pushlstring_(L, c_str.as_ptr(), c_str.as_bytes().len())
|
lua_pushlstring_(L, c_str.as_ptr(), c_str.as_bytes().len())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn lua_pushcfunction(L: *mut lua_State, f: lua_CFunction) {
|
#[inline(always)]
|
||||||
lua_pushcclosurek(L, f, ptr::null(), 0, None)
|
pub unsafe fn lua_pushcfunction(L: *mut lua_State, f: lua_CFunction, debug_name: *const c_char) {
|
||||||
|
lua_pushcclosurek(L, f, debug_name, 0, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn lua_pushcfunctiond(L: *mut lua_State, f: lua_CFunction, debugname: *const c_char) {
|
#[inline(always)]
|
||||||
lua_pushcclosurek(L, f, debugname, 0, None)
|
pub unsafe fn lua_pushcclosure(
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe fn lua_pushcclosure(L: *mut lua_State, f: lua_CFunction, nup: c_int) {
|
|
||||||
lua_pushcclosurek(L, f, ptr::null(), nup, None)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe fn lua_pushcclosured(
|
|
||||||
L: *mut lua_State,
|
L: *mut lua_State,
|
||||||
f: lua_CFunction,
|
f: lua_CFunction,
|
||||||
debugname: *const c_char,
|
debug_name: *const c_char,
|
||||||
nup: c_int,
|
n_up: c_int,
|
||||||
) {
|
) {
|
||||||
lua_pushcclosurek(L, f, debugname, nup, None)
|
lua_pushcclosurek(L, f, debug_name, n_up, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -516,3 +505,13 @@ pub struct lua_Callbacks {
|
||||||
extern "C" {
|
extern "C" {
|
||||||
pub fn lua_callbacks(L: *mut lua_State) -> *mut lua_Callbacks;
|
pub fn lua_callbacks(L: *mut lua_State) -> *mut lua_Callbacks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn real_index2addr(l: *mut lua_State, idx: i32) -> ptr::NonNull<crate::TValue> {
|
||||||
|
debug_assert!(idx > 0, "Invalid stack index: {idx}");
|
||||||
|
let l = &*l;
|
||||||
|
let o = l.base.add(idx as usize - 1);
|
||||||
|
debug_assert!(o < (&*l.ci).top);
|
||||||
|
debug_assert!(o < l.top);
|
||||||
|
ptr::NonNull::new_unchecked(o)
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
use std::ffi::{c_char, c_int, c_void};
|
||||||
|
|
||||||
|
use crate::lua_State;
|
||||||
|
|
||||||
|
pub type luau_AssertHandler = unsafe extern "C" fn(expr: *const c_char, file: *const c_char, line: c_int, function: *const c_char) -> c_int;
|
||||||
|
|
||||||
|
pub type luau_Pfunc = unsafe extern "C" fn(L: *mut lua_State, ud: *mut c_void);
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
#[link_name = "_ZZN4Luau13assertHandlerEvE7handler"]
|
||||||
|
pub static mut luau_assertHandler: luau_AssertHandler;
|
||||||
|
|
||||||
|
pub fn luaD_pcall(L: *mut lua_State, func: luau_Pfunc, ud: *mut c_void, old_top: isize, ef: isize);
|
||||||
|
}
|
|
@ -2,14 +2,24 @@
|
||||||
|
|
||||||
pub use compat::*;
|
pub use compat::*;
|
||||||
pub use lauxlib::*;
|
pub use lauxlib::*;
|
||||||
|
pub use lgc::*;
|
||||||
|
pub use lobject::*;
|
||||||
|
pub use lstate::*;
|
||||||
|
pub use ltable::*;
|
||||||
pub use lua::*;
|
pub use lua::*;
|
||||||
pub use luacode::*;
|
pub use luacode::*;
|
||||||
pub use luacodegen::*;
|
pub use luacodegen::*;
|
||||||
pub use lualib::*;
|
pub use lualib::*;
|
||||||
|
pub use luau::*;
|
||||||
|
|
||||||
pub mod compat;
|
pub mod compat;
|
||||||
pub mod lauxlib;
|
pub mod lauxlib;
|
||||||
|
pub mod lgc;
|
||||||
|
pub mod lobject;
|
||||||
|
pub mod lstate;
|
||||||
|
pub mod ltable;
|
||||||
pub mod lua;
|
pub mod lua;
|
||||||
pub mod luacode;
|
pub mod luacode;
|
||||||
pub mod luacodegen;
|
pub mod luacodegen;
|
||||||
pub mod lualib;
|
pub mod lualib;
|
||||||
|
pub mod luau;
|
||||||
|
|
|
@ -5,3 +5,13 @@ macro_rules! cstr {
|
||||||
as *const ::std::os::raw::c_char
|
as *const ::std::os::raw::c_char
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! opaque {
|
||||||
|
($($vis:vis type $name:ident;)*) => {$(
|
||||||
|
#[repr(C)]
|
||||||
|
$vis struct $name {
|
||||||
|
_data: [u8; 0],
|
||||||
|
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
|
||||||
|
}
|
||||||
|
)*};
|
||||||
|
}
|
||||||
|
|
|
@ -145,7 +145,7 @@ impl<'lua> Function<'lua> {
|
||||||
let _sg = StackGuard::new(state);
|
let _sg = StackGuard::new(state);
|
||||||
check_stack(state, nargs + 3)?;
|
check_stack(state, nargs + 3)?;
|
||||||
|
|
||||||
MemoryState::relax_limit_with(state, || ffi::lua_pushcfunction(state, error_traceback));
|
MemoryState::relax_limit_with(state, || ffi::lua_pushcfunction(state, error_traceback, "mlua::util::error_traceback\0".as_ptr().cast()));
|
||||||
let stack_start = ffi::lua_gettop(state);
|
let stack_start = ffi::lua_gettop(state);
|
||||||
lua.push_ref(&self.0);
|
lua.push_ref(&self.0);
|
||||||
for arg in args.drain_all() {
|
for arg in args.drain_all() {
|
||||||
|
@ -278,7 +278,7 @@ impl<'lua> Function<'lua> {
|
||||||
lua.push_value(arg)?;
|
lua.push_value(arg)?;
|
||||||
}
|
}
|
||||||
protect_lua!(state, nargs + 1, 1, fn(state) {
|
protect_lua!(state, nargs + 1, 1, fn(state) {
|
||||||
ffi::lua_pushcclosure(state, args_wrapper_impl, ffi::lua_gettop(state));
|
ffi::lua_pushcclosure(state, args_wrapper_impl, "mlua::Function::bind::args_wrapper_impl\0".as_ptr().cast(), ffi::lua_gettop(state));
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Function(lua.pop_ref())
|
Function(lua.pop_ref())
|
||||||
|
|
|
@ -85,7 +85,7 @@ mod error;
|
||||||
pub mod ffi;
|
pub mod ffi;
|
||||||
mod function;
|
mod function;
|
||||||
mod hook;
|
mod hook;
|
||||||
mod lua;
|
pub mod lua;
|
||||||
#[cfg(feature = "luau")]
|
#[cfg(feature = "luau")]
|
||||||
mod luau;
|
mod luau;
|
||||||
mod memory;
|
mod memory;
|
||||||
|
|
95
src/lua.rs
95
src/lua.rs
|
@ -78,7 +78,7 @@ pub struct LuaInner {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Data associated with the Lua.
|
// Data associated with the Lua.
|
||||||
pub(crate) struct ExtraData {
|
pub struct ExtraData {
|
||||||
// Same layout as `Lua`
|
// Same layout as `Lua`
|
||||||
inner: MaybeUninit<Arc<LuaInner>>,
|
inner: MaybeUninit<Arc<LuaInner>>,
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ pub(crate) struct ExtraData {
|
||||||
thread_pool: Vec<c_int>,
|
thread_pool: Vec<c_int>,
|
||||||
|
|
||||||
// Address of `WrappedFailure` metatable
|
// Address of `WrappedFailure` metatable
|
||||||
wrapped_failure_mt_ptr: *const c_void,
|
pub wrapped_failure_mt_ptr: *const c_void,
|
||||||
|
|
||||||
// Waker for polling futures
|
// Waker for polling futures
|
||||||
#[cfg(feature = "async")]
|
#[cfg(feature = "async")]
|
||||||
|
@ -412,6 +412,7 @@ impl Lua {
|
||||||
(*extra).libs |= libs;
|
(*extra).libs |= libs;
|
||||||
|
|
||||||
if !options.catch_rust_panics {
|
if !options.catch_rust_panics {
|
||||||
|
eprintln!("overriding pcall");
|
||||||
mlua_expect!(
|
mlua_expect!(
|
||||||
(|| -> Result<()> {
|
(|| -> Result<()> {
|
||||||
let _sg = StackGuard::new(state);
|
let _sg = StackGuard::new(state);
|
||||||
|
@ -421,10 +422,10 @@ impl Lua {
|
||||||
#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
|
#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
|
||||||
ffi::lua_pushvalue(state, ffi::LUA_GLOBALSINDEX);
|
ffi::lua_pushvalue(state, ffi::LUA_GLOBALSINDEX);
|
||||||
|
|
||||||
ffi::lua_pushcfunction(state, safe_pcall);
|
ffi::lua_pushcfunction(state, safe_pcall, "mlua::safe_pcall\0".as_ptr().cast());
|
||||||
rawset_field(state, -2, "pcall")?;
|
rawset_field(state, -2, "pcall")?;
|
||||||
|
|
||||||
ffi::lua_pushcfunction(state, safe_xpcall);
|
ffi::lua_pushcfunction(state, safe_xpcall, "mlua::safe_xpcall\0".as_ptr().cast());
|
||||||
rawset_field(state, -2, "xpcall")?;
|
rawset_field(state, -2, "xpcall")?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1559,10 +1560,15 @@ impl Lua {
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// This function is unsafe because provides a way to execute unsafe C function.
|
/// This function is unsafe because provides a way to execute unsafe C function.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn create_c_function(&self, func: ffi::lua_CFunction) -> Result<Function> {
|
pub unsafe fn create_c_function(
|
||||||
|
&self,
|
||||||
|
func: ffi::lua_CFunction,
|
||||||
|
cont: Option<ffi::lua_Continuation>,
|
||||||
|
debug_name: Option<&'static CStr>,
|
||||||
|
) -> Result<Function> {
|
||||||
let state = self.state();
|
let state = self.state();
|
||||||
check_stack(state, 1)?;
|
check_stack(state, 1)?;
|
||||||
ffi::lua_pushcfunction(state, func);
|
ffi::lua_pushcclosurek(state, func, debug_name.map(CStr::as_ptr).unwrap_or(std::ptr::null()), 0, cont);
|
||||||
Ok(Function(self.pop_ref()))
|
Ok(Function(self.pop_ref()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1574,10 +1580,18 @@ impl Lua {
|
||||||
pub unsafe fn create_c_closure<'lua>(
|
pub unsafe fn create_c_closure<'lua>(
|
||||||
&'lua self,
|
&'lua self,
|
||||||
func: ffi::lua_CFunction,
|
func: ffi::lua_CFunction,
|
||||||
|
cont: Option<ffi::lua_Continuation>,
|
||||||
|
debug_name: Option<&'static CStr>,
|
||||||
upvalues: impl IntoLuaMulti<'lua>,
|
upvalues: impl IntoLuaMulti<'lua>,
|
||||||
) -> Result<Function> {
|
) -> Result<Function> {
|
||||||
let state = self.state();
|
let state = self.state();
|
||||||
|
if matches!(upvalues.lua_multi_len(), Some(0)) {
|
||||||
|
return self.create_c_function(func, cont, debug_name);
|
||||||
|
}
|
||||||
let upvalues = upvalues.into_lua_multi(self)?;
|
let upvalues = upvalues.into_lua_multi(self)?;
|
||||||
|
if upvalues.len() == 0 {
|
||||||
|
return self.create_c_function(func, cont, debug_name);
|
||||||
|
}
|
||||||
let Ok(n) = i32::try_from(upvalues.len()) else {
|
let Ok(n) = i32::try_from(upvalues.len()) else {
|
||||||
return Err(Error::BadArgument { to: Some("create_c_closure".to_owned()), pos: 3, name: Some("upvalues".to_owned()), cause: Arc::new(Error::BindError) })
|
return Err(Error::BadArgument { to: Some("create_c_closure".to_owned()), pos: 3, name: Some("upvalues".to_owned()), cause: Arc::new(Error::BindError) })
|
||||||
};
|
};
|
||||||
|
@ -1586,7 +1600,7 @@ impl Lua {
|
||||||
for upvalue in upvalues {
|
for upvalue in upvalues {
|
||||||
self.push_value(upvalue)?;
|
self.push_value(upvalue)?;
|
||||||
}
|
}
|
||||||
ffi::lua_pushcclosure(state, func, n);
|
ffi::lua_pushcclosurek(state, func, debug_name.map(CStr::as_ptr).unwrap_or(std::ptr::null()), n, cont);
|
||||||
Ok(Function(self.pop_ref()))
|
Ok(Function(self.pop_ref()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2433,26 +2447,10 @@ impl Lua {
|
||||||
ffi::LUA_TFUNCTION => Value::Function(Function(self.pop_ref())),
|
ffi::LUA_TFUNCTION => Value::Function(Function(self.pop_ref())),
|
||||||
|
|
||||||
ffi::LUA_TUSERDATA => {
|
ffi::LUA_TUSERDATA => {
|
||||||
let wrapped_failure_mt_ptr = (*self.extra.get()).wrapped_failure_mt_ptr;
|
match (*self.extra.get()).pop_wrapped_failure(state) {
|
||||||
// We must prevent interaction with userdata types other than UserData OR a WrappedError.
|
Some(Some(e)) => Value::Error(e),
|
||||||
// WrappedPanics are automatically resumed.
|
Some(None) => Nil,
|
||||||
match get_gc_userdata::<WrappedFailure>(state, -1, wrapped_failure_mt_ptr).as_mut()
|
None => Value::UserData(AnyUserData(self.pop_ref())),
|
||||||
{
|
|
||||||
Some(WrappedFailure::Error(err)) => {
|
|
||||||
let err = err.clone();
|
|
||||||
ffi::lua_pop(state, 1);
|
|
||||||
Value::Error(err)
|
|
||||||
}
|
|
||||||
Some(WrappedFailure::Panic(panic)) => {
|
|
||||||
if let Some(panic) = panic.take() {
|
|
||||||
ffi::lua_pop(state, 1);
|
|
||||||
resume_unwind(panic);
|
|
||||||
}
|
|
||||||
// Previously resumed panic?
|
|
||||||
ffi::lua_pop(state, 1);
|
|
||||||
Nil
|
|
||||||
}
|
|
||||||
_ => Value::UserData(AnyUserData(self.pop_ref())),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2800,10 +2798,10 @@ impl Lua {
|
||||||
push_gc_userdata(state, CallbackUpvalue { data: func, extra }, protect)?;
|
push_gc_userdata(state, CallbackUpvalue { data: func, extra }, protect)?;
|
||||||
if protect {
|
if protect {
|
||||||
protect_lua!(state, 1, 1, fn(state) {
|
protect_lua!(state, 1, 1, fn(state) {
|
||||||
ffi::lua_pushcclosure(state, call_callback, 1);
|
ffi::lua_pushcclosure(state, call_callback, "mlua::call_callback\0".as_ptr().cast(), 1);
|
||||||
})?;
|
})?;
|
||||||
} else {
|
} else {
|
||||||
ffi::lua_pushcclosure(state, call_callback, 1);
|
ffi::lua_pushcclosure(state, call_callback, "mlua::call_callback\0".as_ptr().cast(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Function(self.pop_ref()))
|
Ok(Function(self.pop_ref()))
|
||||||
|
@ -2852,10 +2850,10 @@ impl Lua {
|
||||||
push_gc_userdata(state, AsyncPollUpvalue { data: fut, extra }, protect)?;
|
push_gc_userdata(state, AsyncPollUpvalue { data: fut, extra }, protect)?;
|
||||||
if protect {
|
if protect {
|
||||||
protect_lua!(state, 1, 1, fn(state) {
|
protect_lua!(state, 1, 1, fn(state) {
|
||||||
ffi::lua_pushcclosure(state, poll_future, 1);
|
ffi::lua_pushcclosure(state, poll_future, "mlua::poll_future\0".as_ptr().cast(), 1);
|
||||||
})?;
|
})?;
|
||||||
} else {
|
} else {
|
||||||
ffi::lua_pushcclosure(state, poll_future, 1);
|
ffi::lua_pushcclosure(state, poll_future, "mlua::poll_future\0".as_ptr().cast(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(1)
|
Ok(1)
|
||||||
|
@ -2909,10 +2907,10 @@ impl Lua {
|
||||||
push_gc_userdata(state, upvalue, protect)?;
|
push_gc_userdata(state, upvalue, protect)?;
|
||||||
if protect {
|
if protect {
|
||||||
protect_lua!(state, 1, 1, fn(state) {
|
protect_lua!(state, 1, 1, fn(state) {
|
||||||
ffi::lua_pushcclosure(state, call_callback, 1);
|
ffi::lua_pushcclosure(state, call_callback, "mlua::call_callback\0".as_ptr().cast(), 1);
|
||||||
})?;
|
})?;
|
||||||
} else {
|
} else {
|
||||||
ffi::lua_pushcclosure(state, call_callback, 1);
|
ffi::lua_pushcclosure(state, call_callback, "mlua::call_callback\0".as_ptr().cast(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Function(self.pop_ref())
|
Function(self.pop_ref())
|
||||||
|
@ -2933,7 +2931,7 @@ impl Lua {
|
||||||
env.set("get_poll", get_poll)?;
|
env.set("get_poll", get_poll)?;
|
||||||
env.set("yield", coroutine.get::<_, Function>("yield")?)?;
|
env.set("yield", coroutine.get::<_, Function>("yield")?)?;
|
||||||
unsafe {
|
unsafe {
|
||||||
env.set("unpack", self.create_c_function(unpack)?)?;
|
env.set("unpack", self.create_c_function(unpack, None, Some(CStr::from_bytes_with_nul_unchecked(b"unpack\0")))?)?;
|
||||||
}
|
}
|
||||||
env.set("pending", {
|
env.set("pending", {
|
||||||
LightUserData(&ASYNC_POLL_PENDING as *const u8 as *mut c_void)
|
LightUserData(&ASYNC_POLL_PENDING as *const u8 as *mut c_void)
|
||||||
|
@ -3142,6 +3140,31 @@ impl ExtraData {
|
||||||
pub(crate) fn mem_state(&self) -> NonNull<MemoryState> {
|
pub(crate) fn mem_state(&self) -> NonNull<MemoryState> {
|
||||||
self.mem_state.unwrap()
|
self.mem_state.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Uses 2 stack spaces, does not call checkstack
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn pop_wrapped_failure(&self, state: *mut ffi::lua_State) -> Option<Option<Error>> {
|
||||||
|
// We must prevent interaction with userdata types other than UserData OR a WrappedError.
|
||||||
|
// WrappedPanics are automatically resumed.
|
||||||
|
match get_gc_userdata::<WrappedFailure>(state, -1, self.wrapped_failure_mt_ptr).as_mut()
|
||||||
|
{
|
||||||
|
Some(WrappedFailure::Error(err)) => {
|
||||||
|
let err = err.clone();
|
||||||
|
ffi::lua_pop(state, 1);
|
||||||
|
Some(Some(err))
|
||||||
|
}
|
||||||
|
Some(WrappedFailure::Panic(panic)) => {
|
||||||
|
if let Some(panic) = panic.take() {
|
||||||
|
ffi::lua_pop(state, 1);
|
||||||
|
resume_unwind(panic);
|
||||||
|
}
|
||||||
|
// Previously resumed panic?
|
||||||
|
ffi::lua_pop(state, 1);
|
||||||
|
Some(None)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct StateGuard<'a>(&'a LuaInner, *mut ffi::lua_State);
|
struct StateGuard<'a>(&'a LuaInner, *mut ffi::lua_State);
|
||||||
|
@ -3160,12 +3183,12 @@ impl<'a> Drop for StateGuard<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "luau")]
|
#[cfg(feature = "luau")]
|
||||||
unsafe fn extra_data(state: *mut ffi::lua_State) -> *mut ExtraData {
|
pub unsafe fn extra_data(state: *mut ffi::lua_State) -> *mut ExtraData {
|
||||||
(*ffi::lua_callbacks(state)).userdata as *mut ExtraData
|
(*ffi::lua_callbacks(state)).userdata as *mut ExtraData
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "luau"))]
|
#[cfg(not(feature = "luau"))]
|
||||||
unsafe fn extra_data(state: *mut ffi::lua_State) -> *mut ExtraData {
|
pub unsafe fn extra_data(state: *mut ffi::lua_State) -> *mut ExtraData {
|
||||||
let extra_key = &EXTRA_REGISTRY_KEY as *const u8 as *const c_void;
|
let extra_key = &EXTRA_REGISTRY_KEY as *const u8 as *const c_void;
|
||||||
if ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, extra_key) != ffi::LUA_TUSERDATA {
|
if ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, extra_key) != ffi::LUA_TUSERDATA {
|
||||||
// `ExtraData` can be null only when Lua state is foreign.
|
// `ExtraData` can be null only when Lua state is foreign.
|
||||||
|
|
|
@ -17,10 +17,10 @@ impl Lua {
|
||||||
|
|
||||||
globals.raw_set(
|
globals.raw_set(
|
||||||
"collectgarbage",
|
"collectgarbage",
|
||||||
self.create_c_function(lua_collectgarbage)?,
|
self.create_c_function(lua_collectgarbage, None, Some(CStr::from_bytes_with_nul_unchecked(b"collectgarbage\0")))?,
|
||||||
)?;
|
)?;
|
||||||
globals.raw_set("require", self.create_function(lua_require)?)?;
|
globals.raw_set("require", self.create_function(lua_require)?)?;
|
||||||
globals.raw_set("vector", self.create_c_function(lua_vector)?)?;
|
globals.raw_set("vector", self.create_c_function(lua_vector, None, Some(CStr::from_bytes_with_nul_unchecked(b"vector\0")))?)?;
|
||||||
|
|
||||||
// Set `_VERSION` global to include version number
|
// Set `_VERSION` global to include version number
|
||||||
// The environment variable `LUAU_VERSION` set by the build script
|
// The environment variable `LUAU_VERSION` set by the build script
|
||||||
|
|
|
@ -105,8 +105,13 @@ macro_rules! require_module_feature {
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! protect_lua {
|
macro_rules! protect_lua {
|
||||||
|
(@debug_name) => {
|
||||||
|
concat!("protect_lua[", file!(), ":", stringify!(line!()), ":", stringify!(column!()), "]")
|
||||||
|
.as_ptr().cast()
|
||||||
|
};
|
||||||
|
|
||||||
($state:expr, $nargs:expr, $nresults:expr, $f:expr) => {
|
($state:expr, $nargs:expr, $nresults:expr, $f:expr) => {
|
||||||
crate::util::protect_lua_closure($state, $nargs, $nresults, $f)
|
crate::util::protect_lua_closure($state, $nargs, $nresults, $f, $crate::macros::protect_lua!(@debug_name))
|
||||||
};
|
};
|
||||||
|
|
||||||
($state:expr, $nargs:expr, $nresults:expr, fn($state_inner:ident) $code:expr) => {{
|
($state:expr, $nargs:expr, $nresults:expr, fn($state_inner:ident) $code:expr) => {{
|
||||||
|
@ -120,6 +125,7 @@ macro_rules! protect_lua {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::util::protect_lua_call($state, $nargs, do_call)
|
crate::util::protect_lua_call($state, $nargs, do_call, $crate::macros::protect_lua!(@debug_name))
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
pub(crate) use protect_lua;
|
||||||
|
|
34
src/multi.rs
34
src/multi.rs
|
@ -30,6 +30,11 @@ impl<'lua, T: IntoLua<'lua>> IntoLuaMulti<'lua> for T {
|
||||||
v.push_front(self.into_lua(lua)?);
|
v.push_front(self.into_lua(lua)?);
|
||||||
Ok(v)
|
Ok(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn lua_multi_len(&self) -> Option<usize> {
|
||||||
|
Some(1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'lua, T: FromLua<'lua>> FromLuaMulti<'lua> for T {
|
impl<'lua, T: FromLua<'lua>> FromLuaMulti<'lua> for T {
|
||||||
|
@ -58,6 +63,11 @@ impl<'lua> IntoLuaMulti<'lua> for MultiValue<'lua> {
|
||||||
fn into_lua_multi(self, _: &'lua Lua) -> Result<MultiValue<'lua>> {
|
fn into_lua_multi(self, _: &'lua Lua) -> Result<MultiValue<'lua>> {
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn lua_multi_len(&self) -> Option<usize> {
|
||||||
|
Some(self.len())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'lua> FromLuaMulti<'lua> for MultiValue<'lua> {
|
impl<'lua> FromLuaMulti<'lua> for MultiValue<'lua> {
|
||||||
|
@ -145,6 +155,11 @@ impl<'lua, T: IntoLua<'lua>> IntoLuaMulti<'lua> for Variadic<T> {
|
||||||
values.refill(self.0.into_iter().map(|e| e.into_lua(lua)))?;
|
values.refill(self.0.into_iter().map(|e| e.into_lua(lua)))?;
|
||||||
Ok(values)
|
Ok(values)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn lua_multi_len(&self) -> Option<usize> {
|
||||||
|
Some(self.0.len())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'lua, T: FromLua<'lua>> FromLuaMulti<'lua> for Variadic<T> {
|
impl<'lua, T: FromLua<'lua>> FromLuaMulti<'lua> for Variadic<T> {
|
||||||
|
@ -167,6 +182,11 @@ macro_rules! impl_tuple {
|
||||||
fn into_lua_multi(self, lua: &'lua Lua) -> Result<MultiValue<'lua>> {
|
fn into_lua_multi(self, lua: &'lua Lua) -> Result<MultiValue<'lua>> {
|
||||||
Ok(MultiValue::new_or_pooled(lua))
|
Ok(MultiValue::new_or_pooled(lua))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn lua_multi_len(&self) -> Option<usize> {
|
||||||
|
Some(0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'lua> FromLuaMulti<'lua> for () {
|
impl<'lua> FromLuaMulti<'lua> for () {
|
||||||
|
@ -193,6 +213,11 @@ macro_rules! impl_tuple {
|
||||||
push_reverse!(results, $($name.into_lua(lua)?,)*);
|
push_reverse!(results, $($name.into_lua(lua)?,)*);
|
||||||
Ok(results)
|
Ok(results)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn lua_multi_len(&self) -> Option<usize> {
|
||||||
|
Some(count!($last $($name)*))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'lua, $($name,)* $last> FromLuaMulti<'lua> for ($($name,)* $last,)
|
impl<'lua, $($name,)* $last> FromLuaMulti<'lua> for ($($name,)* $last,)
|
||||||
|
@ -236,6 +261,15 @@ macro_rules! push_reverse {
|
||||||
($multi_value:expr,) => ();
|
($multi_value:expr,) => ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! count {
|
||||||
|
($a:ident) => {
|
||||||
|
1
|
||||||
|
};
|
||||||
|
($a:ident $($b:ident)+) => {
|
||||||
|
1 + count!($($b)+)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl_tuple!();
|
impl_tuple!();
|
||||||
impl_tuple!(A);
|
impl_tuple!(A);
|
||||||
impl_tuple!(A B);
|
impl_tuple!(A B);
|
||||||
|
|
|
@ -60,8 +60,8 @@ pub struct Thread<'lua>(pub(crate) LuaRef<'lua>);
|
||||||
///
|
///
|
||||||
/// Requires `feature = "async"`
|
/// Requires `feature = "async"`
|
||||||
///
|
///
|
||||||
/// [`Future`]: futures_core::future::Future
|
/// [`Future`]: std::future::Future
|
||||||
/// [`Stream`]: futures_core::stream::Stream
|
/// [`Stream`]: futures_util::stream::Stream
|
||||||
#[cfg(feature = "async")]
|
#[cfg(feature = "async")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||||
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||||
|
@ -284,8 +284,8 @@ impl<'lua> Thread<'lua> {
|
||||||
///
|
///
|
||||||
/// Requires `feature = "async"`
|
/// Requires `feature = "async"`
|
||||||
///
|
///
|
||||||
/// [`Future`]: futures_core::future::Future
|
/// [`Future`]: std::future::Future
|
||||||
/// [`Stream`]: futures_core::stream::Stream
|
/// [`Stream`]: futures_util::stream::Stream
|
||||||
/// [`resume()`]: https://www.lua.org/manual/5.4/manual.html#lua_resume
|
/// [`resume()`]: https://www.lua.org/manual/5.4/manual.html#lua_resume
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
|
|
@ -307,7 +307,7 @@ impl<'lua> LuaRef<'lua> {
|
||||||
|
|
||||||
impl<'lua> fmt::Debug for LuaRef<'lua> {
|
impl<'lua> fmt::Debug for LuaRef<'lua> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "Ref({})", self.index)
|
write!(f, "Ref({}, {:p})", self.index, self.to_pointer())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
154
src/util/mod.rs
154
src/util/mod.rs
|
@ -23,8 +23,8 @@ static METATABLE_CACHE: Lazy<FxHashMap<TypeId, u8>> = Lazy::new(|| {
|
||||||
map
|
map
|
||||||
});
|
});
|
||||||
|
|
||||||
// Checks that Lua has enough free stack space for future stack operations. On failure, this will
|
/// Checks that Lua has enough free stack space for future stack operations. On failure, this will
|
||||||
// panic with an internal error message.
|
/// panic with an internal error message.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn assert_stack(state: *mut ffi::lua_State, amount: c_int) {
|
pub unsafe fn assert_stack(state: *mut ffi::lua_State, amount: c_int) {
|
||||||
// TODO: This should only be triggered when there is a logic error in `mlua`. In the future,
|
// TODO: This should only be triggered when there is a logic error in `mlua`. In the future,
|
||||||
|
@ -36,7 +36,7 @@ pub unsafe fn assert_stack(state: *mut ffi::lua_State, amount: c_int) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks that Lua has enough free stack space and returns `Error::StackError` on failure.
|
/// Checks that Lua has enough free stack space and returns `Error::StackError` on failure.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn check_stack(state: *mut ffi::lua_State, amount: c_int) -> Result<()> {
|
pub unsafe fn check_stack(state: *mut ffi::lua_State, amount: c_int) -> Result<()> {
|
||||||
if ffi::lua_checkstack(state, amount) == 0 {
|
if ffi::lua_checkstack(state, amount) == 0 {
|
||||||
|
@ -78,22 +78,23 @@ impl Drop for StackGuard {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call a function that calls into the Lua API and may trigger a Lua error (longjmp) in a safe way.
|
/// Call a function that calls into the Lua API and may trigger a Lua error (longjmp) in a safe way.
|
||||||
// Wraps the inner function in a call to `lua_pcall`, so the inner function only has access to a
|
/// Wraps the inner function in a call to `lua_pcall`, so the inner function only has access to a
|
||||||
// limited lua stack. `nargs` is the same as the the parameter to `lua_pcall`, and `nresults` is
|
/// limited lua stack. `nargs` is the same as the the parameter to `lua_pcall`, and `nresults` is
|
||||||
// always `LUA_MULTRET`. Provided function must *not* panic, and since it will generally be lonjmping,
|
/// always `LUA_MULTRET`. Provided function must *not* panic, and since it will generally be lonjmping,
|
||||||
// should not contain any values that implements Drop.
|
/// should not contain any values that implements Drop.
|
||||||
// Internally uses 2 extra stack spaces, and does not call checkstack.
|
/// Internally uses 2 extra stack spaces, and does not call checkstack.
|
||||||
pub unsafe fn protect_lua_call(
|
pub unsafe fn protect_lua_call(
|
||||||
state: *mut ffi::lua_State,
|
state: *mut ffi::lua_State,
|
||||||
nargs: c_int,
|
nargs: c_int,
|
||||||
f: unsafe extern "C" fn(*mut ffi::lua_State) -> c_int,
|
f: unsafe extern "C" fn(*mut ffi::lua_State) -> c_int,
|
||||||
|
debug_name: *const c_char,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let stack_start = ffi::lua_gettop(state) - nargs;
|
let stack_start = ffi::lua_gettop(state) - nargs;
|
||||||
|
|
||||||
MemoryState::relax_limit_with(state, || {
|
MemoryState::relax_limit_with(state, || {
|
||||||
ffi::lua_pushcfunction(state, error_traceback);
|
ffi::lua_pushcfunction(state, error_traceback, "mlua::util::error_traceback\0".as_ptr().cast());
|
||||||
ffi::lua_pushcfunction(state, f);
|
ffi::lua_pushcfunction(state, f, debug_name);
|
||||||
});
|
});
|
||||||
if nargs > 0 {
|
if nargs > 0 {
|
||||||
ffi::lua_rotate(state, stack_start + 1, 2);
|
ffi::lua_rotate(state, stack_start + 1, 2);
|
||||||
|
@ -109,18 +110,19 @@ pub unsafe fn protect_lua_call(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call a function that calls into the Lua API and may trigger a Lua error (longjmp) in a safe way.
|
/// Call a function that calls into the Lua API and may trigger a Lua error (longjmp) in a safe way.
|
||||||
// Wraps the inner function in a call to `lua_pcall`, so the inner function only has access to a
|
/// Wraps the inner function in a call to `lua_pcall`, so the inner function only has access to a
|
||||||
// limited lua stack. `nargs` and `nresults` are similar to the parameters of `lua_pcall`, but the
|
/// limited lua stack. `nargs` and `nresults` are similar to the parameters of `lua_pcall`, but the
|
||||||
// given function return type is not the return value count, instead the inner function return
|
/// given function return type is not the return value count, instead the inner function return
|
||||||
// values are assumed to match the `nresults` param. Provided function must *not* panic, and since it
|
/// values are assumed to match the `nresults` param. Provided function must *not* panic, and since it
|
||||||
// will generally be lonjmping, should not contain any values that implements Drop.
|
/// will generally be lonjmping, should not contain any values that implements Drop.
|
||||||
// Internally uses 3 extra stack spaces, and does not call checkstack.
|
/// Internally uses 3 extra stack spaces, and does not call checkstack.
|
||||||
pub unsafe fn protect_lua_closure<F, R>(
|
pub unsafe fn protect_lua_closure<F, R>(
|
||||||
state: *mut ffi::lua_State,
|
state: *mut ffi::lua_State,
|
||||||
nargs: c_int,
|
nargs: c_int,
|
||||||
nresults: c_int,
|
nresults: c_int,
|
||||||
f: F,
|
f: F,
|
||||||
|
debug_name: *const c_char,
|
||||||
) -> Result<R>
|
) -> Result<R>
|
||||||
where
|
where
|
||||||
F: Fn(*mut ffi::lua_State) -> R,
|
F: Fn(*mut ffi::lua_State) -> R,
|
||||||
|
@ -152,8 +154,8 @@ where
|
||||||
let stack_start = ffi::lua_gettop(state) - nargs;
|
let stack_start = ffi::lua_gettop(state) - nargs;
|
||||||
|
|
||||||
MemoryState::relax_limit_with(state, || {
|
MemoryState::relax_limit_with(state, || {
|
||||||
ffi::lua_pushcfunction(state, error_traceback);
|
ffi::lua_pushcfunction(state, error_traceback, "mlua::util::error_traceback\0".as_ptr().cast());
|
||||||
ffi::lua_pushcfunction(state, do_call::<F, R>);
|
ffi::lua_pushcfunction(state, do_call::<F, R>, debug_name);
|
||||||
});
|
});
|
||||||
if nargs > 0 {
|
if nargs > 0 {
|
||||||
ffi::lua_rotate(state, stack_start + 1, 2);
|
ffi::lua_rotate(state, stack_start + 1, 2);
|
||||||
|
@ -178,12 +180,12 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pops an error off of the stack and returns it. The specific behavior depends on the type of the
|
/// Pops an error off of the stack and returns it. The specific behavior depends on the type of the
|
||||||
// error at the top of the stack:
|
/// error at the top of the stack:
|
||||||
// 1) If the error is actually a WrappedPanic, this will continue the panic.
|
/// 1) If the error is actually a WrappedPanic, this will continue the panic.
|
||||||
// 2) If the error on the top of the stack is actually a WrappedError, just returns it.
|
/// 2) If the error on the top of the stack is actually a WrappedError, just returns it.
|
||||||
// 3) Otherwise, interprets the error as the appropriate lua error.
|
/// 3) Otherwise, interprets the error as the appropriate lua error.
|
||||||
// Uses 2 stack spaces, does not call checkstack.
|
/// Uses 2 stack spaces, does not call checkstack.
|
||||||
pub unsafe fn pop_error(state: *mut ffi::lua_State, err_code: c_int) -> Error {
|
pub unsafe fn pop_error(state: *mut ffi::lua_State, err_code: c_int) -> Error {
|
||||||
mlua_debug_assert!(
|
mlua_debug_assert!(
|
||||||
err_code != ffi::LUA_OK && err_code != ffi::LUA_YIELD,
|
err_code != ffi::LUA_OK && err_code != ffi::LUA_YIELD,
|
||||||
|
@ -233,7 +235,7 @@ pub unsafe fn pop_error(state: *mut ffi::lua_State, err_code: c_int) -> Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uses 3 (or 1 if unprotected) stack spaces, does not call checkstack.
|
/// Uses 3 (or 1 if unprotected) stack spaces, does not call checkstack.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn push_string(state: *mut ffi::lua_State, s: &[u8], protect: bool) -> Result<()> {
|
pub unsafe fn push_string(state: *mut ffi::lua_State, s: &[u8], protect: bool) -> Result<()> {
|
||||||
// Always use protected mode if the string is too long
|
// Always use protected mode if the string is too long
|
||||||
|
@ -247,7 +249,7 @@ pub unsafe fn push_string(state: *mut ffi::lua_State, s: &[u8], protect: bool) -
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uses 3 stack spaces, does not call checkstack.
|
/// Uses 3 stack spaces, does not call checkstack.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn push_table(
|
pub unsafe fn push_table(
|
||||||
state: *mut ffi::lua_State,
|
state: *mut ffi::lua_State,
|
||||||
|
@ -263,7 +265,7 @@ pub unsafe fn push_table(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uses 4 stack spaces, does not call checkstack.
|
/// Uses 4 stack spaces, does not call checkstack.
|
||||||
pub unsafe fn rawset_field(state: *mut ffi::lua_State, table: c_int, field: &str) -> Result<()> {
|
pub unsafe fn rawset_field(state: *mut ffi::lua_State, table: c_int, field: &str) -> Result<()> {
|
||||||
ffi::lua_pushvalue(state, table);
|
ffi::lua_pushvalue(state, table);
|
||||||
protect_lua!(state, 2, 0, |state| {
|
protect_lua!(state, 2, 0, |state| {
|
||||||
|
@ -273,7 +275,7 @@ pub unsafe fn rawset_field(state: *mut ffi::lua_State, table: c_int, field: &str
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internally uses 3 stack spaces, does not call checkstack.
|
/// Internally uses 3 stack spaces, does not call checkstack.
|
||||||
#[cfg(not(feature = "luau"))]
|
#[cfg(not(feature = "luau"))]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T, protect: bool) -> Result<()> {
|
pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T, protect: bool) -> Result<()> {
|
||||||
|
@ -288,7 +290,7 @@ pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T, protect: bool)
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internally uses 3 stack spaces, does not call checkstack.
|
/// Internally uses 3 stack spaces, does not call checkstack.
|
||||||
#[cfg(feature = "luau")]
|
#[cfg(feature = "luau")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T, protect: bool) -> Result<()> {
|
pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T, protect: bool) -> Result<()> {
|
||||||
|
@ -309,7 +311,7 @@ pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T, protect: bool)
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internally uses 3 stack spaces, does not call checkstack.
|
/// Internally uses 3 stack spaces, does not call checkstack.
|
||||||
#[cfg(feature = "lua54")]
|
#[cfg(feature = "lua54")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn push_userdata_uv<T>(
|
pub unsafe fn push_userdata_uv<T>(
|
||||||
|
@ -336,10 +338,10 @@ pub unsafe fn get_userdata<T>(state: *mut ffi::lua_State, index: c_int) -> *mut
|
||||||
ud
|
ud
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pops the userdata off of the top of the stack and returns it to rust, invalidating the lua
|
/// Pops the userdata off of the top of the stack and returns it to rust, invalidating the lua
|
||||||
// userdata and gives it the special "destructed" userdata metatable. Userdata must not have been
|
/// userdata and gives it the special "destructed" userdata metatable. Userdata must not have been
|
||||||
// previously invalidated, and this method does not check for this.
|
/// previously invalidated, and this method does not check for this.
|
||||||
// Uses 1 extra stack space and does not call checkstack.
|
/// Uses 1 extra stack space and does not call checkstack.
|
||||||
pub unsafe fn take_userdata<T>(state: *mut ffi::lua_State) -> T {
|
pub unsafe fn take_userdata<T>(state: *mut ffi::lua_State) -> T {
|
||||||
// We set the metatable of userdata on __gc to a special table with no __gc method and with
|
// We set the metatable of userdata on __gc to a special table with no __gc method and with
|
||||||
// metamethods that trigger an error on access. We do this so that it will not be double
|
// metamethods that trigger an error on access. We do this so that it will not be double
|
||||||
|
@ -357,8 +359,8 @@ pub unsafe fn take_userdata<T>(state: *mut ffi::lua_State) -> T {
|
||||||
ptr::read(ud)
|
ptr::read(ud)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pushes the userdata and attaches a metatable with __gc method.
|
/// Pushes the userdata and attaches a metatable with __gc method.
|
||||||
// Internally uses 3 stack spaces, does not call checkstack.
|
/// Internally uses 3 stack spaces, does not call checkstack.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn push_gc_userdata<T: Any>(
|
pub unsafe fn push_gc_userdata<T: Any>(
|
||||||
state: *mut ffi::lua_State,
|
state: *mut ffi::lua_State,
|
||||||
|
@ -371,7 +373,7 @@ pub unsafe fn push_gc_userdata<T: Any>(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uses 2 stack spaces, does not call checkstack
|
/// Uses 2 stack spaces, does not call checkstack
|
||||||
pub unsafe fn get_gc_userdata<T: Any>(
|
pub unsafe fn get_gc_userdata<T: Any>(
|
||||||
state: *mut ffi::lua_State,
|
state: *mut ffi::lua_State,
|
||||||
index: c_int,
|
index: c_int,
|
||||||
|
@ -467,9 +469,9 @@ unsafe fn init_userdata_metatable_index(state: *mut ffi::lua_State) -> Result<()
|
||||||
if ret != ffi::LUA_OK {
|
if ret != ffi::LUA_OK {
|
||||||
ffi::lua_error(state);
|
ffi::lua_error(state);
|
||||||
}
|
}
|
||||||
ffi::lua_pushcfunction(state, lua_error_impl);
|
ffi::lua_pushcfunction(state, lua_error_impl, "mlua::util::lua_error_impl\0".as_ptr().cast());
|
||||||
ffi::lua_pushcfunction(state, lua_isfunction_impl);
|
ffi::lua_pushcfunction(state, lua_isfunction_impl, "mlua::util::lua_isfunction_impl\0".as_ptr().cast());
|
||||||
ffi::lua_pushcfunction(state, lua_istable_impl);
|
ffi::lua_pushcfunction(state, lua_istable_impl, "mlua::util::lua_istable_impl\0".as_ptr().cast());
|
||||||
ffi::lua_call(state, 3, 1);
|
ffi::lua_call(state, 3, 1);
|
||||||
|
|
||||||
#[cfg(feature = "luau-jit")]
|
#[cfg(feature = "luau-jit")]
|
||||||
|
@ -521,8 +523,8 @@ pub unsafe fn init_userdata_metatable_newindex(state: *mut ffi::lua_State) -> Re
|
||||||
if ret != ffi::LUA_OK {
|
if ret != ffi::LUA_OK {
|
||||||
ffi::lua_error(state);
|
ffi::lua_error(state);
|
||||||
}
|
}
|
||||||
ffi::lua_pushcfunction(state, lua_error_impl);
|
ffi::lua_pushcfunction(state, lua_error_impl, "mlua::util::lua_error_impl\0".as_ptr().cast());
|
||||||
ffi::lua_pushcfunction(state, lua_isfunction_impl);
|
ffi::lua_pushcfunction(state, lua_isfunction_impl, "mlua::util::lua_isfunction_impl\0".as_ptr().cast());
|
||||||
ffi::lua_call(state, 2, 1);
|
ffi::lua_call(state, 2, 1);
|
||||||
|
|
||||||
#[cfg(feature = "luau-jit")]
|
#[cfg(feature = "luau-jit")]
|
||||||
|
@ -536,14 +538,14 @@ pub unsafe fn init_userdata_metatable_newindex(state: *mut ffi::lua_State) -> Re
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Populates the given table with the appropriate members to be a userdata metatable for the given type.
|
/// Populates the given table with the appropriate members to be a userdata metatable for the given type.
|
||||||
// This function takes the given table at the `metatable` index, and adds an appropriate `__gc` member
|
/// This function takes the given table at the `metatable` index, and adds an appropriate `__gc` member
|
||||||
// to it for the given type and a `__metatable` entry to protect the table from script access.
|
/// to it for the given type and a `__metatable` entry to protect the table from script access.
|
||||||
// The function also, if given a `field_getters` or `methods` tables, will create an `__index` metamethod
|
/// The function also, if given a `field_getters` or `methods` tables, will create an `__index` metamethod
|
||||||
// (capturing previous one) to lookup in `field_getters` first, then `methods` and falling back to the
|
/// (capturing previous one) to lookup in `field_getters` first, then `methods` and falling back to the
|
||||||
// captured `__index` if no matches found.
|
/// captured `__index` if no matches found.
|
||||||
// The same is also applicable for `__newindex` metamethod and `field_setters` table.
|
/// The same is also applicable for `__newindex` metamethod and `field_setters` table.
|
||||||
// Internally uses 9 stack spaces and does not call checkstack.
|
/// Internally uses 9 stack spaces and does not call checkstack.
|
||||||
pub unsafe fn init_userdata_metatable<T>(
|
pub unsafe fn init_userdata_metatable<T>(
|
||||||
state: *mut ffi::lua_State,
|
state: *mut ffi::lua_State,
|
||||||
metatable: c_int,
|
metatable: c_int,
|
||||||
|
@ -618,17 +620,17 @@ pub unsafe extern "C" fn userdata_destructor<T>(state: *mut ffi::lua_State) -> c
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
// In the context of a lua callback, this will call the given function and if the given function
|
/// In the context of a lua callback, this will call the given function and if the given function
|
||||||
// returns an error, *or if the given function panics*, this will result in a call to `lua_error` (a
|
/// returns an error, *or if the given function panics*, this will result in a call to `lua_error` (a
|
||||||
// longjmp). The error or panic is wrapped in such a way that when calling `pop_error` back on
|
/// longjmp). The error or panic is wrapped in such a way that when calling `pop_error` back on
|
||||||
// the Rust side, it will resume the panic.
|
/// the Rust side, it will resume the panic.
|
||||||
//
|
///
|
||||||
// This function assumes the structure of the stack at the beginning of a callback, that the only
|
/// This function assumes the structure of the stack at the beginning of a callback, that the only
|
||||||
// elements on the stack are the arguments to the callback.
|
/// elements on the stack are the arguments to the callback.
|
||||||
//
|
///
|
||||||
// This function uses some of the bottom of the stack for error handling, the given callback will be
|
/// This function uses some of the bottom of the stack for error handling, the given callback will be
|
||||||
// given the number of arguments available as an argument, and should return the number of returns
|
/// given the number of arguments available as an argument, and should return the number of returns
|
||||||
// as normal, but cannot assume that the arguments available start at 0.
|
/// as normal, but cannot assume that the arguments available start at 0.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn callback_error<F, R>(state: *mut ffi::lua_State, f: F) -> R
|
pub unsafe fn callback_error<F, R>(state: *mut ffi::lua_State, f: F) -> R
|
||||||
where
|
where
|
||||||
|
@ -709,7 +711,7 @@ pub unsafe extern "C" fn error_traceback(state: *mut ffi::lua_State) -> c_int {
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
// A variant of `error_traceback` that can safely inspect another (yielded) thread stack
|
/// A variant of `error_traceback` that can safely inspect another (yielded) thread stack
|
||||||
pub unsafe fn error_traceback_thread(state: *mut ffi::lua_State, thread: *mut ffi::lua_State) {
|
pub unsafe fn error_traceback_thread(state: *mut ffi::lua_State, thread: *mut ffi::lua_State) {
|
||||||
// Move error object to the main thread to safely call `__tostring` metamethod if present
|
// Move error object to the main thread to safely call `__tostring` metamethod if present
|
||||||
ffi::lua_xmove(thread, state, 1);
|
ffi::lua_xmove(thread, state, 1);
|
||||||
|
@ -723,7 +725,7 @@ pub unsafe fn error_traceback_thread(state: *mut ffi::lua_State, thread: *mut ff
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A variant of `pcall` that does not allow Lua to catch Rust panics from `callback_error`.
|
/// A variant of `pcall` that does not allow Lua to catch Rust panics from `callback_error`.
|
||||||
pub unsafe extern "C" fn safe_pcall(state: *mut ffi::lua_State) -> c_int {
|
pub unsafe extern "C" fn safe_pcall(state: *mut ffi::lua_State) -> c_int {
|
||||||
ffi::luaL_checkstack(state, 2, ptr::null());
|
ffi::luaL_checkstack(state, 2, ptr::null());
|
||||||
|
|
||||||
|
@ -749,7 +751,7 @@ pub unsafe extern "C" fn safe_pcall(state: *mut ffi::lua_State) -> c_int {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A variant of `xpcall` that does not allow Lua to catch Rust panics from `callback_error`.
|
/// A variant of `xpcall` that does not allow Lua to catch Rust panics from `callback_error`.
|
||||||
pub unsafe extern "C" fn safe_xpcall(state: *mut ffi::lua_State) -> c_int {
|
pub unsafe extern "C" fn safe_xpcall(state: *mut ffi::lua_State) -> c_int {
|
||||||
unsafe extern "C" fn xpcall_msgh(state: *mut ffi::lua_State) -> c_int {
|
unsafe extern "C" fn xpcall_msgh(state: *mut ffi::lua_State) -> c_int {
|
||||||
ffi::luaL_checkstack(state, 2, ptr::null());
|
ffi::luaL_checkstack(state, 2, ptr::null());
|
||||||
|
@ -775,7 +777,7 @@ pub unsafe extern "C" fn safe_xpcall(state: *mut ffi::lua_State) -> c_int {
|
||||||
}
|
}
|
||||||
|
|
||||||
ffi::lua_pushvalue(state, 2);
|
ffi::lua_pushvalue(state, 2);
|
||||||
ffi::lua_pushcclosure(state, xpcall_msgh, 1);
|
ffi::lua_pushcclosure(state, xpcall_msgh, "mlua::util::xpcall_msgh\0".as_ptr().cast(), 1);
|
||||||
ffi::lua_copy(state, 1, 2);
|
ffi::lua_copy(state, 1, 2);
|
||||||
ffi::lua_replace(state, 1);
|
ffi::lua_replace(state, 1);
|
||||||
|
|
||||||
|
@ -795,8 +797,8 @@ pub unsafe extern "C" fn safe_xpcall(state: *mut ffi::lua_State) -> c_int {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns Lua main thread for Lua >= 5.2 or checks that the passed thread is main for Lua 5.1.
|
/// Returns Lua main thread for Lua >= 5.2 or checks that the passed thread is main for Lua 5.1.
|
||||||
// Does not call lua_checkstack, uses 1 stack space.
|
/// Does not call lua_checkstack, uses 1 stack space.
|
||||||
pub unsafe fn get_main_state(state: *mut ffi::lua_State) -> Option<*mut ffi::lua_State> {
|
pub unsafe fn get_main_state(state: *mut ffi::lua_State) -> Option<*mut ffi::lua_State> {
|
||||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
{
|
{
|
||||||
|
@ -820,8 +822,8 @@ pub unsafe fn get_main_state(state: *mut ffi::lua_State) -> Option<*mut ffi::lua
|
||||||
Some(ffi::lua_mainthread(state))
|
Some(ffi::lua_mainthread(state))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the internal (with __gc method) metatable for a type T.
|
/// Initialize the internal (with __gc method) metatable for a type T.
|
||||||
// Uses 6 stack spaces and calls checkstack.
|
/// Uses 6 stack spaces and calls checkstack.
|
||||||
pub unsafe fn init_gc_metatable<T: Any>(
|
pub unsafe fn init_gc_metatable<T: Any>(
|
||||||
state: *mut ffi::lua_State,
|
state: *mut ffi::lua_State,
|
||||||
customize_fn: Option<fn(*mut ffi::lua_State) -> Result<()>>,
|
customize_fn: Option<fn(*mut ffi::lua_State) -> Result<()>>,
|
||||||
|
@ -860,7 +862,7 @@ pub unsafe fn get_gc_metatable<T: Any>(state: *mut ffi::lua_State) {
|
||||||
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, ref_addr as *const c_void);
|
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, ref_addr as *const c_void);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the error, panic, and destructed userdata metatables.
|
/// Initialize the error, panic, and destructed userdata metatables.
|
||||||
pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<()> {
|
pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<()> {
|
||||||
check_stack(state, 7)?;
|
check_stack(state, 7)?;
|
||||||
|
|
||||||
|
@ -917,7 +919,7 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<()> {
|
||||||
init_gc_metatable::<WrappedFailure>(
|
init_gc_metatable::<WrappedFailure>(
|
||||||
state,
|
state,
|
||||||
Some(|state| {
|
Some(|state| {
|
||||||
ffi::lua_pushcfunction(state, error_tostring);
|
ffi::lua_pushcfunction(state, error_tostring, "mlua::util::error_tostring\0".as_ptr().cast());
|
||||||
rawset_field(state, -2, "__tostring")
|
rawset_field(state, -2, "__tostring")
|
||||||
}),
|
}),
|
||||||
)?;
|
)?;
|
||||||
|
@ -929,7 +931,7 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
push_table(state, 0, 26, true)?;
|
push_table(state, 0, 26, true)?;
|
||||||
ffi::lua_pushcfunction(state, destructed_error);
|
ffi::lua_pushcfunction(state, destructed_error, "mlua::util::destructed_error\0".as_ptr().cast());
|
||||||
for &method in &[
|
for &method in &[
|
||||||
"__add",
|
"__add",
|
||||||
"__sub",
|
"__sub",
|
||||||
|
@ -1019,8 +1021,8 @@ impl WrappedFailure {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts the given lua value to a string in a reasonable format without causing a Lua error or
|
/// Converts the given lua value to a string in a reasonable format without causing a Lua error or
|
||||||
// panicking.
|
/// panicking.
|
||||||
pub(crate) unsafe fn to_string(state: *mut ffi::lua_State, index: c_int) -> String {
|
pub(crate) unsafe fn to_string(state: *mut ffi::lua_State, index: c_int) -> String {
|
||||||
match ffi::lua_type(state, index) {
|
match ffi::lua_type(state, index) {
|
||||||
ffi::LUA_TNONE => "<none>".to_string(),
|
ffi::LUA_TNONE => "<none>".to_string(),
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//! Mostly copied from bevy_utils
|
//! Mostly copied from bevy_utils
|
||||||
//! https://github.com/bevyengine/bevy/blob/main/crates/bevy_utils/src/short_names.rs
|
//! <https://github.com/bevyengine/bevy/blob/main/crates/bevy_utils/src/short_names.rs>
|
||||||
|
|
||||||
use std::any::type_name;
|
use std::any::type_name;
|
||||||
|
|
||||||
|
|
|
@ -500,6 +500,12 @@ impl<'lua> MultiValue<'lua> {
|
||||||
pub trait IntoLuaMulti<'lua> {
|
pub trait IntoLuaMulti<'lua> {
|
||||||
/// Performs the conversion.
|
/// Performs the conversion.
|
||||||
fn into_lua_multi(self, lua: &'lua Lua) -> Result<MultiValue<'lua>>;
|
fn into_lua_multi(self, lua: &'lua Lua) -> Result<MultiValue<'lua>>;
|
||||||
|
|
||||||
|
/// The exact length of the [`MultiValue`] produced by [`IntoLuaMulti::into_lua_multi`], if known.
|
||||||
|
#[inline(always)]
|
||||||
|
fn lua_multi_len(&self) -> Option<usize> {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait for types that can be created from an arbitrary number of Lua values.
|
/// Trait for types that can be created from an arbitrary number of Lua values.
|
||||||
|
|
|
@ -92,7 +92,7 @@ fn test_c_function() -> Result<()> {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
let func = unsafe { lua.create_c_function(c_function)? };
|
let func = unsafe { lua.create_c_function(c_function, None)? };
|
||||||
func.call(())?;
|
func.call(())?;
|
||||||
assert_eq!(lua.globals().get::<_, bool>("c_function")?, true);
|
assert_eq!(lua.globals().get::<_, bool>("c_function")?, true);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue