summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/main.yml8
-rw-r--r--Cargo.toml4
-rw-r--r--build/find_vendored.rs2
-rw-r--r--src/ffi/compat53.rs223
-rw-r--r--src/ffi/lauxlib.rs9
-rw-r--r--src/ffi/lua.rs33
-rw-r--r--src/ffi/lualib.rs3
-rw-r--r--src/ffi/luau/lauxlib.rs188
-rw-r--r--src/ffi/luau/lua.rs59
-rw-r--r--src/ffi/luau/luacode.rs22
-rw-r--r--src/ffi/luau/lualib.rs84
-rw-r--r--src/ffi/luau/mod.rs4
-rw-r--r--src/ffi/mod.rs26
-rw-r--r--src/function.rs7
-rw-r--r--src/lib.rs2
-rw-r--r--src/lua.rs125
-rw-r--r--src/scope.rs42
-rw-r--r--src/stdlib.rs13
-rw-r--r--src/types.rs6
-rw-r--r--src/userdata.rs12
-rw-r--r--src/util.rs64
-rw-r--r--tests/async.rs4
-rw-r--r--tests/function.rs1
-rw-r--r--tests/hooks.rs2
-rw-r--r--tests/memory.rs7
-rw-r--r--tests/tests.rs24
-rw-r--r--tests/thread.rs3
-rw-r--r--tests/userdata.rs13
28 files changed, 762 insertions, 228 deletions
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 22ba395..e287d35 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -9,7 +9,7 @@ jobs:
matrix:
os: [ubuntu-20.04, macos-latest, windows-latest]
rust: [stable]
- lua: [lua54, lua53, lua52, lua51, luajit]
+ lua: [lua54, lua53, lua52, lua51, luajit, luau]
include:
- os: ubuntu-20.04
target: x86_64-unknown-linux-gnu
@@ -108,7 +108,7 @@ jobs:
matrix:
os: [ubuntu-20.04, macos-latest, windows-latest]
rust: [stable, nightly]
- lua: [lua54, lua53, lua52, lua51, luajit, luajit52]
+ lua: [lua54, lua53, lua52, lua51, luajit, luajit52, luau]
include:
- os: ubuntu-20.04
target: x86_64-unknown-linux-gnu
@@ -144,7 +144,7 @@ jobs:
matrix:
os: [ubuntu-20.04]
rust: [nightly]
- lua: [lua54, lua53, lua52, lua51, luajit]
+ lua: [lua54, lua53, lua52, lua51, luajit, luau]
include:
- os: ubuntu-20.04
target: x86_64-unknown-linux-gnu
@@ -228,7 +228,7 @@ jobs:
runs-on: ubuntu-20.04
strategy:
matrix:
- lua: [lua54, lua53, lua52, lua51, luajit]
+ lua: [lua54, lua53, lua52, lua51, luajit, luau]
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
diff --git a/Cargo.toml b/Cargo.toml
index 076188c..61e6e19 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -34,7 +34,7 @@ lua52 = []
lua51 = []
luajit = []
luajit52 = ["luajit"]
-luau = ["luau-src"]
+luau = ["luau0-src"]
vendored = ["lua-src", "luajit-src"]
module = ["mlua_derive"]
async = ["futures-core", "futures-task", "futures-util"]
@@ -59,7 +59,7 @@ cc = { version = "1.0" }
pkg-config = { version = "0.3.17" }
lua-src = { version = ">= 540.0.0, < 550.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]
rustyline = "9.0"
diff --git a/build/find_vendored.rs b/build/find_vendored.rs
index 4d0d442..d516dfd 100644
--- a/build/find_vendored.rs
+++ b/build/find_vendored.rs
@@ -18,7 +18,7 @@ pub fn probe_lua() -> Option<PathBuf> {
builder.build()
};
#[cfg(feature = "luau")]
- let artifacts = luau_src::Build::new().build();
+ let artifacts = luau0_src::Build::new().build();
#[cfg(not(feature = "module"))]
artifacts.print_cargo_metadata();
diff --git a/src/ffi/compat53.rs b/src/ffi/compat53.rs
index f213e16..8d0fdba 100644
--- a/src/ffi/compat53.rs
+++ b/src/ffi/compat53.rs
@@ -17,6 +17,9 @@ use super::lua52::*;
#[cfg(any(feature = "lua51", feature = "luajit"))]
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) {
while a < b {
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_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 {
let mut ar: lua_Debug = mem::zeroed();
let (mut li, mut le) = (1, 1);
@@ -51,6 +55,27 @@ unsafe fn compat53_countlevels(L: *mut lua_State) -> c_int {
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(
L: *mut lua_State,
mode: *const c_char,
@@ -81,7 +106,7 @@ unsafe fn compat53_checkmode(
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 {
if level == 0 || lua_istable(L, -1) == 0 {
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
}
-#[cfg(any(feature = "lua51", feature = "luajit"))]
-unsafe fn compat53_pushglobalfuncname(L: *mut lua_State, ar: *mut lua_Debug) -> c_int {
+#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
+unsafe fn compat53_pushglobalfuncname(
+ L: *mut lua_State,
+ level: c_int,
+ ar: *mut lua_Debug,
+) -> c_int {
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);
if compat53_findfield(L, top + 1, 2) != 0 {
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"))]
unsafe fn compat53_pushfuncname(L: *mut lua_State, ar: *mut lua_Debug) {
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?
lua_pushliteral(L, "main chunk");
} 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_remove(L, -2); // remove name
} else {
@@ -184,22 +245,22 @@ pub unsafe fn lua_absindex(L: *mut lua_State, mut idx: c_int) -> c_int {
}
// 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;
-#[cfg(any(feature = "lua51", feature = "luajit"))]
+#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
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;
-#[cfg(any(feature = "lua51", feature = "luajit"))]
+#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
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;
-#[cfg(any(feature = "lua51", feature = "luajit"))]
+#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
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;
-#[cfg(any(feature = "lua51", feature = "luajit"))]
+#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
static COMPAT53_ARITH_CODE: &str = r#"
local op,a,b = ...
if op == 0 then return a+b
@@ -212,7 +273,7 @@ elseif op == 6 then return -a
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) {
#[allow(clippy::manual_range_contains)]
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)]
pub unsafe fn lua_copy(L: *mut lua_State, fromidx: c_int, toidx: c_int) {
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;
}
+#[cfg(any(
+ feature = "lua52",
+ feature = "lua51",
+ feature = "luajit",
+ feature = "luau"
+))]
#[inline(always)]
pub unsafe fn lua_tointeger(L: *mut lua_State, i: c_int) -> lua_Integer {
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
// See https://github.com/keplerproject/lua-compat-5.3/issues/40
+#[cfg(any(
+ feature = "lua52",
+ feature = "lua51",
+ feature = "luajit",
+ feature = "luau"
+))]
#[inline(always)]
pub unsafe fn lua_tointegerx(L: *mut lua_State, i: c_int, isnum: *mut c_int) -> lua_Integer {
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;
}
-#[cfg(any(feature = "lua51", feature = "luajit"))]
+#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
#[inline(always)]
pub unsafe fn lua_rawlen(L: *mut lua_State, idx: c_int) -> usize {
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;
-#[cfg(any(feature = "lua51", feature = "luajit"))]
+#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
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;
-#[cfg(any(feature = "lua51", feature = "luajit"))]
+#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
#[inline(always)]
pub unsafe fn lua_compare(L: *mut lua_State, mut idx1: c_int, mut idx2: c_int, op: c_int) -> c_int {
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)]
pub unsafe fn lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char {
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)]
pub unsafe fn lua_pushstring(L: *mut lua_State, s: *const c_char) -> *const c_char {
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)
}
-#[cfg(any(feature = "lua51", feature = "luajit"))]
+#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
#[inline(always)]
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);
@@ -424,6 +497,22 @@ pub unsafe fn lua_getuservalue(L: *mut lua_State, idx: c_int) -> c_int {
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")]
#[inline(always)]
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)]
pub unsafe fn lua_rawsetp(L: *mut lua_State, idx: c_int, p: *const c_void) {
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);
}
+#[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)]
pub unsafe fn lua_dump(
L: *mut lua_State,
@@ -476,7 +593,7 @@ pub unsafe fn lua_dump(
lua_dump_(L, writer, data)
}
-#[cfg(any(feature = "lua51", feature = "luajit"))]
+#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
#[inline(always)]
pub unsafe fn lua_len(L: *mut lua_State, idx: c_int) {
match lua_type(L, idx) {
@@ -565,7 +682,7 @@ pub unsafe fn lua_getextraspace(L: *mut lua_State) -> *mut c_void {
return _ptr;
}
-#[cfg(any(feature = "lua51", feature = "luajit"))]
+#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
#[inline(always)]
pub unsafe fn lua_pushglobaltable(L: *mut lua_State) {
lua_pushvalue(L, LUA_GLOBALSINDEX);
@@ -575,7 +692,7 @@ pub unsafe fn lua_pushglobaltable(L: *mut lua_State) {
// lauxlib ported functions
//
-#[cfg(any(feature = "lua51", feature = "luajit"))]
+#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
#[inline(always)]
pub unsafe fn luaL_checkstack(L: *mut lua_State, sz: c_int, msg: *const c_char) {
if lua_checkstack(L, sz + LUA_MINSTACK) == 0 {
@@ -628,7 +745,7 @@ pub unsafe fn luaL_loadbufferx(
luaL_loadbuffer(L, buff, sz, name)
}
-#[cfg(any(feature = "lua51", feature = "luajit"))]
+#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
#[inline(always)]
pub unsafe fn luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer {
let mut isnum = 0;
@@ -682,6 +799,46 @@ pub unsafe fn luaL_traceback(
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 {
if luaL_callmeta(L, idx, cstr!("__tostring")) == 0 {
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)
}
-#[cfg(any(feature = "lua51", feature = "luajit"))]
+#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
#[inline(always)]
pub unsafe fn luaL_setmetatable(L: *mut lua_State, tname: *const c_char) {
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);
}
-#[cfg(any(feature = "lua51", feature = "luajit"))]
+#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
#[inline(always)]
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);
@@ -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
}
-#[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 {
let abs_i = lua_absindex(L, idx);
luaL_checkstack(L, 3, cstr!("not enough stack slots"));
@@ -791,7 +948,7 @@ pub unsafe fn luaL_requiref(
lua_pop(L, 1);
lua_pushcfunction(L, openf);
lua_pushstring(L, modname);
- #[cfg(any(feature = "lua52", feature = "lua51"))]
+ #[cfg(any(feature = "lua52", feature = "lua51", feature = "luau"))]
{
lua_call(L, 1, 1);
lua_pushvalue(L, -1);
@@ -803,7 +960,7 @@ pub unsafe fn luaL_requiref(
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_setglobal(L, modname);
}
diff --git a/src/ffi/lauxlib.rs b/src/ffi/lauxlib.rs
index 2371edb..a543a7d 100644
--- a/src/ffi/lauxlib.rs
+++ b/src/ffi/lauxlib.rs
@@ -14,6 +14,9 @@ pub use super::lua52::lauxlib::*;
#[cfg(any(feature = "lua51", feature = "luajit"))]
pub use super::lua51::lauxlib::*;
+#[cfg(feature = "luau")]
+pub use super::luau::lauxlib::*;
+
#[cfg(feature = "lua52")]
pub use super::compat53::{luaL_getmetafield, luaL_newmetatable, luaL_requiref, luaL_tolstring};
@@ -24,6 +27,12 @@ pub use super::compat53::{
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.
// 5.4 uses `luaL_Buffer`
pub const LUA_TRACEBACK_STACK: c_int = 11;
diff --git a/src/ffi/lua.rs b/src/ffi/lua.rs
index 53af3a2..d918443 100644
--- a/src/ffi/lua.rs
+++ b/src/ffi/lua.rs
@@ -14,6 +14,9 @@ pub use super::lua52::lua::*;
#[cfg(any(feature = "lua51", feature = "luajit"))]
pub use super::lua51::lua::*;
+#[cfg(feature = "luau")]
+pub use super::luau::lua::*;
+
#[cfg(feature = "lua52")]
pub use super::compat53::{
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,
};
+#[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",))]
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"))]
pub const LUA_MAX_UPVALUES: c_int = 120;
+#[cfg(feature = "luau")]
+pub const LUA_MAX_UPVALUES: c_int = 200;
+
//
// Lua 5.4 compatibility layer
//
@@ -48,7 +62,8 @@ pub const LUA_MAX_UPVALUES: c_int = 120;
feature = "lua53",
feature = "lua52",
feature = "lua51",
- feature = "luajit"
+ feature = "luajit",
+ feature = "luau"
))]
#[inline(always)]
pub unsafe fn lua_resume(
@@ -62,22 +77,32 @@ pub unsafe fn lua_resume(
#[cfg(any(feature = "lua51", feature = "luajit"))]
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);
- if ret == LUA_OK || ret == LUA_YIELD {
+ if (ret == LUA_OK || ret == LUA_YIELD) && !(nres.is_null()) {
*nres = lua_gettop(L);
}
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 {
#[cfg(all(feature = "luajit", feature = "vendored"))]
{
lua_resetthread(L, th);
LUA_OK
}
+ #[cfg(feature = "luau")]
+ {
+ let _ = L;
+ lua_resetthread(th);
+ LUA_OK
+ }
#[cfg(feature = "lua54")]
{
let _ = L;
diff --git a/src/ffi/lualib.rs b/src/ffi/lualib.rs
index 9861460..ff50d85 100644
--- a/src/ffi/lualib.rs
+++ b/src/ffi/lualib.rs
@@ -11,3 +11,6 @@ pub use super::lua52::lualib::*;
#[cfg(any(feature = "lua51", feature = "luajit"))]
pub use super::lua51::lualib::*;
+
+#[cfg(feature = "luau")]
+pub use super::luau::lualib::*;
diff --git a/src/ffi/luau/lauxlib.rs b/src/ffi/luau/lauxlib.rs
new file mode 100644
index 0000000..fe7e6a8
--- /dev/null
+++ b/src/ffi/luau/lauxlib.rs
@@ -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
+//
diff --git a/src/ffi/luau/lua.rs b/src/ffi/luau/lua.rs
index f7d37e4..9c7e361 100644
--- a/src/ffi/luau/lua.rs
+++ b/src/ffi/luau/lua.rs
@@ -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_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.
pub type lua_Alloc = unsafe extern "C" fn(
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_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_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_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_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_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;
@@ -144,8 +148,10 @@ extern "C" {
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_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);
- pub fn lua_pushstring(L: *mut lua_State, s: *const c_char);
+ #[link_name = "lua_pushlstring"]
+ 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
#[link_name = "lua_pushfstringL"]
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)
//
- pub fn lua_gettable(L: *mut lua_State, idx: c_int);
- pub fn lua_getfield(L: *mut lua_State, idx: c_int, k: *const c_char);
+ #[link_name = "lua_gettable"]
+ 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_rawget(L: *mut lua_State, idx: c_int);
- pub fn lua_rawgeti(L: *mut lua_State, idx: c_int, n: c_int);
+ #[link_name = "lua_rawget"]
+ 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_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_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_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_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_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_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_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_status(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_concat(L: *mut lua_State, n: c_int);
// 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)
//
+
#[inline(always)]
pub unsafe fn lua_tonumber(L: *mut lua_State, i: c_int) -> lua_Number {
lua_tonumberx(L, i, ptr::null_mut())
}
#[inline(always)]
-pub unsafe fn lua_tointeger(L: *mut lua_State, i: c_int) -> lua_Integer {
- lua_tointegerx(L, i, ptr::null_mut())
+pub unsafe fn lua_tointeger_(L: *mut lua_State, i: c_int) -> lua_Integer {
+ lua_tointegerx_(L, i, ptr::null_mut())
}
#[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) {
use std::ffi::CString;
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) {
+ lua_pushcclosurek(L, f, ptr::null(), 0, None)
}
-pub unsafe fn lua_pushcfunction(L: *mut lua_State, f: lua_CFunction, debugname: *const c_char) {
+pub unsafe fn lua_pushcfunctiond(L: *mut lua_State, f: lua_CFunction, debugname: *const c_char) {
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,
f: lua_CFunction,
debugname: *const c_char,
@@ -361,8 +382,8 @@ pub unsafe fn lua_setglobal(L: *mut lua_State, var: *const c_char) {
}
#[inline(always)]
-pub unsafe fn lua_getglobal(L: *mut lua_State, var: *const c_char) {
- lua_getfield(L, LUA_GLOBALSINDEX, var)
+pub unsafe fn lua_getglobal_(L: *mut lua_State, var: *const c_char) {
+ lua_getfield_(L, LUA_GLOBALSINDEX, var)
}
#[inline(always)]
diff --git a/src/ffi/luau/luacode.rs b/src/ffi/luau/luacode.rs
new file mode 100644
index 0000000..3f24b65
--- /dev/null
+++ b/src/ffi/luau/luacode.rs
@@ -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;
+}
diff --git a/src/ffi/luau/lualib.rs b/src/ffi/luau/lualib.rs
index bde8a29..2f1ba7e 100644
--- a/src/ffi/luau/lualib.rs
+++ b/src/ffi/luau/lualib.rs
@@ -1,88 +1,8 @@
//! 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::{
- 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
-//
+use super::lua::lua_State;
pub const LUA_COLIBNAME: &str = "coroutine";
pub const LUA_TABLIBNAME: &str = "table";
diff --git a/src/ffi/luau/mod.rs b/src/ffi/luau/mod.rs
index bbdb276..feec60d 100644
--- a/src/ffi/luau/mod.rs
+++ b/src/ffi/luau/mod.rs
@@ -1,7 +1,11 @@
//! Low level bindings to Luau.
+pub use self::lauxlib::*;
pub use self::lua::*;
+pub use self::luacode::*;
pub use self::lualib::*;
+pub mod lauxlib;
pub mod lua;
+pub mod luacode;
pub mod lualib;
diff --git a/src/ffi/mod.rs b/src/ffi/mod.rs
index 9f88188..8382474 100644
--- a/src/ffi/mod.rs
+++ b/src/ffi/mod.rs
@@ -42,6 +42,7 @@ pub const SYS_MIN_ALIGN: usize = 4;
// Hack to avoid stripping a few unused Lua symbols that could be imported
// by C modules in unsafe mode
+#[cfg(not(feature = "luau"))]
pub(crate) fn keep_lua_symbols() {
let mut symbols: Vec<*const extern "C" fn()> = Vec::new();
symbols.push(lua_atpanic as _);
@@ -59,14 +60,25 @@ mod lauxlib;
mod lua;
mod lualib;
-#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
+#[cfg(any(
+ feature = "lua52",
+ feature = "lua51",
+ feature = "luajit",
+ feature = "luau"
+))]
mod compat53;
-#[cfg(any(feature = "lua51", feature = "luajit"))]
-pub mod lua51;
-#[cfg(feature = "lua52")]
-pub mod lua52;
-#[cfg(feature = "lua53")]
-pub mod lua53;
#[cfg(feature = "lua54")]
pub mod lua54;
+
+#[cfg(feature = "lua53")]
+pub mod lua53;
+
+#[cfg(feature = "lua52")]
+pub mod lua52;
+
+#[cfg(any(feature = "lua51", feature = "luajit"))]
+pub mod lua51;
+
+#[cfg(feature = "luau")]
+pub mod luau;
diff --git a/src/function.rs b/src/function.rs
index efc9da0..8c35ef1 100644
--- a/src/function.rs
+++ b/src/function.rs
@@ -1,6 +1,5 @@
-use std::os::raw::{c_int, c_void};
+use std::os::raw::c_int;
use std::ptr;
-use std::slice;
use crate::error::{Error, Result};
use crate::ffi;
@@ -214,7 +213,11 @@ impl<'lua> Function<'lua> {
///
/// If `strip` is true, the binary representation may not include all debug information
/// about the function, to save space.
+ #[cfg(not(feature = "luau"))]
pub fn dump(&self, strip: bool) -> Vec<u8> {
+ use std::os::raw::c_void;
+ use std::slice;
+
unsafe extern "C" fn writer(
_state: *mut ffi::lua_State,
buf: *const c_void,
diff --git a/src/lib.rs b/src/lib.rs
index afc7fa9..ee851d4 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -85,6 +85,7 @@ mod conversion;
mod error;
mod ffi;
mod function;
+#[cfg(not(feature = "luau"))]
mod hook;
mod lua;
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::function::Function;
+#[cfg(not(feature = "luau"))]
pub use crate::hook::{Debug, DebugEvent, DebugNames, DebugSource, DebugStack, HookTriggers};
pub use crate::lua::{AsChunk, Chunk, ChunkMode, GCMode, Lua, LuaOptions};
pub use crate::multi::Variadic;
diff --git a/src/lua.rs b/src/lua.rs
index c4a539c..87a343d 100644
--- a/src/lua.rs
+++ b/src/lua.rs
@@ -14,6 +14,7 @@ use rustc_hash::FxHashMap;
use crate::error::{Error, Result};
use crate::ffi;
use crate::function::Function;
+#[cfg(not(feature = "luau"))]
use crate::hook::{Debug, HookTriggers};
use crate::scope::Scope;
use crate::stdlib::StdLib;
@@ -21,8 +22,8 @@ use crate::string::String;
use crate::table::Table;
use crate::thread::Thread;
use crate::types::{
- Callback, CallbackUpvalue, DestructedUserdataMT, HookCallback, Integer, LightUserData, LuaRef,
- MaybeSend, Number, RegistryKey,
+ Callback, CallbackUpvalue, DestructedUserdataMT, /*HookCallback,*/ Integer, LightUserData,
+ LuaRef, MaybeSend, Number, RegistryKey,
};
use crate::userdata::{
AnyUserData, MetaMethod, UserData, UserDataCell, UserDataFields, UserDataMethods,
@@ -35,6 +36,9 @@ use crate::util::{
};
use crate::value::{FromLua, FromLuaMulti, MultiValue, Nil, ToLua, ToLuaMulti, Value};
+#[cfg(not(feature = "luau"))]
+use crate::types::HookCallback;
+
#[cfg(not(feature = "lua54"))]
use crate::util::push_userdata;
#[cfg(feature = "lua54")]
@@ -103,6 +107,7 @@ struct ExtraData {
#[cfg(feature = "async")]
ref_waker_idx: c_int,
+ #[cfg(not(feature = "luau"))]
hook_callback: Option<HookCallback>,
#[cfg(feature = "lua54")]
warn_callback: Option<WarnCallback>,
@@ -310,6 +315,7 @@ impl Lua {
let mut lua = unsafe { Self::inner_new(libs, options) };
+ #[cfg(not(feature = "luau"))]
if libs.contains(StdLib::PACKAGE) {
mlua_expect!(lua.disable_c_modules(), "Error during disabling C modules");
}
@@ -328,12 +334,16 @@ impl Lua {
///
/// [`StdLib`]: crate::StdLib
pub unsafe fn unsafe_new_with(libs: StdLib, options: LuaOptions) -> Lua {
+ #[cfg(not(feature = "luau"))]
ffi::keep_lua_symbols();
Self::inner_new(libs, options)
}
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(
extra_data: *mut c_void,
ptr: *mut c_void,
@@ -398,9 +408,14 @@ impl Lua {
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
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();
+ // #[cfg(feature = "luau")]
+ // {
+ // ffi::luaL_sandbox(state);
+ // }
+
ffi::luaL_requiref(state, cstr!("_G"), ffi::luaopen_base, 1);
ffi::lua_pop(state, 1);
@@ -427,7 +442,7 @@ impl Lua {
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
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_pushcfunction(lua.state, safe_pcall);
@@ -447,6 +462,9 @@ impl Lua {
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
}
@@ -534,6 +552,7 @@ impl Lua {
recycled_thread_cache: Vec::new(),
#[cfg(feature = "async")]
ref_waker_idx,
+ #[cfg(not(feature = "luau"))]
hook_callback: None,
#[cfg(feature = "lua54")]
warn_callback: None,
@@ -600,9 +619,12 @@ impl Lua {
// If `package` library loaded into a safe lua state then disable C modules
let extra = unsafe { &mut *self.extra.get() };
- let curr_libs = extra.libs;
- if self.safe && (curr_libs ^ (curr_libs | libs)).contains(StdLib::PACKAGE) {
- mlua_expect!(self.disable_c_modules(), "Error during disabling C modules");
+ #[cfg(not(feature = "luau"))]
+ {
+ let curr_libs = extra.libs;
+ if self.safe && (curr_libs ^ (curr_libs | libs)).contains(StdLib::PACKAGE) {
+ mlua_expect!(self.disable_c_modules(), "Error during disabling C modules");
+ }
}
extra.libs |= libs;
@@ -795,6 +817,7 @@ impl Lua {
///
/// [`HookTriggers`]: crate::HookTriggers
/// [`HookTriggers.every_nth_instruction`]: crate::HookTriggers::every_nth_instruction
+ #[cfg(not(feature = "luau"))]
pub fn set_hook<F>(&self, triggers: HookTriggers, callback: F) -> Result<()>
where
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
/// previously set.
+ #[cfg(not(feature = "luau"))]
pub fn remove_hook(&self) {
// If main_state is not available, then sethook wasn't called.
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).
///
/// [`Debug`]: crate::hook::Debug
+ #[cfg(not(feature = "luau"))]
pub fn inspect_stack(&self, level: usize) -> Option<Debug> {
unsafe {
let mut ar: ffi::lua_Debug = mem::zeroed();
@@ -961,7 +986,12 @@ impl Lua {
/// Returns true if the garbage collector is currently running automatically.
///
/// 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 {
let state = self.main_state.unwrap_or(self.state);
unsafe { ffi::lua_gc(state, ffi::LUA_GCISRUNNING, 0) != 0 }
@@ -1018,6 +1048,7 @@ impl Lua {
/// [documentation][lua_doc].
///
/// [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 {
let state = self.main_state.unwrap_or(self.state);
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].
///
/// [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 {
let state = self.main_state.unwrap_or(self.state);
@@ -1138,6 +1170,7 @@ impl Lua {
}
Some(ChunkMode::Binary) => cstr!("b"),
Some(ChunkMode::Text) => cstr!("t"),
+ #[cfg(not(feature = "luau"))]
None if source.starts_with(ffi::LUA_SIGNATURE) && self.safe => {
return Err(Error::SafetyError(
"binary chunks are disabled in safe mode".to_string(),
@@ -1158,7 +1191,7 @@ impl Lua {
self.push_value(env)?;
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
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);
}
Ok(Function(self.pop_ref()))
@@ -1488,7 +1521,7 @@ impl Lua {
assert_stack(self.state, 1);
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
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);
Table(self.pop_ref())
}
@@ -2329,7 +2362,12 @@ impl Lua {
where
'lua: 'callback,
{
- #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
+ #[cfg(any(
+ feature = "lua54",
+ feature = "lua53",
+ feature = "lua52",
+ feature = "luau"
+ ))]
unsafe {
let libs = (*self.extra.get()).libs;
if !libs.contains(StdLib::COROUTINE) {
@@ -2551,6 +2589,7 @@ impl Lua {
}
}
+ #[cfg(not(feature = "luau"))]
fn disable_c_modules(&self) -> Result<()> {
let package: Table = self.globals().get("package")?;
@@ -2577,6 +2616,42 @@ impl Lua {
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> {
let _sg = StackGuard::new(state);
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
// "return", then as a statement. This is the same thing the
// actual lua repl does.
- if self.source.starts_with(ffi::LUA_SIGNATURE) {
+ if self.source[0] < b'\n' {
self.call(())
} else if let Ok(function) = self.lua.load_chunk(
&self.expression_source(),
@@ -2768,7 +2843,7 @@ impl<'lua, 'a> Chunk<'lua, 'a> {
'lua: 'fut,
R: FromLuaMulti<'lua> + 'fut,
{
- if self.source.starts_with(ffi::LUA_SIGNATURE) {
+ if self.source[0] < b'\n' {
self.call_async(())
} else if let Ok(function) = self.lua.load_chunk(
&self.expression_source(),
@@ -2886,9 +2961,9 @@ where
let prealloc_failure = match extra.wrapped_failures_cache.pop() {
Some(index) => PreallocatedFailure::Cached(index),
None => {
- let ud = ffi::lua_newuserdata(state, mem::size_of::<WrappedFailure>());
+ let ud = WrappedFailure::new_userdata(state);
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")]
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) {
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);
}
+ #[cfg(not(feature = "luau"))]
if libs.contains(StdLib::IO) {
requiref(state, ffi::LUA_IOLIBNAME, ffi::luaopen_io, 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);
}
- #[cfg(any(feature = "lua54", feature = "lua53"))]
+ #[cfg(any(feature = "lua54", feature = "lua53", feature = "luau"))]
{
if libs.contains(StdLib::UTF8) {
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) {
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);
}
+ #[cfg(not(feature = "luau"))]
if libs.contains(StdLib::PACKAGE) {
requiref(state, ffi::LUA_LOADLIBNAME, ffi::luaopen_package, 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(())
}
-// We move `extra` (`MutexGuard`) here to correctly drop it if panic
unsafe fn ref_stack_pop(extra: &mut ExtraData) -> c_int {
if let Some(free) = extra.ref_free.pop() {
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)));
}
- #[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)
where
T: Clone,
@@ -3274,7 +3355,7 @@ impl<'lua, T: 'static + UserData> UserDataMethods<'lua, T> for StaticUserDataMet
.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)
where
S: Into<MetaMethod>,
diff --git a/src/scope.rs b/src/scope.rs
index ea31f0b..ffaa400 100644
--- a/src/scope.rs
+++ b/src/scope.rs
@@ -3,7 +3,6 @@ use std::cell::{Cell, RefCell};
use std::marker::PhantomData;
use std::mem;
use std::os::raw::{c_int, c_void};
-use std::ptr;
use std::rc::Rc;
#[cfg(feature = "serialize")]
@@ -18,8 +17,8 @@ use crate::userdata::{
AnyUserData, MetaMethod, UserData, UserDataCell, UserDataFields, UserDataMethods,
};
use crate::util::{
- assert_stack, check_stack, get_userdata, init_userdata_metatable, push_table, rawset_field,
- take_userdata, StackGuard,
+ assert_stack, check_stack, get_userdata, init_userdata_metatable, push_table, push_userdata,
+ rawset_field, take_userdata, StackGuard,
};
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_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_setuservalue(state, -2);
@@ -264,7 +263,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
fn wrap_method<'scope, 'lua, 'callback: 'scope, T: 'scope>(
scope: &Scope<'lua, 'scope>,
data: Rc<RefCell<T>>,
- data_ptr: *const c_void,
+ ud_ptr: *const c_void,
method: NonStaticMethod<'callback, T>,
) -> Result<Function<'lua>> {
// 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);
check_stack(lua.state, 2)?;
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(());
}
}
@@ -336,8 +335,9 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 13)?;
+ #[cfg(not(feature = "luau"))]
#[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 =
ffi::lua_newuserdata(state, mem::size_of::<UserDataCell<Rc<RefCell<T>>>>());
@@ -350,13 +350,22 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
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
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)?;
for (k, m) in ud_methods.meta_methods {
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())?;
}
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)?;
for (k, m) in ud_fields.field_getters {
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)?;
}
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)?;
for (k, m) in ud_fields.field_setters {
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)?;
}
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)?;
for (k, m) in ud_methods.methods {
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)?;
}
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);
// 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);
let ud = AnyUserData(lua.pop_ref());
lua.register_userdata_metatable(mt_ptr, None);
@@ -446,7 +456,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
ffi::lua_pushnil(state);
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_setuservalue(state, -2);
@@ -532,7 +542,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
// First, get the environment table
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
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);
// 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)
where
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)
where
S: Into<MetaMethod>,
diff --git a/src/stdlib.rs b/src/stdlib.rs
index fb0f1b8..fd34c43 100644
--- a/src/stdlib.rs
+++ b/src/stdlib.rs
@@ -9,11 +9,17 @@ impl StdLib {
/// [`coroutine`](https://www.lua.org/manual/5.4/manual.html#6.2) library
///
/// 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);
/// [`table`](https://www.lua.org/manual/5.4/manual.html#6.6) library
pub const TABLE: StdLib = StdLib(1 << 1);
/// [`io`](https://www.lua.org/manual/5.4/manual.html#6.8) library
+ #[cfg(not(feature = "luau"))]
pub const IO: StdLib = StdLib(1 << 2);
/// [`os`](https://www.lua.org/manual/5.4/manual.html#6.9) library
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
///
/// 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);
/// [`bit`](https://www.lua.org/manual/5.2/manual.html#6.7) library
///
/// 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);
/// [`math`](https://www.lua.org/manual/5.4/manual.html#6.7) library
pub const MATH: StdLib = StdLib(1 << 7);
/// [`package`](https://www.lua.org/manual/5.4/manual.html#6.3) library
+ #[cfg(not(feature = "luau"))]
pub const PACKAGE: StdLib = StdLib(1 << 8);
/// [`jit`](http://luajit.org/ext_jit.html) library
///
diff --git a/src/types.rs b/src/types.rs
index cd4b13f..ed7305b 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -11,6 +11,7 @@ use futures_core::future::LocalBoxFuture;
use crate::error::Result;
use crate::ffi;
+#[cfg(not(feature = "luau"))]
use crate::hook::Debug;
use crate::lua::Lua;
use crate::util::{assert_stack, StackGuard};
@@ -48,11 +49,10 @@ pub(crate) struct AsyncPollUpvalue<'lua> {
pub(crate) lua: Lua,
pub(crate) fut: LocalBoxFuture<'lua, Result<MultiValue<'lua>>>,
}
-
-#[cfg(feature = "send")]
+#[cfg(all(feature = "send", not(feature = "luau")))]
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<()>>>;
#[cfg(all(feature = "send", feature = "lua54"))]
diff --git a/src/userdata.rs b/src/userdata.rs
index bf0706c..0680779 100644
--- a/src/userdata.rs
+++ b/src/userdata.rs
@@ -419,7 +419,7 @@ pub trait UserDataMethods<'lua, T: UserData> {
/// Requires `feature = "async"`
///
/// [`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")))]
fn add_async_meta_method<S, A, R, M, MR>(&mut self, name: S, method: M)
where
@@ -461,7 +461,7 @@ pub trait UserDataMethods<'lua, T: UserData> {
/// Requires `feature = "async"`
///
/// [`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")))]
fn add_async_meta_function<S, A, R, F, FR>(&mut self, name: S, function: F)
where
@@ -839,7 +839,7 @@ impl<'lua> AnyUserData<'lua> {
ffi::lua_pushnil(lua.state);
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_setuservalue(lua.state, -2);
@@ -865,6 +865,7 @@ impl<'lua> AnyUserData<'lua> {
///
/// [`get_user_value`]: #method.get_user_value
/// [`set_nth_user_value`]: #method.set_nth_user_value
+ // #[cfg(not(feature = "luau"))]
#[inline]
pub fn set_user_value<V: ToLua<'lua>>(&self, v: V) -> Result<()> {
self.set_nth_user_value(1, v)
@@ -876,6 +877,7 @@ impl<'lua> AnyUserData<'lua> {
///
/// [`set_user_value`]: #method.set_user_value
/// [`get_nth_user_value`]: #method.get_nth_user_value
+ // #[cfg(not(feature = "luau"))]
#[inline]
pub fn get_user_value<V: FromLua<'lua>>(&self) -> Result<V> {
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.
///
/// [`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<()> {
if n < 1 || n > u16::MAX as usize {
return Err(Error::RuntimeError(
@@ -945,6 +948,7 @@ impl<'lua> AnyUserData<'lua> {
/// For other Lua versions this functionality is provided using a wrapping table.
///
/// [`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> {
if n < 1 || n > u16::MAX as usize {
return Err(Error::RuntimeError(
@@ -986,6 +990,7 @@ impl<'lua> AnyUserData<'lua> {
/// The value can be retrieved with [`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<()>
where
S: AsRef<[u8]> + ?Sized,
@@ -1025,6 +1030,7 @@ impl<'lua> AnyUserData<'lua> {
/// Returns an associated value by name set by [`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>
where
S: AsRef<[u8]> + ?Sized,
diff --git a/src/util.rs b/src/util.rs
index 75caa9f..b2c25d8 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -278,6 +278,7 @@ where
}
// Internally uses 3 stack spaces, does not call checkstack.
+#[cfg(not(feature = "luau"))]
#[inline]
pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T) -> Result<()> {
let ud = protect_lua!(state, 0, 1, |state| {
@@ -288,6 +289,27 @@ pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T) -> Result<()> {
}
// 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.
#[cfg(feature = "lua54")]
#[inline]
pub unsafe fn push_userdata_uv<T>(state: *mut ffi::lua_State, t: T, nuvalue: c_int) -> Result<()> {
@@ -316,8 +338,11 @@ pub unsafe fn take_userdata<T>(state: *mut ffi::lua_State) -> T {
// after the first call to __gc.
get_destructed_userdata_metatable(state);
ffi::lua_setmetatable(state, -2);
- let ud = get_userdata(state, -1);
+ let ud = get_userdata::<T>(state, -1);
ffi::lua_pop(state, 1);
+ if cfg!(feature = "luau") {
+ *(ud.offset(1) as *mut u8) = 1; // Mark as destructed
+ }
ptr::read(ud)
}
@@ -508,8 +533,11 @@ pub unsafe fn init_userdata_metatable<T>(
rawset_field(state, -2, "__newindex")?;
}
- ffi::lua_pushcfunction(state, userdata_destructor::<T>);
- rawset_field(state, -2, "__gc")?;
+ #[cfg(not(feature = "luau"))]
+ {
+ ffi::lua_pushcfunction(state, userdata_destructor::<T>);
+ rawset_field(state, -2, "__gc")?;
+ }
ffi::lua_pushboolean(state, 0);
rawset_field(state, -2, "__metatable")?;
@@ -519,6 +547,7 @@ pub unsafe fn init_userdata_metatable<T>(
Ok(())
}
+#[cfg(not(feature = "luau"))]
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
// 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
// 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);
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
}
}
+ #[cfg(feature = "luau")]
+ Some(ffi::lua_mainthread(state))
}
// 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)?;
- ffi::lua_pushcfunction(state, userdata_destructor::<T>);
- rawset_field(state, -2, "__gc")?;
+ #[cfg(not(feature = "luau"))]
+ {
+ ffi::lua_pushcfunction(state, userdata_destructor::<T>);
+ rawset_field(state, -2, "__gc")?;
+ }
ffi::lua_pushboolean(state, 0);
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 {
+ None,
Error(Error),
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
// panicking.
pub(crate) unsafe fn to_string(state: *mut ffi::lua_State, index: c_int) -> String {
diff --git a/tests/async.rs b/tests/async.rs
index dead884..2bfde03 100644
--- a/tests/async.rs
+++ b/tests/async.rs
@@ -299,7 +299,7 @@ async fn test_async_userdata() -> Result<()> {
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 {
let n = data.0.load(Ordering::Relaxed);
Delay::new(Duration::from_millis(n)).await;
@@ -363,7 +363,7 @@ async fn test_async_userdata() -> Result<()> {
.exec_async()
.await?;
- #[cfg(not(feature = "lua51"))]
+ #[cfg(not(any(feature = "lua51", feature = "luau")))]
lua.load(
r#"
userdata:set_value(15)
diff --git a/tests/function.rs b/tests/function.rs
index a7bdd9f..f245c37 100644
--- a/tests/function.rs
+++ b/tests/function.rs
@@ -93,6 +93,7 @@ fn test_c_function() -> Result<()> {
Ok(())
}
+#[cfg(not(feature = "luau"))]
#[test]
fn test_dump() -> Result<()> {
let lua = unsafe { Lua::unsafe_new() };
diff --git a/tests/hooks.rs b/tests/hooks.rs
index 3e8e876..8c44b5d 100644
--- a/tests/hooks.rs
+++ b/tests/hooks.rs
@@ -1,3 +1,5 @@
+#![cfg(not(feature = "luau"))]
+
use std::cell::RefCell;
use std::ops::Deref;
use std::str;
diff --git a/tests/memory.rs b/tests/memory.rs
index 45332f4..36d094e 100644
--- a/tests/memory.rs
+++ b/tests/memory.rs
@@ -41,7 +41,12 @@ fn test_gc_control() -> Result<()> {
#[cfg(feature = "lua54")]
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());
lua.gc_stop();
diff --git a/tests/tests.rs b/tests/tests.rs
index 6c6b132..2d99911 100644
--- a/tests/tests.rs
+++ b/tests/tests.rs
@@ -11,6 +11,7 @@ use mlua::{
UserData, Value, Variadic,
};
+#[cfg(not(feature = "luau"))]
#[test]
fn test_safety() -> Result<()> {
let lua = Lua::new();
@@ -120,6 +121,7 @@ fn test_exec() -> Result<()> {
"#,
)
.eval()?;
+ println!("checkpoint");
assert!(module.contains_key("func")?);
assert_eq!(
module.get::<_, Function>("func")?.call::<_, String>(())?,
@@ -150,6 +152,7 @@ fn test_eval() -> Result<()> {
Ok(())
}
+#[cfg(not(feature = "luau"))]
#[test]
fn test_load_mode() -> Result<()> {
let lua = unsafe { Lua::unsafe_new() };
@@ -250,15 +253,7 @@ fn test_error() -> Result<()> {
}
}
- impl error::Error for TestError {
- fn description(&self) -> &str {
- "test error"
- }
-
- fn cause(&self) -> Option<&dyn error::Error> {
- None
- }
- }
+ impl error::Error for TestError {}
let lua = Lua::new();
@@ -295,8 +290,8 @@ fn test_error() -> Result<()> {
end, 3)
local function handler(err)
- if string.match(_VERSION, ' 5%.1$') or string.match(_VERSION, ' 5%.2$') then
- -- Special case for Lua 5.1/5.2
+ if string.match(_VERSION, ' 5%.1$') or string.match(_VERSION, ' 5%.2$') or _VERSION == "Luau" then
+ -- Special case for Lua 5.1/5.2 and Luau
local caps = string.match(err, ': (%d+)$')
if caps then
err = caps
@@ -1096,7 +1091,11 @@ fn test_context_thread() -> Result<()> {
))]
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)?;
Ok(())
@@ -1170,6 +1169,7 @@ fn test_load_from_function() -> Result<()> {
Ok(())
}
+#[cfg(not(feature = "luau"))]
#[test]
fn test_inspect_stack() -> Result<()> {
let lua = Lua::new();
diff --git a/tests/thread.rs b/tests/thread.rs
index ab687ad..5873680 100644
--- a/tests/thread.rs
+++ b/tests/thread.rs
@@ -155,7 +155,8 @@ fn test_coroutine_from_closure() -> Result<()> {
feature = "lua54",
feature = "lua53",
feature = "lua52",
- feature = "luajit"
+ feature = "luajit",
+ feature = "luau"
))]
let thrd: Thread = lua.load("coroutine.create(main)").eval()?;
#[cfg(feature = "lua51")]
diff --git a/tests/userdata.rs b/tests/userdata.rs
index cba2638..c78b1db 100644
--- a/tests/userdata.rs
+++ b/tests/userdata.rs
@@ -350,7 +350,7 @@ fn test_userdata_take() -> Result<()> {
}
#[test]
-fn test_destroy_userdata() -> Result<()> {
+fn test_userdata_destroy() -> Result<()> {
struct MyUserdata(Arc<()>);
impl UserData for MyUserdata {}
@@ -358,12 +358,15 @@ fn test_destroy_userdata() -> Result<()> {
let rc = Arc::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
- let _ = lua.globals().raw_remove("userdata")?;
+ // Should destroy all objects
+ lua.globals().raw_remove("userdata")?;
+ lua.gc_collect()?;
lua.gc_collect()?;
assert_eq!(Arc::strong_count(&rc), 1);