Initial Luau support

This commit is contained in:
Alex Orlenko 2022-02-19 14:15:15 +00:00
parent 6dc127f4eb
commit c322e028e2
No known key found for this signature in database
GPG Key ID: 4C150C250863B96D
28 changed files with 762 additions and 228 deletions

View File

@ -9,7 +9,7 @@ jobs:
matrix: matrix:
os: [ubuntu-20.04, macos-latest, windows-latest] os: [ubuntu-20.04, macos-latest, windows-latest]
rust: [stable] rust: [stable]
lua: [lua54, lua53, lua52, lua51, luajit] lua: [lua54, lua53, lua52, lua51, luajit, luau]
include: include:
- os: ubuntu-20.04 - os: ubuntu-20.04
target: x86_64-unknown-linux-gnu target: x86_64-unknown-linux-gnu
@ -108,7 +108,7 @@ jobs:
matrix: matrix:
os: [ubuntu-20.04, macos-latest, windows-latest] os: [ubuntu-20.04, macos-latest, windows-latest]
rust: [stable, nightly] rust: [stable, nightly]
lua: [lua54, lua53, lua52, lua51, luajit, luajit52] lua: [lua54, lua53, lua52, lua51, luajit, luajit52, luau]
include: include:
- os: ubuntu-20.04 - os: ubuntu-20.04
target: x86_64-unknown-linux-gnu target: x86_64-unknown-linux-gnu
@ -144,7 +144,7 @@ jobs:
matrix: matrix:
os: [ubuntu-20.04] os: [ubuntu-20.04]
rust: [nightly] rust: [nightly]
lua: [lua54, lua53, lua52, lua51, luajit] lua: [lua54, lua53, lua52, lua51, luajit, luau]
include: include:
- os: ubuntu-20.04 - os: ubuntu-20.04
target: x86_64-unknown-linux-gnu target: x86_64-unknown-linux-gnu
@ -228,7 +228,7 @@ jobs:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
strategy: strategy:
matrix: matrix:
lua: [lua54, lua53, lua52, lua51, luajit] lua: [lua54, lua53, lua52, lua51, luajit, luau]
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1

View File

@ -34,7 +34,7 @@ lua52 = []
lua51 = [] lua51 = []
luajit = [] luajit = []
luajit52 = ["luajit"] luajit52 = ["luajit"]
luau = ["luau-src"] luau = ["luau0-src"]
vendored = ["lua-src", "luajit-src"] vendored = ["lua-src", "luajit-src"]
module = ["mlua_derive"] module = ["mlua_derive"]
async = ["futures-core", "futures-task", "futures-util"] async = ["futures-core", "futures-task", "futures-util"]
@ -59,7 +59,7 @@ cc = { version = "1.0" }
pkg-config = { version = "0.3.17" } pkg-config = { version = "0.3.17" }
lua-src = { version = ">= 540.0.0, < 550.0.0", optional = true } lua-src = { version = ">= 540.0.0, < 550.0.0", optional = true }
luajit-src = { version = ">= 210.3.1, < 220.0.0", optional = true } luajit-src = { version = ">= 210.3.1, < 220.0.0", optional = true }
luau-src = { version = "1", optional = true } luau0-src = { version = "1", optional = true, git = "https://github.com/khvzak/luau-src-rs.git" }
[dev-dependencies] [dev-dependencies]
rustyline = "9.0" rustyline = "9.0"

View File

@ -18,7 +18,7 @@ pub fn probe_lua() -> Option<PathBuf> {
builder.build() builder.build()
}; };
#[cfg(feature = "luau")] #[cfg(feature = "luau")]
let artifacts = luau_src::Build::new().build(); let artifacts = luau0_src::Build::new().build();
#[cfg(not(feature = "module"))] #[cfg(not(feature = "module"))]
artifacts.print_cargo_metadata(); artifacts.print_cargo_metadata();

View File

@ -17,6 +17,9 @@ use super::lua52::*;
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit"))]
use super::lua51::*; use super::lua51::*;
#[cfg(feature = "luau")]
use super::luau::*;
unsafe fn compat53_reverse(L: *mut lua_State, mut a: c_int, mut b: c_int) { unsafe fn compat53_reverse(L: *mut lua_State, mut a: c_int, mut b: c_int) {
while a < b { while a < b {
lua_pushvalue(L, a); lua_pushvalue(L, a);
@ -31,6 +34,7 @@ unsafe fn compat53_reverse(L: *mut lua_State, mut a: c_int, mut b: c_int) {
const COMPAT53_LEVELS1: c_int = 12; // size of the first part of the stack const COMPAT53_LEVELS1: c_int = 12; // size of the first part of the stack
const COMPAT53_LEVELS2: c_int = 10; // size of the second part of the stack const COMPAT53_LEVELS2: c_int = 10; // size of the second part of the stack
#[cfg(not(feature = "luau"))]
unsafe fn compat53_countlevels(L: *mut lua_State) -> c_int { unsafe fn compat53_countlevels(L: *mut lua_State) -> c_int {
let mut ar: lua_Debug = mem::zeroed(); let mut ar: lua_Debug = mem::zeroed();
let (mut li, mut le) = (1, 1); let (mut li, mut le) = (1, 1);
@ -51,6 +55,27 @@ unsafe fn compat53_countlevels(L: *mut lua_State) -> c_int {
le - 1 le - 1
} }
#[cfg(feature = "luau")]
unsafe fn compat53_countlevels(L: *mut lua_State) -> c_int {
let mut ar: lua_Debug = mem::zeroed();
let (mut li, mut le) = (1, 1);
// find an upper bound
while lua_getinfo(L, le, cstr!(""), &mut ar) != 0 {
li = le;
le *= 2;
}
// do a binary search
while li < le {
let m = (li + le) / 2;
if lua_getinfo(L, m, cstr!(""), &mut ar) != 0 {
li = m + 1;
} else {
le = m;
}
}
le - 1
}
unsafe fn compat53_checkmode( unsafe fn compat53_checkmode(
L: *mut lua_State, L: *mut lua_State,
mode: *const c_char, mode: *const c_char,
@ -81,7 +106,7 @@ unsafe fn compat53_checkmode(
LUA_OK LUA_OK
} }
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
unsafe fn compat53_findfield(L: *mut lua_State, objidx: c_int, level: c_int) -> c_int { unsafe fn compat53_findfield(L: *mut lua_State, objidx: c_int, level: c_int) -> 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
@ -110,10 +135,18 @@ unsafe fn compat53_findfield(L: *mut lua_State, objidx: c_int, level: c_int) ->
return 0; // not found return 0; // not found
} }
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
unsafe fn compat53_pushglobalfuncname(L: *mut lua_State, ar: *mut lua_Debug) -> c_int { unsafe fn compat53_pushglobalfuncname(
L: *mut lua_State,
level: c_int,
ar: *mut lua_Debug,
) -> c_int {
let top = lua_gettop(L); let top = lua_gettop(L);
lua_getinfo(L, cstr!("f"), ar); // push function // push function
#[cfg(not(feature = "luau"))]
lua_getinfo(L, cstr!("f"), ar);
#[cfg(feature = "luau")]
lua_getinfo(L, level, cstr!("f"), ar);
lua_pushvalue(L, LUA_GLOBALSINDEX); lua_pushvalue(L, LUA_GLOBALSINDEX);
if compat53_findfield(L, top + 1, 2) != 0 { if compat53_findfield(L, top + 1, 2) != 0 {
lua_copy(L, -1, top + 1); // move name to proper place lua_copy(L, -1, top + 1); // move name to proper place
@ -125,6 +158,34 @@ unsafe fn compat53_pushglobalfuncname(L: *mut lua_State, ar: *mut lua_Debug) ->
} }
} }
#[cfg(feature = "luau")]
unsafe fn compat53_pushfuncname(L: *mut lua_State, level: c_int, ar: *mut lua_Debug) {
/*
if *(*ar).namewhat != b'\0' as c_char {
// is there a name?
lua_pushfstring(L, cstr!("function '%s'"), (*ar).name);
} else
*/
if *(*ar).what == b'm' as c_char {
// main?
lua_pushliteral(L, "main chunk");
} else if *(*ar).what == b'C' as c_char {
if compat53_pushglobalfuncname(L, level, ar) != 0 {
lua_pushfstring(L, cstr!("function '%s'"), lua_tostring(L, -1));
lua_remove(L, -2); // remove name
} else {
lua_pushliteral(L, "?");
}
} else {
lua_pushfstring(
L,
cstr!("function <%s:%d>"),
(*ar).short_src.as_ptr(),
(*ar).linedefined,
);
}
}
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit"))]
unsafe fn compat53_pushfuncname(L: *mut lua_State, ar: *mut lua_Debug) { unsafe fn compat53_pushfuncname(L: *mut lua_State, ar: *mut lua_Debug) {
if *(*ar).namewhat != b'\0' as c_char { if *(*ar).namewhat != b'\0' as c_char {
@ -134,7 +195,7 @@ unsafe fn compat53_pushfuncname(L: *mut lua_State, ar: *mut lua_Debug) {
// main? // main?
lua_pushliteral(L, "main chunk"); lua_pushliteral(L, "main chunk");
} else if *(*ar).what == b'C' as c_char { } else if *(*ar).what == b'C' as c_char {
if compat53_pushglobalfuncname(L, ar) != 0 { if compat53_pushglobalfuncname(L, -1, 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
} else { } else {
@ -184,22 +245,22 @@ pub unsafe fn lua_absindex(L: *mut lua_State, mut idx: c_int) -> c_int {
} }
// Comparison and arithmetic functions // Comparison and arithmetic functions
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
pub const LUA_OPADD: c_int = 0; pub const LUA_OPADD: c_int = 0;
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
pub const LUA_OPSUB: c_int = 1; pub const LUA_OPSUB: c_int = 1;
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
pub const LUA_OPMUL: c_int = 2; pub const LUA_OPMUL: c_int = 2;
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
pub const LUA_OPDIV: c_int = 3; pub const LUA_OPDIV: c_int = 3;
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
pub const LUA_OPMOD: c_int = 4; pub const LUA_OPMOD: c_int = 4;
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
pub const LUA_OPPOW: c_int = 5; pub const LUA_OPPOW: c_int = 5;
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
pub const LUA_OPUNM: c_int = 6; pub const LUA_OPUNM: c_int = 6;
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
static COMPAT53_ARITH_CODE: &str = r#" static COMPAT53_ARITH_CODE: &str = r#"
local op,a,b = ... local op,a,b = ...
if op == 0 then return a+b if op == 0 then return a+b
@ -212,7 +273,7 @@ elseif op == 6 then return -a
end end
"#; "#;
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
pub unsafe fn lua_arith(L: *mut lua_State, op: c_int) { pub unsafe fn lua_arith(L: *mut lua_State, op: c_int) {
#[allow(clippy::manual_range_contains)] #[allow(clippy::manual_range_contains)]
if op < LUA_OPADD || op > LUA_OPUNM { if op < LUA_OPADD || op > LUA_OPUNM {
@ -242,7 +303,7 @@ pub unsafe fn lua_rotate(L: *mut lua_State, mut idx: c_int, mut n: c_int) {
} }
} }
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
#[inline(always)] #[inline(always)]
pub unsafe fn lua_copy(L: *mut lua_State, fromidx: c_int, toidx: c_int) { pub unsafe fn lua_copy(L: *mut lua_State, fromidx: c_int, toidx: c_int) {
let abs_to = lua_absindex(L, toidx); let abs_to = lua_absindex(L, toidx);
@ -263,6 +324,12 @@ pub unsafe fn lua_isinteger(L: *mut lua_State, idx: c_int) -> c_int {
return 0; return 0;
} }
#[cfg(any(
feature = "lua52",
feature = "lua51",
feature = "luajit",
feature = "luau"
))]
#[inline(always)] #[inline(always)]
pub unsafe fn lua_tointeger(L: *mut lua_State, i: c_int) -> lua_Integer { pub unsafe fn lua_tointeger(L: *mut lua_State, i: c_int) -> lua_Integer {
lua_tointegerx(L, i, ptr::null_mut()) lua_tointegerx(L, i, ptr::null_mut())
@ -284,6 +351,12 @@ pub unsafe fn lua_tonumberx(L: *mut lua_State, i: c_int, isnum: *mut c_int) -> l
// Implemented for Lua 5.2 as well // Implemented for Lua 5.2 as well
// See https://github.com/keplerproject/lua-compat-5.3/issues/40 // See https://github.com/keplerproject/lua-compat-5.3/issues/40
#[cfg(any(
feature = "lua52",
feature = "lua51",
feature = "luajit",
feature = "luau"
))]
#[inline(always)] #[inline(always)]
pub unsafe fn lua_tointegerx(L: *mut lua_State, i: c_int, isnum: *mut c_int) -> lua_Integer { pub unsafe fn lua_tointegerx(L: *mut lua_State, i: c_int, isnum: *mut c_int) -> lua_Integer {
let mut ok = 0; let mut ok = 0;
@ -301,20 +374,20 @@ pub unsafe fn lua_tointegerx(L: *mut lua_State, i: c_int, isnum: *mut c_int) ->
return 0; return 0;
} }
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
#[inline(always)] #[inline(always)]
pub unsafe fn lua_rawlen(L: *mut lua_State, idx: c_int) -> usize { pub unsafe fn lua_rawlen(L: *mut lua_State, idx: c_int) -> usize {
lua_objlen(L, idx) lua_objlen(L, idx)
} }
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
pub const LUA_OPEQ: c_int = 0; pub const LUA_OPEQ: c_int = 0;
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
pub const LUA_OPLT: c_int = 1; pub const LUA_OPLT: c_int = 1;
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
pub const LUA_OPLE: c_int = 2; pub const LUA_OPLE: c_int = 2;
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
#[inline(always)] #[inline(always)]
pub unsafe fn lua_compare(L: *mut lua_State, mut idx1: c_int, mut idx2: c_int, op: c_int) -> c_int { pub unsafe fn lua_compare(L: *mut lua_State, mut idx1: c_int, mut idx2: c_int, op: c_int) -> c_int {
match op { match op {
@ -335,7 +408,7 @@ pub unsafe fn lua_compare(L: *mut lua_State, mut idx1: c_int, mut idx2: c_int, o
} }
} }
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
#[inline(always)] #[inline(always)]
pub unsafe fn lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char { pub unsafe fn lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char {
if l == 0 { if l == 0 {
@ -356,7 +429,7 @@ pub unsafe fn lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize) ->
} }
} }
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
#[inline(always)] #[inline(always)]
pub unsafe fn lua_pushstring(L: *mut lua_State, s: *const c_char) -> *const c_char { pub unsafe fn lua_pushstring(L: *mut lua_State, s: *const c_char) -> *const c_char {
lua_pushstring_(L, s); lua_pushstring_(L, s);
@ -401,7 +474,7 @@ pub unsafe fn lua_rawgeti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_in
lua_type(L, -1) lua_type(L, -1)
} }
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
#[inline(always)] #[inline(always)]
pub unsafe fn lua_rawgetp(L: *mut lua_State, idx: c_int, p: *const c_void) -> c_int { pub unsafe fn lua_rawgetp(L: *mut lua_State, idx: c_int, p: *const c_void) -> c_int {
let abs_i = lua_absindex(L, idx); let abs_i = lua_absindex(L, idx);
@ -424,6 +497,22 @@ pub unsafe fn lua_getuservalue(L: *mut lua_State, idx: c_int) -> c_int {
lua_type(L, -1) lua_type(L, -1)
} }
#[cfg(feature = "luau")]
#[inline(always)]
pub unsafe fn lua_getuservalue(L: *mut lua_State, mut idx: c_int) -> c_int {
luaL_checkstack(L, 2, cstr!("not enough stack slots available"));
idx = lua_absindex(L, idx);
lua_pushliteral(L, "__mlua_uservalues");
lua_rawget(L, LUA_REGISTRYINDEX);
if lua_istable(L, -1) == 0 {
return LUA_TNIL;
}
lua_pushvalue(L, idx);
lua_rawget(L, -2);
lua_remove(L, -2);
lua_type(L, -1)
}
#[cfg(feature = "lua52")] #[cfg(feature = "lua52")]
#[inline(always)] #[inline(always)]
pub unsafe fn lua_getuservalue(L: *mut lua_State, idx: c_int) -> c_int { pub unsafe fn lua_getuservalue(L: *mut lua_State, idx: c_int) -> c_int {
@ -449,7 +538,7 @@ pub unsafe fn lua_rawseti(L: *mut lua_State, idx: c_int, n: lua_Integer) {
) )
} }
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
#[inline(always)] #[inline(always)]
pub unsafe fn lua_rawsetp(L: *mut lua_State, idx: c_int, p: *const c_void) { pub unsafe fn lua_rawsetp(L: *mut lua_State, idx: c_int, p: *const c_void) {
let abs_i = lua_absindex(L, idx); let abs_i = lua_absindex(L, idx);
@ -466,6 +555,34 @@ pub unsafe fn lua_setuservalue(L: *mut lua_State, idx: c_int) {
lua_setfenv(L, idx); lua_setfenv(L, idx);
} }
#[cfg(feature = "luau")]
#[inline(always)]
pub unsafe fn lua_setuservalue(L: *mut lua_State, mut idx: c_int) {
luaL_checkstack(L, 4, cstr!("not enough stack slots available"));
idx = lua_absindex(L, idx);
lua_pushliteral(L, "__mlua_uservalues");
lua_pushvalue(L, -1);
lua_rawget(L, LUA_REGISTRYINDEX);
if lua_istable(L, -1) == 0 {
lua_pop(L, 1);
lua_createtable(L, 0, 2); // main table
lua_createtable(L, 0, 1); // metatable
lua_pushliteral(L, "k");
lua_setfield(L, -2, cstr!("__mode"));
lua_setmetatable(L, -2);
lua_pushvalue(L, -2);
lua_pushvalue(L, -2);
lua_rawset(L, LUA_REGISTRYINDEX);
}
lua_replace(L, -2);
lua_pushvalue(L, idx);
lua_pushvalue(L, -3);
lua_remove(L, -4);
lua_rawset(L, -3);
lua_pop(L, 1);
}
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
#[inline(always)] #[inline(always)]
pub unsafe fn lua_dump( pub unsafe fn lua_dump(
L: *mut lua_State, L: *mut lua_State,
@ -476,7 +593,7 @@ pub unsafe fn lua_dump(
lua_dump_(L, writer, data) lua_dump_(L, writer, data)
} }
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
#[inline(always)] #[inline(always)]
pub unsafe fn lua_len(L: *mut lua_State, idx: c_int) { pub unsafe fn lua_len(L: *mut lua_State, idx: c_int) {
match lua_type(L, idx) { match lua_type(L, idx) {
@ -565,7 +682,7 @@ pub unsafe fn lua_getextraspace(L: *mut lua_State) -> *mut c_void {
return _ptr; return _ptr;
} }
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
#[inline(always)] #[inline(always)]
pub unsafe fn lua_pushglobaltable(L: *mut lua_State) { pub unsafe fn lua_pushglobaltable(L: *mut lua_State) {
lua_pushvalue(L, LUA_GLOBALSINDEX); lua_pushvalue(L, LUA_GLOBALSINDEX);
@ -575,7 +692,7 @@ pub unsafe fn lua_pushglobaltable(L: *mut lua_State) {
// lauxlib ported functions // lauxlib ported functions
// //
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
#[inline(always)] #[inline(always)]
pub unsafe fn luaL_checkstack(L: *mut lua_State, sz: c_int, msg: *const c_char) { pub unsafe fn luaL_checkstack(L: *mut lua_State, sz: c_int, msg: *const c_char) {
if lua_checkstack(L, sz + LUA_MINSTACK) == 0 { if lua_checkstack(L, sz + LUA_MINSTACK) == 0 {
@ -628,7 +745,7 @@ pub unsafe fn luaL_loadbufferx(
luaL_loadbuffer(L, buff, sz, name) luaL_loadbuffer(L, buff, sz, name)
} }
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
#[inline(always)] #[inline(always)]
pub unsafe fn luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer { pub unsafe fn luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer {
let mut isnum = 0; let mut isnum = 0;
@ -682,6 +799,46 @@ pub unsafe fn luaL_traceback(
lua_concat(L, lua_gettop(L) - top); lua_concat(L, lua_gettop(L) - top);
} }
#[cfg(feature = "luau")]
pub unsafe fn luaL_traceback(
L: *mut lua_State,
L1: *mut lua_State,
msg: *const c_char,
mut level: c_int,
) {
let mut ar: lua_Debug = mem::zeroed();
let top = lua_gettop(L);
let numlevels = compat53_countlevels(L1);
let mark = if numlevels > COMPAT53_LEVELS1 + COMPAT53_LEVELS2 {
COMPAT53_LEVELS1
} else {
0
};
if !msg.is_null() {
lua_pushfstring(L, cstr!("%s\n"), msg);
}
lua_pushliteral(L, "stack traceback:");
while lua_getinfo(L1, level, cstr!(""), &mut ar) != 0 {
level += 1;
if level == mark {
// too many levels?
lua_pushliteral(L, "\n\t..."); // add a '...'
level = numlevels - COMPAT53_LEVELS2; // and skip to last ones
} else {
lua_getinfo(L1, level - 1, cstr!("sln"), &mut ar);
lua_pushfstring(L, cstr!("\n\t%s:"), ar.short_src.as_ptr());
if ar.currentline > 0 {
lua_pushfstring(L, cstr!("%d:"), ar.currentline);
}
lua_pushliteral(L, " in ");
compat53_pushfuncname(L, level - 1, &mut ar);
lua_concat(L, lua_gettop(L) - top);
}
}
lua_concat(L, lua_gettop(L) - top);
}
pub unsafe fn luaL_tolstring(L: *mut lua_State, idx: c_int, len: *mut usize) -> *const c_char { pub unsafe fn luaL_tolstring(L: *mut lua_State, idx: c_int, len: *mut usize) -> *const c_char {
if luaL_callmeta(L, idx, cstr!("__tostring")) == 0 { if luaL_callmeta(L, idx, cstr!("__tostring")) == 0 {
let t = lua_type(L, idx); let t = lua_type(L, idx);
@ -718,7 +875,7 @@ pub unsafe fn luaL_tolstring(L: *mut lua_State, idx: c_int, len: *mut usize) ->
lua_tolstring(L, -1, len) lua_tolstring(L, -1, len)
} }
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
#[inline(always)] #[inline(always)]
pub unsafe fn luaL_setmetatable(L: *mut lua_State, tname: *const c_char) { pub unsafe fn luaL_setmetatable(L: *mut lua_State, tname: *const c_char) {
luaL_checkstack(L, 1, cstr!("not enough stack slots")); luaL_checkstack(L, 1, cstr!("not enough stack slots"));
@ -726,7 +883,7 @@ pub unsafe fn luaL_setmetatable(L: *mut lua_State, tname: *const c_char) {
lua_setmetatable(L, -2); lua_setmetatable(L, -2);
} }
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
#[inline(always)] #[inline(always)]
pub unsafe fn luaL_testudata(L: *mut lua_State, i: c_int, tname: *const c_char) -> *mut c_void { pub unsafe fn luaL_testudata(L: *mut lua_State, i: c_int, tname: *const c_char) -> *mut c_void {
let mut p = lua_touserdata(L, i); let mut p = lua_touserdata(L, i);
@ -762,7 +919,7 @@ pub unsafe fn luaL_setfuncs(L: *mut lua_State, mut l: *const luaL_Reg, nup: c_in
lua_pop(L, nup); // remove upvalues lua_pop(L, nup); // remove upvalues
} }
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
pub unsafe fn luaL_getsubtable(L: *mut lua_State, idx: c_int, fname: *const c_char) -> c_int { pub unsafe fn luaL_getsubtable(L: *mut lua_State, idx: c_int, fname: *const c_char) -> c_int {
let abs_i = lua_absindex(L, idx); let abs_i = lua_absindex(L, idx);
luaL_checkstack(L, 3, cstr!("not enough stack slots")); luaL_checkstack(L, 3, cstr!("not enough stack slots"));
@ -791,7 +948,7 @@ pub unsafe fn luaL_requiref(
lua_pop(L, 1); lua_pop(L, 1);
lua_pushcfunction(L, openf); lua_pushcfunction(L, openf);
lua_pushstring(L, modname); lua_pushstring(L, modname);
#[cfg(any(feature = "lua52", feature = "lua51"))] #[cfg(any(feature = "lua52", feature = "lua51", feature = "luau"))]
{ {
lua_call(L, 1, 1); lua_call(L, 1, 1);
lua_pushvalue(L, -1); lua_pushvalue(L, -1);
@ -803,7 +960,7 @@ pub unsafe fn luaL_requiref(
lua_getfield(L, -1, modname); lua_getfield(L, -1, modname);
} }
} }
if cfg!(any(feature = "lua52", feature = "lua51")) && glb != 0 { if cfg!(any(feature = "lua52", feature = "lua51", feature = "luau")) && glb != 0 {
lua_pushvalue(L, -1); lua_pushvalue(L, -1);
lua_setglobal(L, modname); lua_setglobal(L, modname);
} }

View File

@ -14,6 +14,9 @@ pub use super::lua52::lauxlib::*;
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit"))]
pub use super::lua51::lauxlib::*; pub use super::lua51::lauxlib::*;
#[cfg(feature = "luau")]
pub use super::luau::lauxlib::*;
#[cfg(feature = "lua52")] #[cfg(feature = "lua52")]
pub use super::compat53::{luaL_getmetafield, luaL_newmetatable, luaL_requiref, luaL_tolstring}; pub use super::compat53::{luaL_getmetafield, luaL_newmetatable, luaL_requiref, luaL_tolstring};
@ -24,6 +27,12 @@ pub use super::compat53::{
luaL_tolstring, luaL_traceback, luaL_tolstring, luaL_traceback,
}; };
#[cfg(feature = "luau")]
pub use super::compat53::{
luaL_checkstack, luaL_getmetafield, luaL_getsubtable, luaL_len, luaL_newmetatable,
luaL_requiref, luaL_setmetatable, luaL_testudata, luaL_tolstring, luaL_traceback,
};
// I believe `luaL_traceback` < 5.4 requires this much free stack to not error. // I believe `luaL_traceback` < 5.4 requires this much free stack to not error.
// 5.4 uses `luaL_Buffer` // 5.4 uses `luaL_Buffer`
pub const LUA_TRACEBACK_STACK: c_int = 11; pub const LUA_TRACEBACK_STACK: c_int = 11;

View File

@ -14,6 +14,9 @@ pub use super::lua52::lua::*;
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit"))]
pub use super::lua51::lua::*; pub use super::lua51::lua::*;
#[cfg(feature = "luau")]
pub use super::luau::lua::*;
#[cfg(feature = "lua52")] #[cfg(feature = "lua52")]
pub use super::compat53::{ pub use super::compat53::{
lua_dump, lua_getextraspace, lua_getfield, lua_getglobal, lua_geti, lua_gettable, lua_dump, lua_getextraspace, lua_getfield, lua_getglobal, lua_geti, lua_gettable,
@ -31,6 +34,14 @@ pub use super::compat53::{
lua_stringtonumber, lua_tointeger, lua_tointegerx, lua_tonumberx, lua_stringtonumber, lua_tointeger, lua_tointegerx, lua_tonumberx,
}; };
#[cfg(feature = "luau")]
pub use super::compat53::{
lua_arith, lua_compare, lua_copy, lua_getextraspace, lua_getfield, lua_getglobal, lua_geti,
lua_gettable, lua_getuservalue, lua_isinteger, lua_len, lua_pushglobaltable, lua_pushlstring,
lua_pushstring, lua_rawget, lua_rawgeti, lua_rawgetp, lua_rawlen, lua_rawseti, lua_rawsetp,
lua_rotate, lua_seti, lua_setuservalue, lua_stringtonumber, lua_tointeger, lua_tointegerx,
};
#[cfg(any(feature = "lua52", feature = "lua53", feature = "lua54",))] #[cfg(any(feature = "lua52", feature = "lua53", feature = "lua54",))]
pub const LUA_MAX_UPVALUES: c_int = 255; pub const LUA_MAX_UPVALUES: c_int = 255;
@ -40,6 +51,9 @@ pub const LUA_MAX_UPVALUES: c_int = 60;
#[cfg(all(feature = "luajit", feature = "vendored"))] #[cfg(all(feature = "luajit", feature = "vendored"))]
pub const LUA_MAX_UPVALUES: c_int = 120; pub const LUA_MAX_UPVALUES: c_int = 120;
#[cfg(feature = "luau")]
pub const LUA_MAX_UPVALUES: c_int = 200;
// //
// Lua 5.4 compatibility layer // Lua 5.4 compatibility layer
// //
@ -48,7 +62,8 @@ pub const LUA_MAX_UPVALUES: c_int = 120;
feature = "lua53", feature = "lua53",
feature = "lua52", feature = "lua52",
feature = "lua51", feature = "lua51",
feature = "luajit" feature = "luajit",
feature = "luau"
))] ))]
#[inline(always)] #[inline(always)]
pub unsafe fn lua_resume( pub unsafe fn lua_resume(
@ -62,22 +77,32 @@ pub unsafe fn lua_resume(
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit"))]
let ret = lua_resume_(L, narg); let ret = lua_resume_(L, narg);
#[cfg(any(feature = "lua53", feature = "lua52"))] #[cfg(any(feature = "lua53", feature = "lua52", feature = "luau"))]
let ret = lua_resume_(L, from, narg); let ret = lua_resume_(L, from, narg);
if ret == LUA_OK || ret == LUA_YIELD { if (ret == LUA_OK || ret == LUA_YIELD) && !(nres.is_null()) {
*nres = lua_gettop(L); *nres = lua_gettop(L);
} }
ret ret
} }
#[cfg(any(feature = "lua54", all(feature = "luajit", feature = "vendored")))] #[cfg(any(
feature = "lua54",
feature = "luau",
all(feature = "luajit", feature = "vendored")
))]
pub unsafe fn lua_resetthreadx(L: *mut lua_State, th: *mut lua_State) -> c_int { pub unsafe fn lua_resetthreadx(L: *mut lua_State, th: *mut lua_State) -> c_int {
#[cfg(all(feature = "luajit", feature = "vendored"))] #[cfg(all(feature = "luajit", feature = "vendored"))]
{ {
lua_resetthread(L, th); lua_resetthread(L, th);
LUA_OK LUA_OK
} }
#[cfg(feature = "luau")]
{
let _ = L;
lua_resetthread(th);
LUA_OK
}
#[cfg(feature = "lua54")] #[cfg(feature = "lua54")]
{ {
let _ = L; let _ = L;

View File

@ -11,3 +11,6 @@ pub use super::lua52::lualib::*;
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit"))]
pub use super::lua51::lualib::*; pub use super::lua51::lualib::*;
#[cfg(feature = "luau")]
pub use super::luau::lualib::*;

188
src/ffi/luau/lauxlib.rs Normal file
View File

@ -0,0 +1,188 @@
//! Contains definitions from `lualib.h`.
use std::alloc;
use std::ffi::CStr;
use std::os::raw::{c_char, c_float, c_int, c_void};
use std::ptr;
use super::lua::{
self, lua_CFunction, lua_Integer, lua_Number, lua_State, lua_Unsigned, LUA_ERRSYNTAX, LUA_OK,
LUA_REGISTRYINDEX,
};
use super::luacode;
#[repr(C)]
pub struct luaL_Reg {
pub name: *const c_char,
pub func: lua_CFunction,
}
extern "C" {
pub fn luaL_register(L: *mut lua_State, libname: *const c_char, l: *const luaL_Reg);
#[link_name = "luaL_getmetafield"]
pub fn luaL_getmetafield_(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int;
pub fn luaL_callmeta(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int;
#[link_name = "luaL_typeerrorL"]
pub fn luaL_typeerror(L: *mut lua_State, narg: c_int, tname: *const c_char) -> !;
#[link_name = "luaL_argerrorL"]
pub fn luaL_argerror(L: *mut lua_State, narg: c_int, extramsg: *const c_char) -> !;
pub fn luaL_checklstring(L: *mut lua_State, narg: c_int, l: *mut usize) -> *const c_char;
pub fn luaL_optlstring(
L: *mut lua_State,
narg: c_int,
def: *const c_char,
l: *mut usize,
) -> *const c_char;
pub fn luaL_checknumber(L: *mut lua_State, narg: c_int) -> lua_Number;
pub fn luaL_optnumber(L: *mut lua_State, narg: c_int, def: lua_Number) -> lua_Number;
pub fn luaL_checkboolean(L: *mut lua_State, narg: c_int) -> c_int;
pub fn luaL_optboolean(L: *mut lua_State, narg: c_int, def: c_int) -> c_int;
pub fn luaL_checkinteger(L: *mut lua_State, narg: c_int) -> lua_Integer;
pub fn luaL_optinteger(L: *mut lua_State, narg: c_int, def: lua_Integer) -> lua_Integer;
pub fn luaL_checkunsigned(L: *mut lua_State, narg: c_int) -> lua_Unsigned;
pub fn luaL_optunsigned(L: *mut lua_State, narg: c_int, def: lua_Unsigned) -> lua_Unsigned;
pub fn luaL_checkvector(L: *mut lua_State, narg: c_int) -> *const c_float;
pub fn luaL_optvector(L: *mut lua_State, narg: c_int, def: *const c_float) -> *const c_float;
#[link_name = "luaL_checkstack"]
pub fn luaL_checkstack_(L: *mut lua_State, sz: c_int, msg: *const c_char);
pub fn luaL_checktype(L: *mut lua_State, narg: c_int, t: c_int);
pub fn luaL_checkany(L: *mut lua_State, narg: c_int);
#[link_name = "luaL_newmetatable"]
pub fn luaL_newmetatable_(L: *mut lua_State, tname: *const c_char) -> c_int;
pub fn luaL_checkudata(L: *mut lua_State, ud: c_int, tname: *const c_char) -> *mut c_void;
pub fn luaL_where(L: *mut lua_State, lvl: c_int);
#[link_name = "luaL_errorL"]
pub fn luaL_error(L: *mut lua_State, fmt: *const c_char, ...) -> !;
pub fn luaL_checkoption(
L: *mut lua_State,
narg: c_int,
def: *const c_char,
lst: *const *const c_char,
) -> c_int;
#[link_name = "luaL_tolstring"]
pub fn luaL_tolstring_(L: *mut lua_State, idx: c_int, len: *mut usize) -> *const c_char;
pub fn luaL_newstate() -> *mut lua_State;
// TODO: luaL_findtable
}
//
// Some useful macros (implemented as Rust functions)
//
#[inline(always)]
pub unsafe fn luaL_argcheck(L: *mut lua_State, cond: c_int, arg: c_int, extramsg: *const c_char) {
if cond == 0 {
luaL_argerror(L, arg, extramsg);
}
}
#[inline(always)]
pub unsafe fn luaL_argexpected(L: *mut lua_State, cond: c_int, arg: c_int, tname: *const c_char) {
if cond == 0 {
luaL_typeerror(L, arg, tname);
}
}
#[inline(always)]
pub unsafe fn luaL_checkstring(L: *mut lua_State, n: c_int) -> *const c_char {
luaL_checklstring(L, n, ptr::null_mut())
}
#[inline(always)]
pub unsafe fn luaL_optstring(L: *mut lua_State, n: c_int, d: *const c_char) -> *const c_char {
luaL_optlstring(L, n, d, ptr::null_mut())
}
// TODO: luaL_opt
#[inline(always)]
pub unsafe fn luaL_typename(L: *mut lua_State, i: c_int) -> *const c_char {
lua::lua_typename(L, lua::lua_type(L, i))
}
#[inline(always)]
pub unsafe fn luaL_getmetatable(L: *mut lua_State, n: *const c_char) {
lua::lua_getfield_(L, LUA_REGISTRYINDEX, n);
}
#[inline(always)]
pub unsafe fn luaL_ref(L: *mut lua_State, t: c_int) -> c_int {
assert_eq!(t, LUA_REGISTRYINDEX);
let r = lua::lua_ref(L, -1);
lua::lua_pop(L, 1);
r
}
#[inline(always)]
pub unsafe fn luaL_unref(L: *mut lua_State, t: c_int, r#ref: c_int) {
assert_eq!(t, LUA_REGISTRYINDEX);
lua::lua_unref(L, r#ref)
}
pub unsafe fn luaL_loadbufferx(
L: *mut lua_State,
data: *const c_char,
mut size: usize,
name: *const c_char,
mode: *const c_char,
) -> c_int {
let chunk_is_text = (*data as u8) >= b'\n';
if !mode.is_null() {
let modeb = CStr::from_ptr(mode).to_bytes();
if !chunk_is_text && !modeb.contains(&b'b') {
lua::lua_pushfstring(
L,
cstr!("attempt to load a binary chunk (mode is '%s')"),
mode,
);
return LUA_ERRSYNTAX;
} else if chunk_is_text && !modeb.contains(&b't') {
lua::lua_pushfstring(
L,
cstr!("attempt to load a text chunk (mode is '%s')"),
mode,
);
return LUA_ERRSYNTAX;
}
}
if chunk_is_text {
let data = luacode::luau_compile(data, size, ptr::null_mut(), &mut size);
let layout = alloc::Layout::from_size_align_unchecked(size, super::super::SYS_MIN_ALIGN);
let ok = lua::luau_load(L, name, data, size, 0) == 0;
alloc::dealloc(data as *mut u8, layout);
if !ok {
return LUA_ERRSYNTAX;
}
} else {
if lua::luau_load(L, name, data, size, 0) != 0 {
return LUA_ERRSYNTAX;
}
}
LUA_OK
}
#[inline(always)]
pub unsafe fn luaL_loadbuffer(
L: *mut lua_State,
data: *const c_char,
size: usize,
name: *const c_char,
) -> c_int {
luaL_loadbufferx(L, data, size, name, ptr::null())
}
//
// TODO: Generic Buffer Manipulation
//

View File

@ -69,6 +69,9 @@ pub type lua_Unsigned = c_uint;
pub type lua_CFunction = unsafe extern "C" fn(L: *mut lua_State) -> c_int; pub type lua_CFunction = unsafe extern "C" fn(L: *mut lua_State) -> c_int;
pub type lua_Continuation = unsafe extern "C" fn(L: *mut lua_State, status: c_int) -> c_int; pub type lua_Continuation = unsafe extern "C" fn(L: *mut lua_State, status: c_int) -> c_int;
/// Type for userdata destructor functions.
pub type lua_Udestructor = unsafe extern "C" fn(*mut c_void);
/// Type for memory-allocation functions. /// Type for memory-allocation functions.
pub type lua_Alloc = unsafe extern "C" fn( pub type lua_Alloc = unsafe extern "C" fn(
L: *mut lua_State, L: *mut lua_State,
@ -121,14 +124,15 @@ extern "C" {
pub fn lua_lessthan(L: *mut lua_State, idx1: c_int, idx2: c_int) -> c_int; pub fn lua_lessthan(L: *mut lua_State, idx1: c_int, idx2: c_int) -> c_int;
pub fn lua_tonumberx(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Number; pub fn lua_tonumberx(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Number;
pub fn lua_tointegerx(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Integer; #[link_name = "lua_tointegerx"]
pub fn lua_tointegerx_(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Integer;
pub fn lua_tounsignedx(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Unsigned; pub fn lua_tounsignedx(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Unsigned;
pub fn lua_tovector(L: *mut lua_State, idx: c_int) -> *const c_float; pub fn lua_tovector(L: *mut lua_State, idx: c_int) -> *const c_float;
pub fn lua_toboolean(L: *mut lua_State, idx: c_int) -> c_int; pub fn lua_toboolean(L: *mut lua_State, idx: c_int) -> c_int;
pub fn lua_tolstring(L: *mut lua_State, idx: c_int, len: *mut usize) -> *const c_char; pub fn lua_tolstring(L: *mut lua_State, idx: c_int, len: *mut usize) -> *const c_char;
pub fn lua_tostringatom(L: *mut lua_State, idx: c_int, atom: *mut c_int) -> *const c_char; pub fn lua_tostringatom(L: *mut lua_State, idx: c_int, atom: *mut c_int) -> *const c_char;
pub fn lua_namecallatom(L: *mut lua_State, atom: *mut c_int) -> *const c_char; pub fn lua_namecallatom(L: *mut lua_State, atom: *mut c_int) -> *const c_char;
pub fn lua_objlen(L: *mut lua_State, idx: c_int) -> c_int; pub fn lua_objlen(L: *mut lua_State, idx: c_int) -> usize;
pub fn lua_tocfunction(L: *mut lua_State, idx: c_int) -> Option<lua_CFunction>; pub fn lua_tocfunction(L: *mut lua_State, idx: c_int) -> Option<lua_CFunction>;
pub fn lua_touserdata(L: *mut lua_State, idx: c_int) -> *mut c_void; pub fn lua_touserdata(L: *mut lua_State, idx: c_int) -> *mut c_void;
pub fn lua_touserdatatagged(L: *mut lua_State, idx: c_int, tag: c_int) -> *mut c_void; pub fn lua_touserdatatagged(L: *mut lua_State, idx: c_int, tag: c_int) -> *mut c_void;
@ -144,8 +148,10 @@ extern "C" {
pub fn lua_pushinteger(L: *mut lua_State, n: lua_Integer); pub fn lua_pushinteger(L: *mut lua_State, n: lua_Integer);
pub fn lua_pushunsigned(L: *mut lua_State, n: lua_Unsigned); pub fn lua_pushunsigned(L: *mut lua_State, n: lua_Unsigned);
pub fn lua_pushvector(L: *mut lua_State, x: c_float, y: c_float, z: c_float); pub fn lua_pushvector(L: *mut lua_State, x: c_float, y: c_float, z: c_float);
pub fn lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize); #[link_name = "lua_pushlstring"]
pub fn lua_pushstring(L: *mut lua_State, s: *const c_char); pub fn lua_pushlstring_(L: *mut lua_State, s: *const c_char, l: usize);
#[link_name = "lua_pushstring"]
pub fn lua_pushstring_(L: *mut lua_State, s: *const c_char);
// lua_pushvfstring // lua_pushvfstring
#[link_name = "lua_pushfstringL"] #[link_name = "lua_pushfstringL"]
pub fn lua_pushfstring(L: *mut lua_State, fmt: *const c_char, ...) -> *const c_char; pub fn lua_pushfstring(L: *mut lua_State, fmt: *const c_char, ...) -> *const c_char;
@ -163,11 +169,15 @@ extern "C" {
// //
// Get functions (Lua -> stack) // Get functions (Lua -> stack)
// //
pub fn lua_gettable(L: *mut lua_State, idx: c_int); #[link_name = "lua_gettable"]
pub fn lua_getfield(L: *mut lua_State, idx: c_int, k: *const c_char); pub fn lua_gettable_(L: *mut lua_State, idx: c_int);
#[link_name = "lua_getfield"]
pub fn lua_getfield_(L: *mut lua_State, idx: c_int, k: *const c_char);
pub fn lua_rawgetfield(L: *mut lua_State, idx: c_int, k: *const c_char); pub fn lua_rawgetfield(L: *mut lua_State, idx: c_int, k: *const c_char);
pub fn lua_rawget(L: *mut lua_State, idx: c_int); #[link_name = "lua_rawget"]
pub fn lua_rawgeti(L: *mut lua_State, idx: c_int, n: c_int); pub fn lua_rawget_(L: *mut lua_State, idx: c_int);
#[link_name = "lua_rawgeti"]
pub fn lua_rawgeti_(L: *mut lua_State, idx: c_int, n: c_int);
pub fn lua_createtable(L: *mut lua_State, narr: c_int, nrec: c_int); pub fn lua_createtable(L: *mut lua_State, narr: c_int, nrec: c_int);
pub fn lua_setreadonly(L: *mut lua_State, idx: c_int, enabled: c_int); pub fn lua_setreadonly(L: *mut lua_State, idx: c_int, enabled: c_int);
@ -175,7 +185,7 @@ extern "C" {
pub fn lua_setsafeenv(L: *mut lua_State, idx: c_int, enabled: c_int); pub fn lua_setsafeenv(L: *mut lua_State, idx: c_int, enabled: c_int);
pub fn lua_newuserdatatagged(L: *mut lua_State, sz: usize, tag: c_int) -> *mut c_void; pub fn lua_newuserdatatagged(L: *mut lua_State, sz: usize, tag: c_int) -> *mut c_void;
pub fn lua_newuserdatadtor(L: *mut lua_State, sz: usize, dtor: fn(*mut c_void)); pub fn lua_newuserdatadtor(L: *mut lua_State, sz: usize, dtor: lua_Udestructor) -> *mut c_void;
pub fn lua_getmetatable(L: *mut lua_State, objindex: c_int) -> c_int; pub fn lua_getmetatable(L: *mut lua_State, objindex: c_int) -> c_int;
pub fn lua_getfenv(L: *mut lua_State, idx: c_int); pub fn lua_getfenv(L: *mut lua_State, idx: c_int);
@ -185,7 +195,8 @@ extern "C" {
pub fn lua_settable(L: *mut lua_State, idx: c_int); pub fn lua_settable(L: *mut lua_State, idx: c_int);
pub fn lua_setfield(L: *mut lua_State, idx: c_int, k: *const c_char); pub fn lua_setfield(L: *mut lua_State, idx: c_int, k: *const c_char);
pub fn lua_rawset(L: *mut lua_State, idx: c_int); pub fn lua_rawset(L: *mut lua_State, idx: c_int);
pub fn lua_rawseti(L: *mut lua_State, idx: c_int, n: c_int); #[link_name = "lua_rawseti"]
pub fn lua_rawseti_(L: *mut lua_State, idx: c_int, n: c_int);
pub fn lua_setmetatable(L: *mut lua_State, objindex: c_int) -> c_int; pub fn lua_setmetatable(L: *mut lua_State, objindex: c_int) -> c_int;
pub fn lua_setfenv(L: *mut lua_State, idx: c_int) -> c_int; pub fn lua_setfenv(L: *mut lua_State, idx: c_int) -> c_int;
@ -207,7 +218,8 @@ extern "C" {
// //
pub fn lua_yield(L: *mut lua_State, nresults: c_int) -> c_int; pub fn lua_yield(L: *mut lua_State, nresults: c_int) -> c_int;
pub fn lua_break(L: *mut lua_State) -> c_int; pub fn lua_break(L: *mut lua_State) -> c_int;
pub fn lua_resume(L: *mut lua_State, from: *mut lua_State, narg: c_int) -> c_int; #[link_name = "lua_resume"]
pub fn lua_resume_(L: *mut lua_State, from: *mut lua_State, narg: c_int) -> c_int;
pub fn lua_resumeerror(L: *mut lua_State, from: *mut lua_State) -> c_int; pub fn lua_resumeerror(L: *mut lua_State, from: *mut lua_State) -> c_int;
pub fn lua_status(L: *mut lua_State) -> c_int; pub fn lua_status(L: *mut lua_State) -> c_int;
pub fn lua_isyieldable(L: *mut lua_State) -> c_int; pub fn lua_isyieldable(L: *mut lua_State) -> c_int;
@ -241,7 +253,7 @@ extern "C" {
pub fn lua_next(L: *mut lua_State, idx: c_int) -> c_int; pub fn lua_next(L: *mut lua_State, idx: c_int) -> c_int;
pub fn lua_concat(L: *mut lua_State, n: c_int); pub fn lua_concat(L: *mut lua_State, n: c_int);
// TODO: lua_encodepointer, lua_clock // TODO: lua_encodepointer, lua_clock
pub fn lua_setuserdatadtor(L: *mut lua_State, tag: c_int, dtor: fn(*mut c_void)); pub fn lua_setuserdatadtor(L: *mut lua_State, tag: c_int, dtor: Option<lua_Udestructor>);
} }
// //
@ -258,14 +270,15 @@ extern "C" {
// //
// Some useful macros (implemented as Rust functions) // Some useful macros (implemented as Rust functions)
// //
#[inline(always)] #[inline(always)]
pub unsafe fn lua_tonumber(L: *mut lua_State, i: c_int) -> lua_Number { pub unsafe fn lua_tonumber(L: *mut lua_State, i: c_int) -> lua_Number {
lua_tonumberx(L, i, ptr::null_mut()) lua_tonumberx(L, i, ptr::null_mut())
} }
#[inline(always)] #[inline(always)]
pub unsafe fn lua_tointeger(L: *mut lua_State, i: c_int) -> lua_Integer { pub unsafe fn lua_tointeger_(L: *mut lua_State, i: c_int) -> lua_Integer {
lua_tointegerx(L, i, ptr::null_mut()) lua_tointegerx_(L, i, ptr::null_mut())
} }
#[inline(always)] #[inline(always)]
@ -339,14 +352,22 @@ pub unsafe fn lua_isnoneornil(L: *mut lua_State, n: c_int) -> c_int {
pub unsafe fn lua_pushliteral(L: *mut lua_State, s: &'static str) { pub unsafe fn lua_pushliteral(L: *mut lua_State, s: &'static str) {
use std::ffi::CString; use std::ffi::CString;
let c_str = CString::new(s).unwrap(); let c_str = CString::new(s).unwrap();
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, debugname: *const c_char) { pub unsafe fn lua_pushcfunction(L: *mut lua_State, f: lua_CFunction) {
lua_pushcclosurek(L, f, ptr::null(), 0, None)
}
pub unsafe fn lua_pushcfunctiond(L: *mut lua_State, f: lua_CFunction, debugname: *const c_char) {
lua_pushcclosurek(L, f, debugname, 0, None) 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, debugname: *const c_char,
@ -361,8 +382,8 @@ pub unsafe fn lua_setglobal(L: *mut lua_State, var: *const c_char) {
} }
#[inline(always)] #[inline(always)]
pub unsafe fn lua_getglobal(L: *mut lua_State, var: *const c_char) { pub unsafe fn lua_getglobal_(L: *mut lua_State, var: *const c_char) {
lua_getfield(L, LUA_GLOBALSINDEX, var) lua_getfield_(L, LUA_GLOBALSINDEX, var)
} }
#[inline(always)] #[inline(always)]

22
src/ffi/luau/luacode.rs Normal file
View File

@ -0,0 +1,22 @@
//! Contains definitions from `luacode.h`.
use std::os::raw::{c_char, c_int};
#[repr(C)]
pub struct lua_CompileOptions {
pub optimizationLevel: c_int,
pub debugLevel: c_int,
pub coverageLevel: c_int,
pub vectorLib: *const c_char,
pub vectorCtor: *const c_char,
pub mutableGlobals: *mut *const c_char,
}
extern "C" {
pub fn luau_compile(
source: *const c_char,
size: usize,
options: *mut lua_CompileOptions,
outsize: *mut usize,
) -> *mut c_char;
}

View File

@ -1,88 +1,8 @@
//! Contains definitions from `lualib.h`. //! Contains definitions from `lualib.h`.
use std::os::raw::{c_char, c_float, c_int, c_void}; use std::os::raw::c_int;
use super::lua::{ use super::lua::lua_State;
lua_CFunction, lua_Integer, lua_Number, lua_State, lua_Unsigned, lua_getfield,
LUA_REGISTRYINDEX,
};
#[repr(C)]
pub struct luaL_Reg {
pub name: *const c_char,
pub func: lua_CFunction,
}
extern "C" {
pub fn luaL_register(L: *mut lua_State, libname: *const c_char, l: *const luaL_Reg);
pub fn luaL_getmetafield(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int;
pub fn luaL_callmeta(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int;
// TODO: luaL_typeerrorL, luaL_argerrorL
pub fn luaL_checklstring(L: *mut lua_State, narg: c_int, l: *mut usize) -> *const c_char;
pub fn luaL_optlstring(
L: *mut lua_State,
narg: c_int,
def: *const c_char,
l: *mut usize,
) -> *const c_char;
pub fn luaL_checknumber(L: *mut lua_State, narg: c_int) -> lua_Number;
pub fn luaL_optnumber(L: *mut lua_State, narg: c_int, def: lua_Number) -> lua_Number;
pub fn luaL_checkboolean(L: *mut lua_State, narg: c_int) -> c_int;
pub fn luaL_optboolean(L: *mut lua_State, narg: c_int, def: c_int) -> c_int;
pub fn luaL_checkinteger(L: *mut lua_State, narg: c_int) -> lua_Integer;
pub fn luaL_optinteger(L: *mut lua_State, narg: c_int, def: lua_Integer) -> lua_Integer;
pub fn luaL_checkunsigned(L: *mut lua_State, narg: c_int) -> lua_Unsigned;
pub fn luaL_optunsigned(L: *mut lua_State, narg: c_int, def: lua_Unsigned) -> lua_Unsigned;
pub fn luaL_checkvector(L: *mut lua_State, narg: c_int) -> *const c_float;
pub fn luaL_optvector(L: *mut lua_State, narg: c_int, def: *const c_float) -> *const c_float;
pub fn luaL_checkstack(L: *mut lua_State, sz: c_int, msg: *const c_char);
pub fn luaL_checktype(L: *mut lua_State, narg: c_int, t: c_int);
pub fn luaL_checkany(L: *mut lua_State, narg: c_int);
pub fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_int;
pub fn luaL_checkudata(L: *mut lua_State, ud: c_int, tname: *const c_char) -> *mut c_void;
pub fn luaL_where(L: *mut lua_State, lvl: c_int);
#[link_name = "luaL_errorL"]
pub fn luaL_error(L: *mut lua_State, fmt: *const c_char, ...) -> !;
pub fn luaL_checkoption(
L: *mut lua_State,
narg: c_int,
def: *const c_char,
lst: *const *const c_char,
) -> c_int;
pub fn luaL_tolstring(L: *mut lua_State, idx: c_int, len: *mut usize) -> *const c_char;
pub fn luaL_newstate() -> *mut lua_State;
// TODO: luaL_findtable
}
//
// Some useful macros (implemented as Rust functions)
//
// TODO: luaL_argcheck, luaL_argexpected, luaL_checkstring, luaL_optstring, luaL_typename, luaL_opt
#[inline(always)]
pub unsafe fn luaL_getmetatable(L: *mut lua_State, n: *const c_char) {
lua_getfield(L, LUA_REGISTRYINDEX, n);
}
//
// TODO: Generic Buffer Manipulation
//
//
// Builtin libraries
//
pub const LUA_COLIBNAME: &str = "coroutine"; pub const LUA_COLIBNAME: &str = "coroutine";
pub const LUA_TABLIBNAME: &str = "table"; pub const LUA_TABLIBNAME: &str = "table";

View File

@ -1,7 +1,11 @@
//! Low level bindings to Luau. //! Low level bindings to Luau.
pub use self::lauxlib::*;
pub use self::lua::*; pub use self::lua::*;
pub use self::luacode::*;
pub use self::lualib::*; pub use self::lualib::*;
pub mod lauxlib;
pub mod lua; pub mod lua;
pub mod luacode;
pub mod lualib; pub mod lualib;

View File

@ -42,6 +42,7 @@ pub const SYS_MIN_ALIGN: usize = 4;
// Hack to avoid stripping a few unused Lua symbols that could be imported // Hack to avoid stripping a few unused Lua symbols that could be imported
// by C modules in unsafe mode // by C modules in unsafe mode
#[cfg(not(feature = "luau"))]
pub(crate) fn keep_lua_symbols() { pub(crate) fn keep_lua_symbols() {
let mut symbols: Vec<*const extern "C" fn()> = Vec::new(); let mut symbols: Vec<*const extern "C" fn()> = Vec::new();
symbols.push(lua_atpanic as _); symbols.push(lua_atpanic as _);
@ -59,14 +60,25 @@ mod lauxlib;
mod lua; mod lua;
mod lualib; mod lualib;
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))] #[cfg(any(
feature = "lua52",
feature = "lua51",
feature = "luajit",
feature = "luau"
))]
mod compat53; mod compat53;
#[cfg(feature = "lua54")]
pub mod lua54;
#[cfg(feature = "lua53")]
pub mod lua53;
#[cfg(feature = "lua52")]
pub mod lua52;
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit"))]
pub mod lua51; pub mod lua51;
#[cfg(feature = "lua52")]
pub mod lua52; #[cfg(feature = "luau")]
#[cfg(feature = "lua53")] pub mod luau;
pub mod lua53;
#[cfg(feature = "lua54")]
pub mod lua54;

View File

@ -1,6 +1,5 @@
use std::os::raw::{c_int, c_void}; use std::os::raw::c_int;
use std::ptr; use std::ptr;
use std::slice;
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::ffi; use crate::ffi;
@ -214,7 +213,11 @@ impl<'lua> Function<'lua> {
/// ///
/// 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
/// about the function, to save space. /// about the function, to save space.
#[cfg(not(feature = "luau"))]
pub fn dump(&self, strip: bool) -> Vec<u8> { pub fn dump(&self, strip: bool) -> Vec<u8> {
use std::os::raw::c_void;
use std::slice;
unsafe extern "C" fn writer( unsafe extern "C" fn writer(
_state: *mut ffi::lua_State, _state: *mut ffi::lua_State,
buf: *const c_void, buf: *const c_void,

View File

@ -85,6 +85,7 @@ mod conversion;
mod error; mod error;
mod ffi; mod ffi;
mod function; mod function;
#[cfg(not(feature = "luau"))]
mod hook; mod hook;
mod lua; mod lua;
mod multi; mod multi;
@ -104,6 +105,7 @@ pub use crate::{ffi::lua_CFunction, ffi::lua_State};
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;
#[cfg(not(feature = "luau"))]
pub use crate::hook::{Debug, DebugEvent, DebugNames, DebugSource, DebugStack, HookTriggers}; pub use crate::hook::{Debug, DebugEvent, DebugNames, DebugSource, DebugStack, HookTriggers};
pub use crate::lua::{AsChunk, Chunk, ChunkMode, GCMode, Lua, LuaOptions}; pub use crate::lua::{AsChunk, Chunk, ChunkMode, GCMode, Lua, LuaOptions};
pub use crate::multi::Variadic; pub use crate::multi::Variadic;

View File

@ -14,6 +14,7 @@ use rustc_hash::FxHashMap;
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::ffi; use crate::ffi;
use crate::function::Function; use crate::function::Function;
#[cfg(not(feature = "luau"))]
use crate::hook::{Debug, HookTriggers}; use crate::hook::{Debug, HookTriggers};
use crate::scope::Scope; use crate::scope::Scope;
use crate::stdlib::StdLib; use crate::stdlib::StdLib;
@ -21,8 +22,8 @@ use crate::string::String;
use crate::table::Table; use crate::table::Table;
use crate::thread::Thread; use crate::thread::Thread;
use crate::types::{ use crate::types::{
Callback, CallbackUpvalue, DestructedUserdataMT, HookCallback, Integer, LightUserData, LuaRef, Callback, CallbackUpvalue, DestructedUserdataMT, /*HookCallback,*/ Integer, LightUserData,
MaybeSend, Number, RegistryKey, LuaRef, MaybeSend, Number, RegistryKey,
}; };
use crate::userdata::{ use crate::userdata::{
AnyUserData, MetaMethod, UserData, UserDataCell, UserDataFields, UserDataMethods, AnyUserData, MetaMethod, UserData, UserDataCell, UserDataFields, UserDataMethods,
@ -35,6 +36,9 @@ use crate::util::{
}; };
use crate::value::{FromLua, FromLuaMulti, MultiValue, Nil, ToLua, ToLuaMulti, Value}; use crate::value::{FromLua, FromLuaMulti, MultiValue, Nil, ToLua, ToLuaMulti, Value};
#[cfg(not(feature = "luau"))]
use crate::types::HookCallback;
#[cfg(not(feature = "lua54"))] #[cfg(not(feature = "lua54"))]
use crate::util::push_userdata; use crate::util::push_userdata;
#[cfg(feature = "lua54")] #[cfg(feature = "lua54")]
@ -103,6 +107,7 @@ struct ExtraData {
#[cfg(feature = "async")] #[cfg(feature = "async")]
ref_waker_idx: c_int, ref_waker_idx: c_int,
#[cfg(not(feature = "luau"))]
hook_callback: Option<HookCallback>, hook_callback: Option<HookCallback>,
#[cfg(feature = "lua54")] #[cfg(feature = "lua54")]
warn_callback: Option<WarnCallback>, warn_callback: Option<WarnCallback>,
@ -310,6 +315,7 @@ impl Lua {
let mut lua = unsafe { Self::inner_new(libs, options) }; let mut lua = unsafe { Self::inner_new(libs, options) };
#[cfg(not(feature = "luau"))]
if libs.contains(StdLib::PACKAGE) { if libs.contains(StdLib::PACKAGE) {
mlua_expect!(lua.disable_c_modules(), "Error during disabling C modules"); mlua_expect!(lua.disable_c_modules(), "Error during disabling C modules");
} }
@ -328,12 +334,16 @@ impl Lua {
/// ///
/// [`StdLib`]: crate::StdLib /// [`StdLib`]: crate::StdLib
pub unsafe fn unsafe_new_with(libs: StdLib, options: LuaOptions) -> Lua { pub unsafe fn unsafe_new_with(libs: StdLib, options: LuaOptions) -> Lua {
#[cfg(not(feature = "luau"))]
ffi::keep_lua_symbols(); ffi::keep_lua_symbols();
Self::inner_new(libs, options) Self::inner_new(libs, options)
} }
unsafe fn inner_new(libs: StdLib, options: LuaOptions) -> Lua { unsafe fn inner_new(libs: StdLib, options: LuaOptions) -> Lua {
#[cfg_attr(any(feature = "lua51", feature = "luajit"), allow(dead_code))] #[cfg_attr(
any(feature = "lua51", feature = "luajit", feature = "luau"),
allow(dead_code)
)]
unsafe extern "C" fn allocator( unsafe extern "C" fn allocator(
extra_data: *mut c_void, extra_data: *mut c_void,
ptr: *mut c_void, ptr: *mut c_void,
@ -398,9 +408,14 @@ impl Lua {
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
let state = ffi::lua_newstate(allocator, mem_info as *mut c_void); let state = ffi::lua_newstate(allocator, mem_info as *mut c_void);
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
let state = ffi::luaL_newstate(); let state = ffi::luaL_newstate();
// #[cfg(feature = "luau")]
// {
// ffi::luaL_sandbox(state);
// }
ffi::luaL_requiref(state, cstr!("_G"), ffi::luaopen_base, 1); ffi::luaL_requiref(state, cstr!("_G"), ffi::luaopen_base, 1);
ffi::lua_pop(state, 1); ffi::lua_pop(state, 1);
@ -427,7 +442,7 @@ impl Lua {
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
ffi::lua_rawgeti(lua.state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS); ffi::lua_rawgeti(lua.state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS);
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
ffi::lua_pushvalue(lua.state, ffi::LUA_GLOBALSINDEX); ffi::lua_pushvalue(lua.state, ffi::LUA_GLOBALSINDEX);
ffi::lua_pushcfunction(lua.state, safe_pcall); ffi::lua_pushcfunction(lua.state, safe_pcall);
@ -447,6 +462,9 @@ impl Lua {
extra.recycled_thread_cache = Vec::with_capacity(options.thread_cache_size); extra.recycled_thread_cache = Vec::with_capacity(options.thread_cache_size);
} }
#[cfg(feature = "luau")]
mlua_expect!(lua.prepare_luau_state(), "Error preparing Luau state");
lua lua
} }
@ -534,6 +552,7 @@ impl Lua {
recycled_thread_cache: Vec::new(), recycled_thread_cache: Vec::new(),
#[cfg(feature = "async")] #[cfg(feature = "async")]
ref_waker_idx, ref_waker_idx,
#[cfg(not(feature = "luau"))]
hook_callback: None, hook_callback: None,
#[cfg(feature = "lua54")] #[cfg(feature = "lua54")]
warn_callback: None, warn_callback: None,
@ -600,10 +619,13 @@ impl Lua {
// If `package` library loaded into a safe lua state then disable C modules // If `package` library loaded into a safe lua state then disable C modules
let extra = unsafe { &mut *self.extra.get() }; let extra = unsafe { &mut *self.extra.get() };
#[cfg(not(feature = "luau"))]
{
let curr_libs = extra.libs; let curr_libs = extra.libs;
if self.safe && (curr_libs ^ (curr_libs | libs)).contains(StdLib::PACKAGE) { if self.safe && (curr_libs ^ (curr_libs | libs)).contains(StdLib::PACKAGE) {
mlua_expect!(self.disable_c_modules(), "Error during disabling C modules"); mlua_expect!(self.disable_c_modules(), "Error during disabling C modules");
} }
}
extra.libs |= libs; extra.libs |= libs;
res res
@ -795,6 +817,7 @@ impl Lua {
/// ///
/// [`HookTriggers`]: crate::HookTriggers /// [`HookTriggers`]: crate::HookTriggers
/// [`HookTriggers.every_nth_instruction`]: crate::HookTriggers::every_nth_instruction /// [`HookTriggers.every_nth_instruction`]: crate::HookTriggers::every_nth_instruction
#[cfg(not(feature = "luau"))]
pub fn set_hook<F>(&self, triggers: HookTriggers, callback: F) -> Result<()> pub fn set_hook<F>(&self, triggers: HookTriggers, callback: F) -> Result<()>
where where
F: 'static + MaybeSend + FnMut(&Lua, Debug) -> Result<()>, F: 'static + MaybeSend + FnMut(&Lua, Debug) -> Result<()>,
@ -832,6 +855,7 @@ impl Lua {
/// Remove any hook previously set by `set_hook`. This function has no effect if a hook was not /// Remove any hook previously set by `set_hook`. This function has no effect if a hook was not
/// previously set. /// previously set.
#[cfg(not(feature = "luau"))]
pub fn remove_hook(&self) { pub fn remove_hook(&self) {
// If main_state is not available, then sethook wasn't called. // If main_state is not available, then sethook wasn't called.
let state = match self.main_state { let state = match self.main_state {
@ -909,6 +933,7 @@ impl Lua {
/// function that has called level `n` (except for tail calls, which do not count in the stack). /// function that has called level `n` (except for tail calls, which do not count in the stack).
/// ///
/// [`Debug`]: crate::hook::Debug /// [`Debug`]: crate::hook::Debug
#[cfg(not(feature = "luau"))]
pub fn inspect_stack(&self, level: usize) -> Option<Debug> { pub fn inspect_stack(&self, level: usize) -> Option<Debug> {
unsafe { unsafe {
let mut ar: ffi::lua_Debug = mem::zeroed(); let mut ar: ffi::lua_Debug = mem::zeroed();
@ -961,7 +986,12 @@ impl Lua {
/// Returns true if the garbage collector is currently running automatically. /// Returns true if the garbage collector is currently running automatically.
/// ///
/// Requires `feature = "lua54/lua53/lua52"` /// Requires `feature = "lua54/lua53/lua52"`
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] #[cfg(any(
feature = "lua54",
feature = "lua53",
feature = "lua52",
feature = "luau"
))]
pub fn gc_is_running(&self) -> bool { pub fn gc_is_running(&self) -> bool {
let state = self.main_state.unwrap_or(self.state); let state = self.main_state.unwrap_or(self.state);
unsafe { ffi::lua_gc(state, ffi::LUA_GCISRUNNING, 0) != 0 } unsafe { ffi::lua_gc(state, ffi::LUA_GCISRUNNING, 0) != 0 }
@ -1018,6 +1048,7 @@ impl Lua {
/// [documentation][lua_doc]. /// [documentation][lua_doc].
/// ///
/// [lua_doc]: https://www.lua.org/manual/5.4/manual.html#2.5 /// [lua_doc]: https://www.lua.org/manual/5.4/manual.html#2.5
#[cfg(not(feature = "luau"))]
pub fn gc_set_pause(&self, pause: c_int) -> c_int { pub fn gc_set_pause(&self, pause: c_int) -> c_int {
let state = self.main_state.unwrap_or(self.state); let state = self.main_state.unwrap_or(self.state);
unsafe { ffi::lua_gc(state, ffi::LUA_GCSETPAUSE, pause) } unsafe { ffi::lua_gc(state, ffi::LUA_GCSETPAUSE, pause) }
@ -1040,6 +1071,7 @@ impl Lua {
/// More information can be found in the Lua [documentation][lua_doc]. /// More information can be found in the Lua [documentation][lua_doc].
/// ///
/// [lua_doc]: https://www.lua.org/manual/5.4/manual.html#2.5.1 /// [lua_doc]: https://www.lua.org/manual/5.4/manual.html#2.5.1
#[cfg(not(feature = "luau"))]
pub fn gc_inc(&self, pause: c_int, step_multiplier: c_int, step_size: c_int) -> GCMode { pub fn gc_inc(&self, pause: c_int, step_multiplier: c_int, step_size: c_int) -> GCMode {
let state = self.main_state.unwrap_or(self.state); let state = self.main_state.unwrap_or(self.state);
@ -1138,6 +1170,7 @@ impl Lua {
} }
Some(ChunkMode::Binary) => cstr!("b"), Some(ChunkMode::Binary) => cstr!("b"),
Some(ChunkMode::Text) => cstr!("t"), Some(ChunkMode::Text) => cstr!("t"),
#[cfg(not(feature = "luau"))]
None if source.starts_with(ffi::LUA_SIGNATURE) && self.safe => { None if source.starts_with(ffi::LUA_SIGNATURE) && self.safe => {
return Err(Error::SafetyError( return Err(Error::SafetyError(
"binary chunks are disabled in safe mode".to_string(), "binary chunks are disabled in safe mode".to_string(),
@ -1158,7 +1191,7 @@ impl Lua {
self.push_value(env)?; self.push_value(env)?;
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
ffi::lua_setupvalue(self.state, -2, 1); ffi::lua_setupvalue(self.state, -2, 1);
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
ffi::lua_setfenv(self.state, -2); ffi::lua_setfenv(self.state, -2);
} }
Ok(Function(self.pop_ref())) Ok(Function(self.pop_ref()))
@ -1488,7 +1521,7 @@ impl Lua {
assert_stack(self.state, 1); assert_stack(self.state, 1);
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
ffi::lua_rawgeti(self.state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS); ffi::lua_rawgeti(self.state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS);
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
ffi::lua_pushvalue(self.state, ffi::LUA_GLOBALSINDEX); ffi::lua_pushvalue(self.state, ffi::LUA_GLOBALSINDEX);
Table(self.pop_ref()) Table(self.pop_ref())
} }
@ -2329,7 +2362,12 @@ impl Lua {
where where
'lua: 'callback, 'lua: 'callback,
{ {
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] #[cfg(any(
feature = "lua54",
feature = "lua53",
feature = "lua52",
feature = "luau"
))]
unsafe { unsafe {
let libs = (*self.extra.get()).libs; let libs = (*self.extra.get()).libs;
if !libs.contains(StdLib::COROUTINE) { if !libs.contains(StdLib::COROUTINE) {
@ -2551,6 +2589,7 @@ impl Lua {
} }
} }
#[cfg(not(feature = "luau"))]
fn disable_c_modules(&self) -> Result<()> { fn disable_c_modules(&self) -> Result<()> {
let package: Table = self.globals().get("package")?; let package: Table = self.globals().get("package")?;
@ -2577,6 +2616,42 @@ impl Lua {
Ok(()) Ok(())
} }
#[cfg(feature = "luau")]
unsafe fn prepare_luau_state(&self) -> Result<()> {
use std::ffi::CStr;
// Since Luau has some missing standard function, we re-implement them here
// They are: collectgarbage, loadstring, require
unsafe extern "C" fn lua_collectgarbage(state: *mut ffi::lua_State) -> c_int {
let option = ffi::luaL_optstring(state, 1, cstr!("collect"));
let option = CStr::from_ptr(option);
match option.to_str() {
Ok("collect") => {
ffi::lua_gc(state, ffi::LUA_GCCOLLECT, 0);
return 0;
}
Ok("count") => {
let n = ffi::lua_gc(state, ffi::LUA_GCCOUNT, 0);
ffi::lua_pushnumber(state, n as ffi::lua_Number);
return 1;
}
// TODO: More variants
_ => ffi::luaL_error(
state,
cstr!("collectgarbage must be called with 'count' or 'collect'"),
),
}
}
self.globals().raw_set(
"collectgarbage",
self.create_c_function(lua_collectgarbage)?,
)?;
Ok(())
}
pub(crate) unsafe fn make_from_ptr(state: *mut ffi::lua_State) -> Option<Self> { pub(crate) unsafe fn make_from_ptr(state: *mut ffi::lua_State) -> Option<Self> {
let _sg = StackGuard::new(state); let _sg = StackGuard::new(state);
assert_stack(state, 1); assert_stack(state, 1);
@ -2740,7 +2815,7 @@ impl<'lua, 'a> Chunk<'lua, 'a> {
// For source code, first try interpreting the lua as an expression by adding // For source code, first try interpreting the lua as an expression by adding
// "return", then as a statement. This is the same thing the // "return", then as a statement. This is the same thing the
// actual lua repl does. // actual lua repl does.
if self.source.starts_with(ffi::LUA_SIGNATURE) { if self.source[0] < b'\n' {
self.call(()) self.call(())
} else if let Ok(function) = self.lua.load_chunk( } else if let Ok(function) = self.lua.load_chunk(
&self.expression_source(), &self.expression_source(),
@ -2768,7 +2843,7 @@ impl<'lua, 'a> Chunk<'lua, 'a> {
'lua: 'fut, 'lua: 'fut,
R: FromLuaMulti<'lua> + 'fut, R: FromLuaMulti<'lua> + 'fut,
{ {
if self.source.starts_with(ffi::LUA_SIGNATURE) { if self.source[0] < b'\n' {
self.call_async(()) self.call_async(())
} else if let Ok(function) = self.lua.load_chunk( } else if let Ok(function) = self.lua.load_chunk(
&self.expression_source(), &self.expression_source(),
@ -2886,9 +2961,9 @@ where
let prealloc_failure = match extra.wrapped_failures_cache.pop() { let prealloc_failure = match extra.wrapped_failures_cache.pop() {
Some(index) => PreallocatedFailure::Cached(index), Some(index) => PreallocatedFailure::Cached(index),
None => { None => {
let ud = ffi::lua_newuserdata(state, mem::size_of::<WrappedFailure>()); let ud = WrappedFailure::new_userdata(state);
ffi::lua_rotate(state, 1, 1); ffi::lua_rotate(state, 1, 1);
PreallocatedFailure::New(ud as *mut WrappedFailure) PreallocatedFailure::New(ud)
} }
}; };
@ -3006,7 +3081,12 @@ unsafe fn load_from_std_lib(state: *mut ffi::lua_State, libs: StdLib) -> Result<
#[cfg(feature = "luajit")] #[cfg(feature = "luajit")]
let _gc_guard = GcGuard::new(state); let _gc_guard = GcGuard::new(state);
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] #[cfg(any(
feature = "lua54",
feature = "lua53",
feature = "lua52",
feature = "luau"
))]
{ {
if libs.contains(StdLib::COROUTINE) { if libs.contains(StdLib::COROUTINE) {
requiref(state, ffi::LUA_COLIBNAME, ffi::luaopen_coroutine, 1)?; requiref(state, ffi::LUA_COLIBNAME, ffi::luaopen_coroutine, 1)?;
@ -3019,6 +3099,7 @@ unsafe fn load_from_std_lib(state: *mut ffi::lua_State, libs: StdLib) -> Result<
ffi::lua_pop(state, 1); ffi::lua_pop(state, 1);
} }
#[cfg(not(feature = "luau"))]
if libs.contains(StdLib::IO) { if libs.contains(StdLib::IO) {
requiref(state, ffi::LUA_IOLIBNAME, ffi::luaopen_io, 1)?; requiref(state, ffi::LUA_IOLIBNAME, ffi::luaopen_io, 1)?;
ffi::lua_pop(state, 1); ffi::lua_pop(state, 1);
@ -3034,7 +3115,7 @@ unsafe fn load_from_std_lib(state: *mut ffi::lua_State, libs: StdLib) -> Result<
ffi::lua_pop(state, 1); ffi::lua_pop(state, 1);
} }
#[cfg(any(feature = "lua54", feature = "lua53"))] #[cfg(any(feature = "lua54", feature = "lua53", feature = "luau"))]
{ {
if libs.contains(StdLib::UTF8) { if libs.contains(StdLib::UTF8) {
requiref(state, ffi::LUA_UTF8LIBNAME, ffi::luaopen_utf8, 1)?; requiref(state, ffi::LUA_UTF8LIBNAME, ffi::luaopen_utf8, 1)?;
@ -3042,7 +3123,7 @@ unsafe fn load_from_std_lib(state: *mut ffi::lua_State, libs: StdLib) -> Result<
} }
} }
#[cfg(feature = "lua52")] #[cfg(any(feature = "lua52", feature = "luau"))]
{ {
if libs.contains(StdLib::BIT) { if libs.contains(StdLib::BIT) {
requiref(state, ffi::LUA_BITLIBNAME, ffi::luaopen_bit32, 1)?; requiref(state, ffi::LUA_BITLIBNAME, ffi::luaopen_bit32, 1)?;
@ -3068,6 +3149,7 @@ unsafe fn load_from_std_lib(state: *mut ffi::lua_State, libs: StdLib) -> Result<
ffi::lua_pop(state, 1); ffi::lua_pop(state, 1);
} }
#[cfg(not(feature = "luau"))]
if libs.contains(StdLib::PACKAGE) { if libs.contains(StdLib::PACKAGE) {
requiref(state, ffi::LUA_LOADLIBNAME, ffi::luaopen_package, 1)?; requiref(state, ffi::LUA_LOADLIBNAME, ffi::luaopen_package, 1)?;
ffi::lua_pop(state, 1); ffi::lua_pop(state, 1);
@ -3089,7 +3171,6 @@ unsafe fn load_from_std_lib(state: *mut ffi::lua_State, libs: StdLib) -> Result<
Ok(()) Ok(())
} }
// We move `extra` (`MutexGuard`) here to correctly drop it if panic
unsafe fn ref_stack_pop(extra: &mut ExtraData) -> c_int { unsafe fn ref_stack_pop(extra: &mut ExtraData) -> c_int {
if let Some(free) = extra.ref_free.pop() { if let Some(free) = extra.ref_free.pop() {
ffi::lua_replace(extra.ref_thread, free); ffi::lua_replace(extra.ref_thread, free);
@ -3238,7 +3319,7 @@ impl<'lua, T: 'static + UserData> UserDataMethods<'lua, T> for StaticUserDataMet
.push((meta.into(), Self::box_method_mut(method))); .push((meta.into(), Self::box_method_mut(method)));
} }
#[cfg(all(feature = "async", not(feature = "lua51")))] #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
fn add_async_meta_method<S, A, R, M, MR>(&mut self, meta: S, method: M) fn add_async_meta_method<S, A, R, M, MR>(&mut self, meta: S, method: M)
where where
T: Clone, T: Clone,
@ -3274,7 +3355,7 @@ impl<'lua, T: 'static + UserData> UserDataMethods<'lua, T> for StaticUserDataMet
.push((meta.into(), Self::box_function_mut(function))); .push((meta.into(), Self::box_function_mut(function)));
} }
#[cfg(all(feature = "async", not(feature = "lua51")))] #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
fn add_async_meta_function<S, A, R, F, FR>(&mut self, meta: S, function: F) fn add_async_meta_function<S, A, R, F, FR>(&mut self, meta: S, function: F)
where where
S: Into<MetaMethod>, S: Into<MetaMethod>,

View File

@ -3,7 +3,6 @@ use std::cell::{Cell, RefCell};
use std::marker::PhantomData; use std::marker::PhantomData;
use std::mem; use std::mem;
use std::os::raw::{c_int, c_void}; use std::os::raw::{c_int, c_void};
use std::ptr;
use std::rc::Rc; use std::rc::Rc;
#[cfg(feature = "serialize")] #[cfg(feature = "serialize")]
@ -18,8 +17,8 @@ use crate::userdata::{
AnyUserData, MetaMethod, UserData, UserDataCell, UserDataFields, UserDataMethods, AnyUserData, MetaMethod, UserData, UserDataCell, UserDataFields, UserDataMethods,
}; };
use crate::util::{ use crate::util::{
assert_stack, check_stack, get_userdata, init_userdata_metatable, push_table, rawset_field, assert_stack, check_stack, get_userdata, init_userdata_metatable, push_table, push_userdata,
take_userdata, StackGuard, rawset_field, take_userdata, StackGuard,
}; };
use crate::value::{FromLua, FromLuaMulti, MultiValue, ToLua, ToLuaMulti, Value}; use crate::value::{FromLua, FromLuaMulti, MultiValue, ToLua, ToLuaMulti, Value};
@ -206,7 +205,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
ffi::lua_pushnil(state); ffi::lua_pushnil(state);
ffi::lua_setiuservalue(state, -2, i as c_int); ffi::lua_setiuservalue(state, -2, i as c_int);
} }
#[cfg(any(feature = "lua53", feature = "lua52"))] #[cfg(any(feature = "lua53", feature = "lua52", feature = "luau"))]
{ {
ffi::lua_pushnil(state); ffi::lua_pushnil(state);
ffi::lua_setuservalue(state, -2); ffi::lua_setuservalue(state, -2);
@ -264,7 +263,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
fn wrap_method<'scope, 'lua, 'callback: 'scope, T: 'scope>( fn wrap_method<'scope, 'lua, 'callback: 'scope, T: 'scope>(
scope: &Scope<'lua, 'scope>, scope: &Scope<'lua, 'scope>,
data: Rc<RefCell<T>>, data: Rc<RefCell<T>>,
data_ptr: *const c_void, ud_ptr: *const c_void,
method: NonStaticMethod<'callback, T>, method: NonStaticMethod<'callback, T>,
) -> Result<Function<'lua>> { ) -> Result<Function<'lua>> {
// On methods that actually receive the userdata, we fake a type check on the passed in // On methods that actually receive the userdata, we fake a type check on the passed in
@ -280,7 +279,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
let _sg = StackGuard::new(lua.state); let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 2)?; check_stack(lua.state, 2)?;
lua.push_userdata_ref(&ud.0)?; lua.push_userdata_ref(&ud.0)?;
if get_userdata(lua.state, -1) as *const _ == data_ptr { if get_userdata(lua.state, -1) as *const _ == ud_ptr {
return Ok(()); return Ok(());
} }
} }
@ -336,8 +335,9 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
let _sg = StackGuard::new(lua.state); let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 13)?; check_stack(lua.state, 13)?;
#[cfg(not(feature = "luau"))]
#[allow(clippy::let_and_return)] #[allow(clippy::let_and_return)]
let data_ptr = protect_lua!(lua.state, 0, 1, |state| { let ud_ptr = protect_lua!(lua.state, 0, 1, |state| {
let ud = let ud =
ffi::lua_newuserdata(state, mem::size_of::<UserDataCell<Rc<RefCell<T>>>>()); ffi::lua_newuserdata(state, mem::size_of::<UserDataCell<Rc<RefCell<T>>>>());
@ -350,13 +350,22 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
ud ud
})?; })?;
#[cfg(feature = "luau")]
let ud_ptr = {
push_userdata::<UserDataCell<Rc<RefCell<T>>>>(
lua.state,
UserDataCell::new(data.clone()),
)?;
ffi::lua_touserdata(lua.state, -1)
};
// Prepare metatable, add meta methods first and then meta fields // Prepare metatable, add meta methods first and then meta fields
let meta_methods_nrec = ud_methods.meta_methods.len() + ud_fields.meta_fields.len() + 1; let meta_methods_nrec = ud_methods.meta_methods.len() + ud_fields.meta_fields.len() + 1;
push_table(lua.state, 0, meta_methods_nrec as c_int)?; push_table(lua.state, 0, meta_methods_nrec as c_int)?;
for (k, m) in ud_methods.meta_methods { for (k, m) in ud_methods.meta_methods {
let data = data.clone(); let data = data.clone();
lua.push_value(Value::Function(wrap_method(self, data, data_ptr, m)?))?; lua.push_value(Value::Function(wrap_method(self, data, ud_ptr, m)?))?;
rawset_field(lua.state, -2, k.validate()?.name())?; rawset_field(lua.state, -2, k.validate()?.name())?;
} }
for (k, f) in ud_fields.meta_fields { for (k, f) in ud_fields.meta_fields {
@ -371,7 +380,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
push_table(lua.state, 0, field_getters_nrec as c_int)?; push_table(lua.state, 0, field_getters_nrec as c_int)?;
for (k, m) in ud_fields.field_getters { for (k, m) in ud_fields.field_getters {
let data = data.clone(); let data = data.clone();
lua.push_value(Value::Function(wrap_method(self, data, data_ptr, m)?))?; lua.push_value(Value::Function(wrap_method(self, data, ud_ptr, m)?))?;
rawset_field(lua.state, -2, &k)?; rawset_field(lua.state, -2, &k)?;
} }
field_getters_index = Some(ffi::lua_absindex(lua.state, -1)); field_getters_index = Some(ffi::lua_absindex(lua.state, -1));
@ -383,7 +392,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
push_table(lua.state, 0, field_setters_nrec as c_int)?; push_table(lua.state, 0, field_setters_nrec as c_int)?;
for (k, m) in ud_fields.field_setters { for (k, m) in ud_fields.field_setters {
let data = data.clone(); let data = data.clone();
lua.push_value(Value::Function(wrap_method(self, data, data_ptr, m)?))?; lua.push_value(Value::Function(wrap_method(self, data, ud_ptr, m)?))?;
rawset_field(lua.state, -2, &k)?; rawset_field(lua.state, -2, &k)?;
} }
field_setters_index = Some(ffi::lua_absindex(lua.state, -1)); field_setters_index = Some(ffi::lua_absindex(lua.state, -1));
@ -396,7 +405,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
push_table(lua.state, 0, methods_nrec as c_int)?; push_table(lua.state, 0, methods_nrec as c_int)?;
for (k, m) in ud_methods.methods { for (k, m) in ud_methods.methods {
let data = data.clone(); let data = data.clone();
lua.push_value(Value::Function(wrap_method(self, data, data_ptr, m)?))?; lua.push_value(Value::Function(wrap_method(self, data, ud_ptr, m)?))?;
rawset_field(lua.state, -2, &k)?; rawset_field(lua.state, -2, &k)?;
} }
methods_index = Some(ffi::lua_absindex(lua.state, -1)); methods_index = Some(ffi::lua_absindex(lua.state, -1));
@ -417,7 +426,8 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
let mt_ptr = ffi::lua_topointer(lua.state, -1); let mt_ptr = ffi::lua_topointer(lua.state, -1);
// Write userdata just before attaching metatable with `__gc` metamethod // Write userdata just before attaching metatable with `__gc` metamethod
ptr::write(data_ptr as _, UserDataCell::new(data)); #[cfg(not(feature = "luau"))]
std::ptr::write(ud_ptr as _, UserDataCell::new(data));
ffi::lua_setmetatable(lua.state, -2); ffi::lua_setmetatable(lua.state, -2);
let ud = AnyUserData(lua.pop_ref()); let ud = AnyUserData(lua.pop_ref());
lua.register_userdata_metatable(mt_ptr, None); lua.register_userdata_metatable(mt_ptr, None);
@ -446,7 +456,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
ffi::lua_pushnil(state); ffi::lua_pushnil(state);
ffi::lua_setiuservalue(state, -2, i as c_int); ffi::lua_setiuservalue(state, -2, i as c_int);
} }
#[cfg(any(feature = "lua53", feature = "lua52"))] #[cfg(any(feature = "lua53", feature = "lua52", feature = "luau"))]
{ {
ffi::lua_pushnil(state); ffi::lua_pushnil(state);
ffi::lua_setuservalue(state, -2); ffi::lua_setuservalue(state, -2);
@ -532,7 +542,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
// First, get the environment table // First, get the environment table
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
ffi::lua_getupvalue(state, -1, 1); ffi::lua_getupvalue(state, -1, 1);
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
ffi::lua_getfenv(state, -1); ffi::lua_getfenv(state, -1);
// Second, get the `get_poll()` closure using the corresponding key // Second, get the `get_poll()` closure using the corresponding key
@ -727,7 +737,7 @@ impl<'lua, T: UserData> UserDataMethods<'lua, T> for NonStaticUserDataMethods<'l
)); ));
} }
#[cfg(all(feature = "async", not(feature = "lua51")))] #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
fn add_async_meta_method<S, A, R, M, MR>(&mut self, _meta: S, _method: M) fn add_async_meta_method<S, A, R, M, MR>(&mut self, _meta: S, _method: M)
where where
T: Clone, T: Clone,
@ -772,7 +782,7 @@ impl<'lua, T: UserData> UserDataMethods<'lua, T> for NonStaticUserDataMethods<'l
)); ));
} }
#[cfg(all(feature = "async", not(feature = "lua51")))] #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
fn add_async_meta_function<S, A, R, F, FR>(&mut self, _meta: S, _function: F) fn add_async_meta_function<S, A, R, F, FR>(&mut self, _meta: S, _function: F)
where where
S: Into<MetaMethod>, S: Into<MetaMethod>,

View File

@ -9,11 +9,17 @@ impl StdLib {
/// [`coroutine`](https://www.lua.org/manual/5.4/manual.html#6.2) library /// [`coroutine`](https://www.lua.org/manual/5.4/manual.html#6.2) library
/// ///
/// Requires `feature = "lua54/lua53/lua52"` /// Requires `feature = "lua54/lua53/lua52"`
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] #[cfg(any(
feature = "lua54",
feature = "lua53",
feature = "lua52",
feature = "luau"
))]
pub const COROUTINE: StdLib = StdLib(1); pub const COROUTINE: StdLib = StdLib(1);
/// [`table`](https://www.lua.org/manual/5.4/manual.html#6.6) library /// [`table`](https://www.lua.org/manual/5.4/manual.html#6.6) library
pub const TABLE: StdLib = StdLib(1 << 1); pub const TABLE: StdLib = StdLib(1 << 1);
/// [`io`](https://www.lua.org/manual/5.4/manual.html#6.8) library /// [`io`](https://www.lua.org/manual/5.4/manual.html#6.8) library
#[cfg(not(feature = "luau"))]
pub const IO: StdLib = StdLib(1 << 2); pub const IO: StdLib = StdLib(1 << 2);
/// [`os`](https://www.lua.org/manual/5.4/manual.html#6.9) library /// [`os`](https://www.lua.org/manual/5.4/manual.html#6.9) library
pub const OS: StdLib = StdLib(1 << 3); pub const OS: StdLib = StdLib(1 << 3);
@ -22,16 +28,17 @@ impl StdLib {
/// [`utf8`](https://www.lua.org/manual/5.4/manual.html#6.5) library /// [`utf8`](https://www.lua.org/manual/5.4/manual.html#6.5) library
/// ///
/// Requires `feature = "lua54/lua53"` /// Requires `feature = "lua54/lua53"`
#[cfg(any(feature = "lua54", feature = "lua53"))] #[cfg(any(feature = "lua54", feature = "lua53", feature = "luau"))]
pub const UTF8: StdLib = StdLib(1 << 5); pub const UTF8: StdLib = StdLib(1 << 5);
/// [`bit`](https://www.lua.org/manual/5.2/manual.html#6.7) library /// [`bit`](https://www.lua.org/manual/5.2/manual.html#6.7) library
/// ///
/// Requires `feature = "lua52/luajit"` /// Requires `feature = "lua52/luajit"`
#[cfg(any(feature = "lua52", feature = "luajit", doc))] #[cfg(any(feature = "lua52", feature = "luajit", feature = "luau", doc))]
pub const BIT: StdLib = StdLib(1 << 6); pub const BIT: StdLib = StdLib(1 << 6);
/// [`math`](https://www.lua.org/manual/5.4/manual.html#6.7) library /// [`math`](https://www.lua.org/manual/5.4/manual.html#6.7) library
pub const MATH: StdLib = StdLib(1 << 7); pub const MATH: StdLib = StdLib(1 << 7);
/// [`package`](https://www.lua.org/manual/5.4/manual.html#6.3) library /// [`package`](https://www.lua.org/manual/5.4/manual.html#6.3) library
#[cfg(not(feature = "luau"))]
pub const PACKAGE: StdLib = StdLib(1 << 8); pub const PACKAGE: StdLib = StdLib(1 << 8);
/// [`jit`](http://luajit.org/ext_jit.html) library /// [`jit`](http://luajit.org/ext_jit.html) library
/// ///

View File

@ -11,6 +11,7 @@ use futures_core::future::LocalBoxFuture;
use crate::error::Result; use crate::error::Result;
use crate::ffi; use crate::ffi;
#[cfg(not(feature = "luau"))]
use crate::hook::Debug; use crate::hook::Debug;
use crate::lua::Lua; use crate::lua::Lua;
use crate::util::{assert_stack, StackGuard}; use crate::util::{assert_stack, StackGuard};
@ -48,11 +49,10 @@ pub(crate) struct AsyncPollUpvalue<'lua> {
pub(crate) lua: Lua, pub(crate) lua: Lua,
pub(crate) fut: LocalBoxFuture<'lua, Result<MultiValue<'lua>>>, pub(crate) fut: LocalBoxFuture<'lua, Result<MultiValue<'lua>>>,
} }
#[cfg(all(feature = "send", not(feature = "luau")))]
#[cfg(feature = "send")]
pub(crate) type HookCallback = Arc<Mutex<dyn FnMut(&Lua, Debug) -> Result<()> + Send>>; pub(crate) type HookCallback = Arc<Mutex<dyn FnMut(&Lua, Debug) -> Result<()> + Send>>;
#[cfg(not(feature = "send"))] #[cfg(all(not(feature = "send"), not(feature = "luau")))]
pub(crate) type HookCallback = Arc<Mutex<dyn FnMut(&Lua, Debug) -> Result<()>>>; pub(crate) type HookCallback = Arc<Mutex<dyn FnMut(&Lua, Debug) -> Result<()>>>;
#[cfg(all(feature = "send", feature = "lua54"))] #[cfg(all(feature = "send", feature = "lua54"))]

View File

@ -419,7 +419,7 @@ pub trait UserDataMethods<'lua, T: UserData> {
/// Requires `feature = "async"` /// Requires `feature = "async"`
/// ///
/// [`add_meta_method`]: #method.add_meta_method /// [`add_meta_method`]: #method.add_meta_method
#[cfg(all(feature = "async", not(feature = "lua51")))] #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))] #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
fn add_async_meta_method<S, A, R, M, MR>(&mut self, name: S, method: M) fn add_async_meta_method<S, A, R, M, MR>(&mut self, name: S, method: M)
where where
@ -461,7 +461,7 @@ pub trait UserDataMethods<'lua, T: UserData> {
/// Requires `feature = "async"` /// Requires `feature = "async"`
/// ///
/// [`add_meta_function`]: #method.add_meta_function /// [`add_meta_function`]: #method.add_meta_function
#[cfg(all(feature = "async", not(feature = "lua51")))] #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))] #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
fn add_async_meta_function<S, A, R, F, FR>(&mut self, name: S, function: F) fn add_async_meta_function<S, A, R, F, FR>(&mut self, name: S, function: F)
where where
@ -839,7 +839,7 @@ impl<'lua> AnyUserData<'lua> {
ffi::lua_pushnil(lua.state); ffi::lua_pushnil(lua.state);
ffi::lua_setiuservalue(lua.state, -2, i as c_int); ffi::lua_setiuservalue(lua.state, -2, i as c_int);
} }
#[cfg(any(feature = "lua53", feature = "lua52"))] #[cfg(any(feature = "lua53", feature = "lua52", feature = "luau"))]
{ {
ffi::lua_pushnil(lua.state); ffi::lua_pushnil(lua.state);
ffi::lua_setuservalue(lua.state, -2); ffi::lua_setuservalue(lua.state, -2);
@ -865,6 +865,7 @@ impl<'lua> AnyUserData<'lua> {
/// ///
/// [`get_user_value`]: #method.get_user_value /// [`get_user_value`]: #method.get_user_value
/// [`set_nth_user_value`]: #method.set_nth_user_value /// [`set_nth_user_value`]: #method.set_nth_user_value
// #[cfg(not(feature = "luau"))]
#[inline] #[inline]
pub fn set_user_value<V: ToLua<'lua>>(&self, v: V) -> Result<()> { pub fn set_user_value<V: ToLua<'lua>>(&self, v: V) -> Result<()> {
self.set_nth_user_value(1, v) self.set_nth_user_value(1, v)
@ -876,6 +877,7 @@ impl<'lua> AnyUserData<'lua> {
/// ///
/// [`set_user_value`]: #method.set_user_value /// [`set_user_value`]: #method.set_user_value
/// [`get_nth_user_value`]: #method.get_nth_user_value /// [`get_nth_user_value`]: #method.get_nth_user_value
// #[cfg(not(feature = "luau"))]
#[inline] #[inline]
pub fn get_user_value<V: FromLua<'lua>>(&self) -> Result<V> { pub fn get_user_value<V: FromLua<'lua>>(&self) -> Result<V> {
self.get_nth_user_value(1) self.get_nth_user_value(1)
@ -891,6 +893,7 @@ impl<'lua> AnyUserData<'lua> {
/// For other Lua versions this functionality is provided using a wrapping table. /// For other Lua versions this functionality is provided using a wrapping table.
/// ///
/// [`get_nth_user_value`]: #method.get_nth_user_value /// [`get_nth_user_value`]: #method.get_nth_user_value
// #[cfg(not(feature = "luau"))]
pub fn set_nth_user_value<V: ToLua<'lua>>(&self, n: usize, v: V) -> Result<()> { pub fn set_nth_user_value<V: ToLua<'lua>>(&self, n: usize, v: V) -> Result<()> {
if n < 1 || n > u16::MAX as usize { if n < 1 || n > u16::MAX as usize {
return Err(Error::RuntimeError( return Err(Error::RuntimeError(
@ -945,6 +948,7 @@ impl<'lua> AnyUserData<'lua> {
/// For other Lua versions this functionality is provided using a wrapping table. /// For other Lua versions this functionality is provided using a wrapping table.
/// ///
/// [`set_nth_user_value`]: #method.set_nth_user_value /// [`set_nth_user_value`]: #method.set_nth_user_value
// #[cfg(not(feature = "luau"))]
pub fn get_nth_user_value<V: FromLua<'lua>>(&self, n: usize) -> Result<V> { pub fn get_nth_user_value<V: FromLua<'lua>>(&self, n: usize) -> Result<V> {
if n < 1 || n > u16::MAX as usize { if n < 1 || n > u16::MAX as usize {
return Err(Error::RuntimeError( return Err(Error::RuntimeError(
@ -986,6 +990,7 @@ impl<'lua> AnyUserData<'lua> {
/// The value can be retrieved with [`get_named_user_value`]. /// The value can be retrieved with [`get_named_user_value`].
/// ///
/// [`get_named_user_value`]: #method.get_named_user_value /// [`get_named_user_value`]: #method.get_named_user_value
// #[cfg(not(feature = "luau"))]
pub fn set_named_user_value<S, V>(&self, name: &S, v: V) -> Result<()> pub fn set_named_user_value<S, V>(&self, name: &S, v: V) -> Result<()>
where where
S: AsRef<[u8]> + ?Sized, S: AsRef<[u8]> + ?Sized,
@ -1025,6 +1030,7 @@ impl<'lua> AnyUserData<'lua> {
/// Returns an associated value by name set by [`set_named_user_value`]. /// Returns an associated value by name set by [`set_named_user_value`].
/// ///
/// [`set_named_user_value`]: #method.set_named_user_value /// [`set_named_user_value`]: #method.set_named_user_value
// #[cfg(not(feature = "luau"))]
pub fn get_named_user_value<S, V>(&self, name: &S) -> Result<V> pub fn get_named_user_value<S, V>(&self, name: &S) -> Result<V>
where where
S: AsRef<[u8]> + ?Sized, S: AsRef<[u8]> + ?Sized,

View File

@ -278,6 +278,7 @@ where
} }
// Internally uses 3 stack spaces, does not call checkstack. // Internally uses 3 stack spaces, does not call checkstack.
#[cfg(not(feature = "luau"))]
#[inline] #[inline]
pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T) -> Result<()> { pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T) -> Result<()> {
let ud = protect_lua!(state, 0, 1, |state| { let ud = protect_lua!(state, 0, 1, |state| {
@ -287,6 +288,27 @@ pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T) -> Result<()> {
Ok(()) Ok(())
} }
// Internally uses 3 stack spaces, does not call checkstack.
#[cfg(feature = "luau")]
#[inline]
pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T) -> Result<()> {
unsafe extern "C" fn destructor<T>(ud: *mut c_void) {
let ud = ud as *mut T;
if *(ud.offset(1) as *mut u8) == 0 {
ptr::drop_in_place(ud);
}
}
let ud = protect_lua!(state, 0, 1, |state| {
let size = mem::size_of::<T>() + 1;
ffi::lua_newuserdatadtor(state, size, destructor::<T>) as *mut T
})?;
ptr::write(ud, t);
*(ud.offset(1) as *mut u8) = 0; // Mark as not destructed
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]
@ -316,8 +338,11 @@ pub unsafe fn take_userdata<T>(state: *mut ffi::lua_State) -> T {
// after the first call to __gc. // after the first call to __gc.
get_destructed_userdata_metatable(state); get_destructed_userdata_metatable(state);
ffi::lua_setmetatable(state, -2); ffi::lua_setmetatable(state, -2);
let ud = get_userdata(state, -1); let ud = get_userdata::<T>(state, -1);
ffi::lua_pop(state, 1); ffi::lua_pop(state, 1);
if cfg!(feature = "luau") {
*(ud.offset(1) as *mut u8) = 1; // Mark as destructed
}
ptr::read(ud) ptr::read(ud)
} }
@ -508,8 +533,11 @@ pub unsafe fn init_userdata_metatable<T>(
rawset_field(state, -2, "__newindex")?; rawset_field(state, -2, "__newindex")?;
} }
#[cfg(not(feature = "luau"))]
{
ffi::lua_pushcfunction(state, userdata_destructor::<T>); ffi::lua_pushcfunction(state, userdata_destructor::<T>);
rawset_field(state, -2, "__gc")?; rawset_field(state, -2, "__gc")?;
}
ffi::lua_pushboolean(state, 0); ffi::lua_pushboolean(state, 0);
rawset_field(state, -2, "__metatable")?; rawset_field(state, -2, "__metatable")?;
@ -519,6 +547,7 @@ pub unsafe fn init_userdata_metatable<T>(
Ok(()) Ok(())
} }
#[cfg(not(feature = "luau"))]
pub unsafe extern "C" fn userdata_destructor<T>(state: *mut ffi::lua_State) -> c_int { pub unsafe extern "C" fn userdata_destructor<T>(state: *mut ffi::lua_State) -> c_int {
// It's probably NOT a good idea to catch Rust panics in finalizer // It's probably NOT a good idea to catch Rust panics in finalizer
// Lua 5.4 ignores it, other versions generates `LUA_ERRGCMM` without calling message handler // Lua 5.4 ignores it, other versions generates `LUA_ERRGCMM` without calling message handler
@ -553,7 +582,7 @@ where
// We cannot shadow Rust errors with Lua ones, we pre-allocate enough memory // We cannot shadow Rust errors with Lua ones, we pre-allocate enough memory
// to store a wrapped error or panic *before* we proceed. // to store a wrapped error or panic *before* we proceed.
let ud = ffi::lua_newuserdata(state, mem::size_of::<WrappedFailure>()); let ud = WrappedFailure::new_userdata(state);
ffi::lua_rotate(state, 1, 1); ffi::lua_rotate(state, 1, 1);
match catch_unwind(AssertUnwindSafe(|| f(nargs))) { match catch_unwind(AssertUnwindSafe(|| f(nargs))) {
@ -706,6 +735,8 @@ pub unsafe fn get_main_state(state: *mut ffi::lua_State) -> Option<*mut ffi::lua
None None
} }
} }
#[cfg(feature = "luau")]
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.
@ -718,8 +749,11 @@ pub unsafe fn init_gc_metatable<T: Any>(
push_table(state, 0, 3)?; push_table(state, 0, 3)?;
#[cfg(not(feature = "luau"))]
{
ffi::lua_pushcfunction(state, userdata_destructor::<T>); ffi::lua_pushcfunction(state, userdata_destructor::<T>);
rawset_field(state, -2, "__gc")?; rawset_field(state, -2, "__gc")?;
}
ffi::lua_pushboolean(state, 0); ffi::lua_pushboolean(state, 0);
rawset_field(state, -2, "__metatable")?; rawset_field(state, -2, "__metatable")?;
@ -879,10 +913,28 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<()> {
} }
pub(crate) enum WrappedFailure { pub(crate) enum WrappedFailure {
None,
Error(Error), Error(Error),
Panic(Option<Box<dyn Any + Send + 'static>>), Panic(Option<Box<dyn Any + Send + 'static>>),
} }
impl WrappedFailure {
pub(crate) unsafe fn new_userdata(state: *mut ffi::lua_State) -> *mut Self {
let size = mem::size_of::<WrappedFailure>();
#[cfg(feature = "luau")]
let ud = {
unsafe extern "C" fn destructor(p: *mut c_void) {
ptr::drop_in_place(p as *mut WrappedFailure);
}
ffi::lua_newuserdatadtor(state, size, destructor) as *mut Self
};
#[cfg(not(feature = "luau"))]
let ud = ffi::lua_newuserdata(state, size) as *mut Self;
ptr::write(ud, WrappedFailure::None);
ud
}
}
// 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 {

View File

@ -299,7 +299,7 @@ async fn test_async_userdata() -> Result<()> {
Ok(format!("elapsed:{}ms", n)) Ok(format!("elapsed:{}ms", n))
}); });
#[cfg(not(feature = "lua51"))] #[cfg(not(any(feature = "lua51", feature = "luau")))]
methods.add_async_meta_method(mlua::MetaMethod::Call, |_, data, ()| async move { methods.add_async_meta_method(mlua::MetaMethod::Call, |_, data, ()| async move {
let n = data.0.load(Ordering::Relaxed); let n = data.0.load(Ordering::Relaxed);
Delay::new(Duration::from_millis(n)).await; Delay::new(Duration::from_millis(n)).await;
@ -363,7 +363,7 @@ async fn test_async_userdata() -> Result<()> {
.exec_async() .exec_async()
.await?; .await?;
#[cfg(not(feature = "lua51"))] #[cfg(not(any(feature = "lua51", feature = "luau")))]
lua.load( lua.load(
r#" r#"
userdata:set_value(15) userdata:set_value(15)

View File

@ -93,6 +93,7 @@ fn test_c_function() -> Result<()> {
Ok(()) Ok(())
} }
#[cfg(not(feature = "luau"))]
#[test] #[test]
fn test_dump() -> Result<()> { fn test_dump() -> Result<()> {
let lua = unsafe { Lua::unsafe_new() }; let lua = unsafe { Lua::unsafe_new() };

View File

@ -1,3 +1,5 @@
#![cfg(not(feature = "luau"))]
use std::cell::RefCell; use std::cell::RefCell;
use std::ops::Deref; use std::ops::Deref;
use std::str; use std::str;

View File

@ -41,7 +41,12 @@ fn test_gc_control() -> Result<()> {
#[cfg(feature = "lua54")] #[cfg(feature = "lua54")]
assert_eq!(lua.gc_gen(0, 0), mlua::GCMode::Incremental); assert_eq!(lua.gc_gen(0, 0), mlua::GCMode::Incremental);
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] #[cfg(any(
feature = "lua54",
feature = "lua53",
feature = "lua52",
feature = "luau"
))]
{ {
assert!(lua.gc_is_running()); assert!(lua.gc_is_running());
lua.gc_stop(); lua.gc_stop();

View File

@ -11,6 +11,7 @@ use mlua::{
UserData, Value, Variadic, UserData, Value, Variadic,
}; };
#[cfg(not(feature = "luau"))]
#[test] #[test]
fn test_safety() -> Result<()> { fn test_safety() -> Result<()> {
let lua = Lua::new(); let lua = Lua::new();
@ -120,6 +121,7 @@ fn test_exec() -> Result<()> {
"#, "#,
) )
.eval()?; .eval()?;
println!("checkpoint");
assert!(module.contains_key("func")?); assert!(module.contains_key("func")?);
assert_eq!( assert_eq!(
module.get::<_, Function>("func")?.call::<_, String>(())?, module.get::<_, Function>("func")?.call::<_, String>(())?,
@ -150,6 +152,7 @@ fn test_eval() -> Result<()> {
Ok(()) Ok(())
} }
#[cfg(not(feature = "luau"))]
#[test] #[test]
fn test_load_mode() -> Result<()> { fn test_load_mode() -> Result<()> {
let lua = unsafe { Lua::unsafe_new() }; let lua = unsafe { Lua::unsafe_new() };
@ -250,15 +253,7 @@ fn test_error() -> Result<()> {
} }
} }
impl error::Error for TestError { impl error::Error for TestError {}
fn description(&self) -> &str {
"test error"
}
fn cause(&self) -> Option<&dyn error::Error> {
None
}
}
let lua = Lua::new(); let lua = Lua::new();
@ -295,8 +290,8 @@ fn test_error() -> Result<()> {
end, 3) end, 3)
local function handler(err) local function handler(err)
if string.match(_VERSION, ' 5%.1$') or string.match(_VERSION, ' 5%.2$') then if string.match(_VERSION, ' 5%.1$') or string.match(_VERSION, ' 5%.2$') or _VERSION == "Luau" then
-- Special case for Lua 5.1/5.2 -- Special case for Lua 5.1/5.2 and Luau
local caps = string.match(err, ': (%d+)$') local caps = string.match(err, ': (%d+)$')
if caps then if caps then
err = caps err = caps
@ -1096,7 +1091,11 @@ fn test_context_thread() -> Result<()> {
))] ))]
f.call::<_, ()>(lua.current_thread())?; f.call::<_, ()>(lua.current_thread())?;
#[cfg(any(feature = "lua51", all(feature = "luajit", not(feature = "luajit52"))))] #[cfg(any(
feature = "lua51",
all(feature = "luajit", not(feature = "luajit52")),
feature = "luau"
))]
f.call::<_, ()>(Nil)?; f.call::<_, ()>(Nil)?;
Ok(()) Ok(())
@ -1170,6 +1169,7 @@ fn test_load_from_function() -> Result<()> {
Ok(()) Ok(())
} }
#[cfg(not(feature = "luau"))]
#[test] #[test]
fn test_inspect_stack() -> Result<()> { fn test_inspect_stack() -> Result<()> {
let lua = Lua::new(); let lua = Lua::new();

View File

@ -155,7 +155,8 @@ fn test_coroutine_from_closure() -> Result<()> {
feature = "lua54", feature = "lua54",
feature = "lua53", feature = "lua53",
feature = "lua52", feature = "lua52",
feature = "luajit" feature = "luajit",
feature = "luau"
))] ))]
let thrd: Thread = lua.load("coroutine.create(main)").eval()?; let thrd: Thread = lua.load("coroutine.create(main)").eval()?;
#[cfg(feature = "lua51")] #[cfg(feature = "lua51")]

View File

@ -350,7 +350,7 @@ fn test_userdata_take() -> Result<()> {
} }
#[test] #[test]
fn test_destroy_userdata() -> Result<()> { fn test_userdata_destroy() -> Result<()> {
struct MyUserdata(Arc<()>); struct MyUserdata(Arc<()>);
impl UserData for MyUserdata {} impl UserData for MyUserdata {}
@ -358,12 +358,15 @@ fn test_destroy_userdata() -> Result<()> {
let rc = Arc::new(()); let rc = Arc::new(());
let lua = Lua::new(); let lua = Lua::new();
lua.globals().set("userdata", MyUserdata(rc.clone()))?; let ud = lua.create_userdata(MyUserdata(rc.clone()))?;
ud.set_user_value(MyUserdata(rc.clone()))?;
lua.globals().set("userdata", ud)?;
assert_eq!(Arc::strong_count(&rc), 2); assert_eq!(Arc::strong_count(&rc), 3);
// should destroy all objects // Should destroy all objects
let _ = lua.globals().raw_remove("userdata")?; lua.globals().raw_remove("userdata")?;
lua.gc_collect()?;
lua.gc_collect()?; lua.gc_collect()?;
assert_eq!(Arc::strong_count(&rc), 1); assert_eq!(Arc::strong_count(&rc), 1);