More ffi module refactoring

This commit is contained in:
Alex Orlenko 2022-02-25 15:08:56 +00:00
parent c322e028e2
commit eed7b1f3af
No known key found for this signature in database
GPG key ID: 4C150C250863B96D
18 changed files with 966 additions and 720 deletions

View file

@ -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 }
luau0-src = { version = "1", optional = true, git = "https://github.com/khvzak/luau-src-rs.git" }
luau0-src = { version = "0.1.0", optional = true }
[dev-dependencies]
rustyline = "9.0"

View file

@ -1,38 +0,0 @@
//! Contains definitions from `lauxlib.h`.
use std::os::raw::c_int;
#[cfg(feature = "lua54")]
pub use super::lua54::lauxlib::*;
#[cfg(feature = "lua53")]
pub use super::lua53::lauxlib::*;
#[cfg(feature = "lua52")]
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};
#[cfg(any(feature = "lua51", feature = "luajit"))]
pub use super::compat53::{
luaL_checkstack, luaL_getmetafield, luaL_getsubtable, luaL_len, luaL_loadbufferx,
luaL_newmetatable, luaL_requiref, luaL_setfuncs, luaL_setmetatable, luaL_testudata,
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;

View file

@ -1,111 +0,0 @@
//! Contains definitions from `lua.h`.
use std::os::raw::c_int;
#[cfg(feature = "lua54")]
pub use super::lua54::lua::*;
#[cfg(feature = "lua53")]
pub use super::lua53::lua::*;
#[cfg(feature = "lua52")]
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,
lua_getuservalue, lua_isinteger, lua_pushlstring, lua_rawget, lua_rawgeti, lua_rawgetp,
lua_rawseti, lua_rotate, lua_seti, lua_stringtonumber, lua_tointeger, lua_tointegerx,
LUA_EXTRASPACE,
};
#[cfg(any(feature = "lua51", feature = "luajit"))]
pub use super::compat53::{
lua_absindex, lua_arith, lua_compare, lua_copy, lua_dump, 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, 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;
#[cfg(any(feature = "lua51", all(feature = "luajit", not(feature = "vendored"))))]
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
//
#[cfg(any(
feature = "lua53",
feature = "lua52",
feature = "lua51",
feature = "luajit",
feature = "luau"
))]
#[inline(always)]
pub unsafe fn lua_resume(
L: *mut lua_State,
from: *mut lua_State,
narg: c_int,
nres: *mut c_int,
) -> c_int {
#[cfg(any(feature = "lua51", feature = "luajit"))]
let _ = from;
#[cfg(any(feature = "lua51", feature = "luajit"))]
let ret = lua_resume_(L, narg);
#[cfg(any(feature = "lua53", feature = "lua52", feature = "luau"))]
let ret = lua_resume_(L, from, narg);
if (ret == LUA_OK || ret == LUA_YIELD) && !(nres.is_null()) {
*nres = lua_gettop(L);
}
ret
}
#[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;
lua_resetthread(th)
}
}

View file

@ -1,25 +1,16 @@
//! Lua 5.3 compatibility layer for Lua 5.1/5.2
//! MLua compatibility layer for Lua 5.1/JIT
//!
//! Based on github.com/keplerproject/lua-compat-5.3
#![allow(clippy::needless_return)]
use std::convert::TryInto;
use std::ffi::CStr;
use std::mem;
use std::os::raw::{c_char, c_int, c_void};
use std::ptr;
use std::str::FromStr;
#[cfg(feature = "lua52")]
use super::lua52::*;
#[cfg(any(feature = "lua51", feature = "luajit"))]
use super::lua51::*;
#[cfg(feature = "luau")]
use super::luau::*;
use super::lua::*;
use super::lauxlib::*;
#[inline(always)]
unsafe fn compat53_reverse(L: *mut lua_State, mut a: c_int, mut b: c_int) {
while a < b {
lua_pushvalue(L, a);
@ -34,7 +25,6 @@ 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);
@ -47,28 +37,7 @@ unsafe fn compat53_countlevels(L: *mut lua_State) -> c_int {
while li < le {
let m = (li + le) / 2;
if lua_getstack(L, m, &mut ar) != 0 {
li = m + 1;
} else {
le = m;
}
}
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;
li = m + 1
} else {
le = m;
}
@ -106,7 +75,6 @@ unsafe fn compat53_checkmode(
LUA_OK
}
#[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
@ -132,21 +100,12 @@ unsafe fn compat53_findfield(L: *mut lua_State, objidx: c_int, level: c_int) ->
}
lua_pop(L, 1); // remove value
}
return 0; // not found
0 // not found
}
#[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 {
unsafe fn compat53_pushglobalfuncname(L: *mut lua_State, ar: *mut lua_Debug) -> c_int {
let top = lua_gettop(L);
// push function
#[cfg(not(feature = "luau"))]
lua_getinfo(L, cstr!("f"), ar);
#[cfg(feature = "luau")]
lua_getinfo(L, level, cstr!("f"), ar);
lua_getinfo(L, cstr!("f"), ar); // push function
lua_pushvalue(L, LUA_GLOBALSINDEX);
if compat53_findfield(L, top + 1, 2) != 0 {
lua_copy(L, -1, top + 1); // move name to proper place
@ -158,35 +117,6 @@ unsafe fn compat53_pushglobalfuncname(
}
}
#[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 {
// is there a name?
@ -195,7 +125,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, -1, ar) != 0 {
if compat53_pushglobalfuncname(L, ar) != 0 {
lua_pushfstring(L, cstr!("function '%s'"), lua_tostring(L, -1));
lua_remove(L, -2); // remove name
} else {
@ -211,31 +141,10 @@ unsafe fn compat53_pushfuncname(L: *mut lua_State, ar: *mut lua_Debug) {
}
}
unsafe fn compat53_call_lua(L: *mut lua_State, code: &str, nargs: c_int, nret: c_int) {
lua_rawgetp(L, LUA_REGISTRYINDEX, code.as_ptr() as *const c_void);
if lua_type(L, -1) != LUA_TFUNCTION {
lua_pop(L, 1);
if luaL_loadbuffer(
L,
code.as_ptr() as *const c_char,
code.as_bytes().len(),
cstr!("=none"),
) != 0
{
lua_error(L);
}
lua_pushvalue(L, -1);
lua_rawsetp(L, LUA_REGISTRYINDEX, code.as_ptr() as *const c_void);
}
lua_insert(L, -nargs - 1);
lua_call(L, nargs, nret);
}
//
// lua ported functions
//
#[cfg(any(feature = "lua51", feature = "luajit"))]
#[inline(always)]
pub unsafe fn lua_absindex(L: *mut lua_State, mut idx: c_int) -> c_int {
if idx < 0 && idx > LUA_REGISTRYINDEX {
@ -244,50 +153,6 @@ pub unsafe fn lua_absindex(L: *mut lua_State, mut idx: c_int) -> c_int {
idx
}
// Comparison and arithmetic functions
#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
pub const LUA_OPADD: c_int = 0;
#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
pub const LUA_OPSUB: c_int = 1;
#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
pub const LUA_OPMUL: c_int = 2;
#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
pub const LUA_OPDIV: c_int = 3;
#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
pub const LUA_OPMOD: c_int = 4;
#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
pub const LUA_OPPOW: c_int = 5;
#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
pub const LUA_OPUNM: c_int = 6;
#[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
elseif op == 1 then return a-b
elseif op == 2 then return a*b
elseif op == 3 then return a/b
elseif op == 4 then return a%b
elseif op == 5 then return a^b
elseif op == 6 then return -a
end
"#;
#[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 {
luaL_error(L, cstr!("invalid 'op' argument for lua_arith"));
}
luaL_checkstack(L, 5, cstr!("not enough stack slots"));
if op == LUA_OPUNM {
lua_pushvalue(L, -1);
}
lua_pushnumber(L, op as lua_Number);
lua_insert(L, -3);
compat53_call_lua(L, COMPAT53_ARITH_CODE, 3, 1);
}
pub unsafe fn lua_rotate(L: *mut lua_State, mut idx: c_int, mut n: c_int) {
idx = lua_absindex(L, idx);
let n_elems = lua_gettop(L) - idx + 1;
@ -303,7 +168,6 @@ pub unsafe fn lua_rotate(L: *mut lua_State, mut idx: c_int, mut n: c_int) {
}
}
#[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);
@ -321,42 +185,23 @@ pub unsafe fn lua_isinteger(L: *mut lua_State, idx: c_int) -> c_int {
return 1;
}
}
return 0;
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())
}
#[cfg(any(feature = "lua51", feature = "luajit"))]
#[inline(always)]
pub unsafe fn lua_tonumberx(L: *mut lua_State, i: c_int, isnum: *mut c_int) -> lua_Number {
let n = lua_tonumber(L, i);
if !isnum.is_null() {
*isnum = if n != 0.0 || lua_isnumber(L, i) != 0 {
1
} else {
0
};
*isnum = (n != 0.0 || lua_isnumber(L, i) != 0) as c_int;
}
return n;
n
}
// 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;
@ -371,44 +216,14 @@ pub unsafe fn lua_tointegerx(L: *mut lua_State, i: c_int, isnum: *mut c_int) ->
if !isnum.is_null() {
*isnum = 0;
}
return 0;
0
}
#[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", feature = "luau"))]
pub const LUA_OPEQ: c_int = 0;
#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
pub const LUA_OPLT: c_int = 1;
#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
pub const LUA_OPLE: c_int = 2;
#[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 {
LUA_OPEQ => lua_equal(L, idx1, idx2),
LUA_OPLT => lua_lessthan(L, idx1, idx2),
LUA_OPLE => {
luaL_checkstack(L, 5, cstr!("not enough stack slots"));
idx1 = lua_absindex(L, idx1);
idx2 = lua_absindex(L, idx2);
lua_pushvalue(L, idx1);
lua_pushvalue(L, idx2);
compat53_call_lua(L, "local a,b=...\nreturn a<=b\n", 2, 1);
let result = lua_toboolean(L, -1);
lua_pop(L, 1);
result
}
_ => luaL_error(L, cstr!("invalid 'op' argument for lua_compare")),
}
}
#[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 {
@ -419,17 +234,6 @@ pub unsafe fn lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize) ->
lua_tostring(L, -1)
}
#[cfg(feature = "lua52")]
#[inline(always)]
pub unsafe fn lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char {
if l == 0 {
lua_pushlstring_(L, cstr!(""), 0)
} else {
lua_pushlstring_(L, s, l)
}
}
#[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);
@ -458,8 +262,7 @@ pub unsafe fn lua_getfield(L: *mut lua_State, idx: c_int, k: *const c_char) -> c
pub unsafe fn lua_geti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) -> c_int {
idx = lua_absindex(L, idx);
lua_pushinteger(L, n);
lua_gettable(L, idx);
lua_type(L, -1)
lua_gettable(L, idx)
}
#[inline(always)]
@ -470,56 +273,24 @@ pub unsafe fn lua_rawget(L: *mut lua_State, idx: c_int) -> c_int {
#[inline(always)]
pub unsafe fn lua_rawgeti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int {
lua_rawgeti_(L, idx, n.try_into().expect("cannot convert to lua_Integer"));
let n = n.try_into().expect("cannot convert index to lua_Integer");
lua_rawgeti_(L, idx, n);
lua_type(L, -1)
}
#[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);
lua_pushlightuserdata(L, p as *mut c_void);
lua_rawget(L, abs_i);
lua_type(L, -1)
lua_rawget(L, abs_i)
}
#[cfg(feature = "lua52")]
#[inline(always)]
pub unsafe fn lua_rawgetp(L: *mut lua_State, idx: c_int, p: *const c_void) -> c_int {
lua_rawgetp_(L, idx, p);
lua_type(L, -1)
}
#[cfg(any(feature = "lua51", feature = "luajit"))]
#[inline(always)]
pub unsafe fn lua_getuservalue(L: *mut lua_State, idx: c_int) -> c_int {
lua_getfenv(L, idx);
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 {
lua_getuservalue_(L, idx);
lua_type(L, -1)
}
#[inline(always)]
pub unsafe fn lua_seti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) {
luaL_checkstack(L, 1, cstr!("not enough stack slots available"));
@ -531,14 +302,10 @@ pub unsafe fn lua_seti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) {
#[inline(always)]
pub unsafe fn lua_rawseti(L: *mut lua_State, idx: c_int, n: lua_Integer) {
lua_rawseti_(
L,
idx,
n.try_into().expect("cannot convert index from lua_Integer"),
)
let n = n.try_into().expect("cannot convert index from lua_Integer");
lua_rawseti_(L, idx, n)
}
#[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);
@ -548,41 +315,12 @@ pub unsafe fn lua_rawsetp(L: *mut lua_State, idx: c_int, p: *const c_void) {
lua_rawset(L, abs_i);
}
#[cfg(any(feature = "lua51", feature = "luajit"))]
#[inline(always)]
pub unsafe fn lua_setuservalue(L: *mut lua_State, idx: c_int) {
luaL_checktype(L, -1, LUA_TTABLE);
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,
@ -593,7 +331,6 @@ pub unsafe fn lua_dump(
lua_dump_(L, writer, data)
}
#[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) {
@ -616,83 +353,29 @@ pub unsafe fn lua_len(L: *mut lua_State, idx: c_int) {
}
}
#[inline(always)]
pub unsafe fn lua_stringtonumber(L: *mut lua_State, s: *const c_char) -> usize {
let cs = CStr::from_ptr(s);
if let Ok(rs) = cs.to_str() {
if let Ok(n) = lua_Number::from_str(rs.trim()) {
lua_pushnumber(L, n);
return cs.to_bytes_with_nul().len();
}
}
0
}
pub const LUA_EXTRASPACE: usize = mem::size_of::<*const ()>();
#[allow(clippy::branches_sharing_code)]
pub unsafe fn lua_getextraspace(L: *mut lua_State) -> *mut c_void {
luaL_checkstack(L, 4, cstr!("not enough stack slots available"));
lua_pushliteral(L, "__compat53_extraspace");
lua_pushvalue(L, -1);
lua_rawget(L, LUA_REGISTRYINDEX);
if lua_istable(L, -1) == 0 {
lua_pop(L, 1);
lua_createtable(L, 0, 2);
lua_createtable(L, 0, 1);
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);
let is_main = lua_pushthread(L);
lua_rawget(L, -2);
let mut _ptr = lua_touserdata(L, -1);
if _ptr.is_null() {
lua_pop(L, 1);
_ptr = lua_newuserdata(L, LUA_EXTRASPACE);
if is_main != 0 {
// mem::size_of::<c_void>() == 1
ptr::write_bytes(_ptr, 0, LUA_EXTRASPACE);
lua_pushthread(L);
lua_pushvalue(L, -2);
lua_rawset(L, -4);
lua_pushboolean(L, 1);
lua_pushvalue(L, -2);
lua_rawset(L, -4);
} else {
lua_pushboolean(L, 1);
lua_rawget(L, -3);
let mptr = lua_touserdata(L, -1);
if !mptr.is_null() {
ptr::copy_nonoverlapping(mptr, _ptr, LUA_EXTRASPACE)
} else {
ptr::write_bytes(_ptr, 0, LUA_EXTRASPACE);
}
lua_pop(L, 1);
lua_pushthread(L);
lua_pushvalue(L, -2);
lua_rawset(L, -4);
}
}
lua_pop(L, 2);
return _ptr;
}
#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
#[inline(always)]
pub unsafe fn lua_pushglobaltable(L: *mut lua_State) {
lua_pushvalue(L, LUA_GLOBALSINDEX);
}
#[inline(always)]
pub unsafe fn lua_resume(
L: *mut lua_State,
_from: *mut lua_State,
narg: c_int,
nres: *mut c_int,
) -> c_int {
let ret = lua_resume_(L, narg);
if (ret == LUA_OK || ret == LUA_YIELD) && !(nres.is_null()) {
*nres = lua_gettop(L);
}
ret
}
//
// lauxlib ported functions
//
#[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 {
@ -717,7 +400,7 @@ pub unsafe fn luaL_getmetafield(L: *mut lua_State, obj: c_int, e: *const c_char)
#[inline(always)]
pub unsafe fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_int {
if luaL_newmetatable_(L, tname) != 0 {
lua_pushstring(L, tname);
lua_pushstring_(L, tname);
lua_setfield(L, -2, cstr!("__name"));
1
} else {
@ -725,7 +408,6 @@ pub unsafe fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_in
}
}
#[cfg(any(feature = "lua51", feature = "luajit"))]
#[inline(always)]
pub unsafe fn luaL_loadbufferx(
L: *mut lua_State,
@ -745,7 +427,6 @@ pub unsafe fn luaL_loadbufferx(
luaL_loadbuffer(L, buff, sz, name)
}
#[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;
@ -759,7 +440,6 @@ pub unsafe fn luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer {
res
}
#[cfg(any(feature = "lua51", feature = "luajit"))]
pub unsafe fn luaL_traceback(
L: *mut lua_State,
L1: *mut lua_State,
@ -799,46 +479,6 @@ 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);
@ -875,7 +515,6 @@ 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", 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"));
@ -883,57 +522,19 @@ pub unsafe fn luaL_setmetatable(L: *mut lua_State, tname: *const c_char) {
lua_setmetatable(L, -2);
}
#[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);
luaL_checkstack(L, 2, cstr!("not enough stack slots"));
if p.is_null() || lua_getmetatable(L, i) == 0 {
return ptr::null_mut();
} else {
luaL_getmetatable(L, tname);
let res = lua_rawequal(L, -1, -2);
lua_pop(L, 2);
if res == 0 {
p = ptr::null_mut();
}
}
return p;
}
#[cfg(any(feature = "lua51", feature = "luajit"))]
#[inline(always)]
pub unsafe fn luaL_setfuncs(L: *mut lua_State, mut l: *const luaL_Reg, nup: c_int) {
luaL_checkstack(L, nup + 1, cstr!("too many upvalues"));
while !(*l).name.is_null() {
// fill the table with given functions
l = l.offset(1);
lua_pushstring(L, (*l).name);
for _ in 0..nup {
// copy upvalues to the top
lua_pushvalue(L, -(nup + 1));
}
lua_pushcclosure(L, (*l).func, nup); // closure with those upvalues
lua_settable(L, -(nup + 3)); // table must be below the upvalues, the name and the closure
}
lua_pop(L, nup); // remove upvalues
}
#[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"));
lua_pushstring(L, fname);
lua_gettable(L, abs_i);
if lua_istable(L, -1) != 0 {
lua_pushstring_(L, fname);
if lua_gettable(L, abs_i) == LUA_TTABLE {
return 1;
}
lua_pop(L, 1);
lua_newtable(L);
lua_pushstring(L, fname);
lua_pushstring_(L, fname);
lua_pushvalue(L, -2);
lua_settable(L, abs_i);
return 0;
0
}
pub unsafe fn luaL_requiref(
@ -948,7 +549,7 @@ pub unsafe fn luaL_requiref(
lua_pop(L, 1);
lua_pushcfunction(L, openf);
lua_pushstring(L, modname);
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luau"))]
#[cfg(feature = "lua51")]
{
lua_call(L, 1, 1);
lua_pushvalue(L, -1);
@ -960,7 +561,7 @@ pub unsafe fn luaL_requiref(
lua_getfield(L, -1, modname);
}
}
if cfg!(any(feature = "lua52", feature = "lua51", feature = "luau")) && glb != 0 {
if cfg!(feature = "lua51") && glb != 0 {
lua_pushvalue(L, -1);
lua_setglobal(L, modname);
}

View file

@ -1,9 +1,11 @@
//! Low level bindings to Lua 5.1.
pub use self::lauxlib::*;
pub use self::lua::*;
pub use self::lualib::*;
pub use compat::*;
pub use lauxlib::*;
pub use lua::*;
pub use lualib::*;
pub mod compat;
pub mod lauxlib;
pub mod lua;
pub mod lualib;

258
src/ffi/lua52/compat.rs Normal file
View file

@ -0,0 +1,258 @@
//! MLua compatibility layer for Lua 5.2
//!
//! Based on github.com/keplerproject/lua-compat-5.3
use std::convert::TryInto;
use std::os::raw::{c_char, c_int, c_void};
use std::ptr;
use super::lauxlib::*;
use super::lua::*;
#[inline(always)]
unsafe fn compat53_reverse(L: *mut lua_State, mut a: c_int, mut b: c_int) {
while a < b {
lua_pushvalue(L, a);
lua_pushvalue(L, b);
lua_replace(L, a);
lua_replace(L, b);
a += 1;
b -= 1;
}
}
//
// lua ported functions
//
pub unsafe fn lua_rotate(L: *mut lua_State, mut idx: c_int, mut n: c_int) {
idx = lua_absindex(L, idx);
let n_elems = lua_gettop(L) - idx + 1;
if n < 0 {
n += n_elems;
}
if n > 0 && n < n_elems {
luaL_checkstack(L, 2, cstr!("not enough stack slots available"));
n = n_elems - n;
compat53_reverse(L, idx, idx + n - 1);
compat53_reverse(L, idx + n, idx + n_elems - 1);
compat53_reverse(L, idx, idx + n_elems - 1);
}
}
#[inline(always)]
pub unsafe fn lua_isinteger(L: *mut lua_State, idx: c_int) -> c_int {
if lua_type(L, idx) == LUA_TNUMBER {
let n = lua_tonumber(L, idx);
let i = lua_tointeger(L, idx);
if (n - i as lua_Number).abs() < lua_Number::EPSILON {
return 1;
}
}
0
}
#[inline(always)]
pub unsafe fn lua_tointeger(L: *mut lua_State, i: c_int) -> lua_Integer {
lua_tointegerx(L, i, ptr::null_mut())
}
// Implemented for Lua 5.2 as well
// See https://github.com/keplerproject/lua-compat-5.3/issues/40
#[inline(always)]
pub unsafe fn lua_tointegerx(L: *mut lua_State, i: c_int, isnum: *mut c_int) -> lua_Integer {
let mut ok = 0;
let n = lua_tonumberx(L, i, &mut ok);
let n_int = n as lua_Integer;
if ok != 0 && (n - n_int as lua_Number).abs() < lua_Number::EPSILON {
if !isnum.is_null() {
*isnum = 1;
}
return n_int;
}
if !isnum.is_null() {
*isnum = 0;
}
0
}
#[inline(always)]
pub unsafe fn lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char {
if l == 0 {
lua_pushlstring_(L, cstr!(""), 0)
} else {
lua_pushlstring_(L, s, l)
}
}
#[inline(always)]
pub unsafe fn lua_getglobal(L: *mut lua_State, var: *const c_char) -> c_int {
lua_getglobal_(L, var);
lua_type(L, -1)
}
#[inline(always)]
pub unsafe fn lua_gettable(L: *mut lua_State, idx: c_int) -> c_int {
lua_gettable_(L, idx);
lua_type(L, -1)
}
#[inline(always)]
pub unsafe fn lua_getfield(L: *mut lua_State, idx: c_int, k: *const c_char) -> c_int {
lua_getfield_(L, idx, k);
lua_type(L, -1)
}
#[inline(always)]
pub unsafe fn lua_geti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) -> c_int {
idx = lua_absindex(L, idx);
lua_pushinteger(L, n);
lua_gettable(L, idx)
}
#[inline(always)]
pub unsafe fn lua_rawget(L: *mut lua_State, idx: c_int) -> c_int {
lua_rawget_(L, idx);
lua_type(L, -1)
}
#[inline(always)]
pub unsafe fn lua_rawgeti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int {
let n = n.try_into().expect("cannot convert index to lua_Integer");
lua_rawgeti_(L, idx, n);
lua_type(L, -1)
}
#[inline(always)]
pub unsafe fn lua_rawgetp(L: *mut lua_State, idx: c_int, p: *const c_void) -> c_int {
lua_rawgetp_(L, idx, p);
lua_type(L, -1)
}
#[inline(always)]
pub unsafe fn lua_getuservalue(L: *mut lua_State, idx: c_int) -> c_int {
lua_getuservalue_(L, idx);
lua_type(L, -1)
}
#[inline(always)]
pub unsafe fn lua_seti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) {
luaL_checkstack(L, 1, cstr!("not enough stack slots available"));
idx = lua_absindex(L, idx);
lua_pushinteger(L, n);
lua_insert(L, -2);
lua_settable(L, idx);
}
#[inline(always)]
pub unsafe fn lua_rawseti(L: *mut lua_State, idx: c_int, n: lua_Integer) {
let n = n.try_into().expect("cannot convert index from lua_Integer");
lua_rawseti_(L, idx, n)
}
#[inline(always)]
pub unsafe fn lua_dump(
L: *mut lua_State,
writer: lua_Writer,
data: *mut c_void,
_strip: c_int,
) -> c_int {
lua_dump_(L, writer, data)
}
#[inline(always)]
pub unsafe fn lua_resume(
L: *mut lua_State,
from: *mut lua_State,
narg: c_int,
nres: *mut c_int,
) -> c_int {
let ret = lua_resume_(L, from, narg);
if (ret == LUA_OK || ret == LUA_YIELD) && !(nres.is_null()) {
*nres = lua_gettop(L);
}
ret
}
//
// lauxlib ported functions
//
#[inline(always)]
pub unsafe fn luaL_getmetafield(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int {
if luaL_getmetafield_(L, obj, e) != 0 {
lua_type(L, -1)
} else {
LUA_TNIL
}
}
#[inline(always)]
pub unsafe fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_int {
if luaL_newmetatable_(L, tname) != 0 {
lua_pushstring(L, tname);
lua_setfield(L, -2, cstr!("__name"));
1
} else {
0
}
}
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);
match t {
LUA_TNIL => {
lua_pushliteral(L, "nil");
}
LUA_TSTRING | LUA_TNUMBER => {
lua_pushvalue(L, idx);
}
LUA_TBOOLEAN => {
if lua_toboolean(L, idx) == 0 {
lua_pushliteral(L, "false");
} else {
lua_pushliteral(L, "true");
}
}
_ => {
let tt = luaL_getmetafield(L, idx, cstr!("__name"));
let name = if tt == LUA_TSTRING {
lua_tostring(L, -1)
} else {
lua_typename(L, t)
};
lua_pushfstring(L, cstr!("%s: %p"), name, lua_topointer(L, idx));
if tt != LUA_TNIL {
lua_replace(L, -2);
}
}
};
} else if lua_isstring(L, -1) == 0 {
luaL_error(L, cstr!("'__tostring' must return a string"));
}
lua_tolstring(L, -1, len)
}
pub unsafe fn luaL_requiref(
L: *mut lua_State,
modname: *const c_char,
openf: lua_CFunction,
glb: c_int,
) {
luaL_checkstack(L, 3, cstr!("not enough stack slots available"));
luaL_getsubtable(L, LUA_REGISTRYINDEX, cstr!("_LOADED"));
if lua_getfield(L, -1, modname) == LUA_TNIL {
lua_pop(L, 1);
lua_pushcfunction(L, openf);
lua_pushstring(L, modname);
lua_call(L, 1, 1);
lua_pushvalue(L, -1);
lua_setfield(L, -3, modname);
}
if glb != 0 {
lua_pushvalue(L, -1);
lua_setglobal(L, modname);
}
lua_replace(L, -2);
}

View file

@ -1,9 +1,11 @@
//! Low level bindings to Lua 5.2.
pub use self::lauxlib::*;
pub use self::lua::*;
pub use self::lualib::*;
pub use compat::*;
pub use lauxlib::*;
pub use lua::*;
pub use lualib::*;
pub mod compat;
pub mod lauxlib;
pub mod lua;
pub mod lualib;

19
src/ffi/lua53/compat.rs Normal file
View file

@ -0,0 +1,19 @@
//! MLua compatibility layer for Lua 5.2
use std::os::raw::c_int;
use super::lua::*;
#[inline(always)]
pub unsafe fn lua_resume(
L: *mut lua_State,
from: *mut lua_State,
narg: c_int,
nres: *mut c_int,
) -> c_int {
let ret = lua_resume_(L, from, narg);
if (ret == LUA_OK || ret == LUA_YIELD) && !(nres.is_null()) {
*nres = lua_gettop(L);
}
ret
}

View file

@ -1,9 +1,11 @@
//! Low level bindings to Lua 5.3.
pub use self::lauxlib::*;
pub use self::lua::*;
pub use self::lualib::*;
pub use compat::*;
pub use lauxlib::*;
pub use lua::*;
pub use lualib::*;
pub mod compat;
pub mod lauxlib;
pub mod lua;
pub mod lualib;

View file

@ -1,8 +1,8 @@
//! Low level bindings to Lua 5.4.
pub use self::lauxlib::*;
pub use self::lua::*;
pub use self::lualib::*;
pub use lauxlib::*;
pub use lua::*;
pub use lualib::*;
pub mod lauxlib;
pub mod lua;

View file

@ -1,16 +0,0 @@
//! Contains definitions from `lualib.h`.
#[cfg(feature = "lua54")]
pub use super::lua54::lualib::*;
#[cfg(feature = "lua53")]
pub use super::lua53::lualib::*;
#[cfg(feature = "lua52")]
pub use super::lua52::lualib::*;
#[cfg(any(feature = "lua51", feature = "luajit"))]
pub use super::lua51::lualib::*;
#[cfg(feature = "luau")]
pub use super::luau::lualib::*;

555
src/ffi/luau/compat.rs Normal file
View file

@ -0,0 +1,555 @@
//! MLua compatibility layer for Roblox Luau.
//!
//! Based on github.com/keplerproject/lua-compat-5.3
use std::convert::TryInto;
use std::ffi::CStr;
use std::mem;
use std::os::raw::{c_char, c_int, c_void};
use std::ptr;
use super::lauxlib::*;
use super::lua::*;
use super::luacode::*;
unsafe fn compat53_reverse(L: *mut lua_State, mut a: c_int, mut b: c_int) {
while a < b {
lua_pushvalue(L, a);
lua_pushvalue(L, b);
lua_replace(L, a);
lua_replace(L, b);
a += 1;
b -= 1;
}
}
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
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_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
}
lua_pushnil(L); // start 'next' loop
while lua_next(L, -2) != 0 {
// for each pair in table
if lua_type(L, -2) == LUA_TSTRING {
// ignore non-string keys
if lua_rawequal(L, objidx, -1) != 0 {
// found object?
lua_pop(L, 1); // remove value (but keep name)
return 1;
} else if compat53_findfield(L, objidx, level - 1) != 0 {
// try recursively
lua_remove(L, -2); // remove table (but keep name)
lua_pushliteral(L, ".");
lua_insert(L, -2); // place '.' between the two names
lua_concat(L, 3);
return 1;
}
}
lua_pop(L, 1); // remove value
}
return 0; // not found
}
unsafe fn compat53_pushglobalfuncname(
L: *mut lua_State,
level: c_int,
ar: *mut lua_Debug,
) -> c_int {
let top = lua_gettop(L);
// 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
lua_pop(L, 2); // remove pushed values
return 1;
} else {
lua_settop(L, top); // remove function and global table
return 0;
}
}
#[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,
);
}
}
//
// lua ported functions
//
pub unsafe fn lua_rotate(L: *mut lua_State, mut idx: c_int, mut n: c_int) {
idx = lua_absindex(L, idx);
let n_elems = lua_gettop(L) - idx + 1;
if n < 0 {
n += n_elems;
}
if n > 0 && n < n_elems {
luaL_checkstack(L, 2, cstr!("not enough stack slots available"));
n = n_elems - n;
compat53_reverse(L, idx, idx + n - 1);
compat53_reverse(L, idx + n, idx + n_elems - 1);
compat53_reverse(L, idx, idx + n_elems - 1);
}
}
#[inline(always)]
pub unsafe fn lua_copy(L: *mut lua_State, fromidx: c_int, toidx: c_int) {
let abs_to = lua_absindex(L, toidx);
luaL_checkstack(L, 1, cstr!("not enough stack slots"));
lua_pushvalue(L, fromidx);
lua_replace(L, abs_to);
}
#[inline(always)]
pub unsafe fn lua_isinteger(L: *mut lua_State, idx: c_int) -> c_int {
if lua_type(L, idx) == LUA_TNUMBER {
let n = lua_tonumber(L, idx);
let i = lua_tointeger(L, idx);
if (n - i as lua_Number).abs() < lua_Number::EPSILON {
return 1;
}
}
0
}
#[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_tointegerx(L: *mut lua_State, i: c_int, isnum: *mut c_int) -> lua_Integer {
let mut ok = 0;
let n = lua_tonumberx(L, i, &mut ok);
let n_int = n as lua_Integer;
if ok != 0 && (n - n_int as lua_Number).abs() < lua_Number::EPSILON {
if !isnum.is_null() {
*isnum = 1;
}
return n_int;
}
if !isnum.is_null() {
*isnum = 0;
}
0
}
#[inline(always)]
pub unsafe fn lua_rawlen(L: *mut lua_State, idx: c_int) -> usize {
lua_objlen(L, idx)
}
#[inline(always)]
pub unsafe fn lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char {
if l == 0 {
lua_pushlstring_(L, cstr!(""), 0);
} else {
lua_pushlstring_(L, s, l);
}
lua_tostring(L, -1)
}
#[inline(always)]
pub unsafe fn lua_pushstring(L: *mut lua_State, s: *const c_char) -> *const c_char {
lua_pushstring_(L, s);
lua_tostring(L, -1)
}
#[inline(always)]
pub unsafe fn lua_geti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) -> c_int {
idx = lua_absindex(L, idx);
lua_pushinteger(L, n);
lua_gettable(L, idx)
}
#[inline(always)]
pub unsafe fn lua_rawgeti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int {
let n = n.try_into().expect("cannot convert index to lua_Integer");
lua_rawgeti_(L, idx, n)
}
#[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);
lua_pushlightuserdata(L, p as *mut c_void);
lua_rawget(L, abs_i)
}
#[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");
if lua_rawget(L, LUA_REGISTRYINDEX) != LUA_TTABLE {
return LUA_TNIL;
}
lua_pushvalue(L, idx);
lua_rawget(L, -2);
lua_remove(L, -2);
lua_type(L, -1)
}
#[inline(always)]
pub unsafe fn lua_seti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) {
luaL_checkstack(L, 1, cstr!("not enough stack slots available"));
idx = lua_absindex(L, idx);
lua_pushinteger(L, n);
lua_insert(L, -2);
lua_settable(L, idx);
}
#[inline(always)]
pub unsafe fn lua_rawseti(L: *mut lua_State, idx: c_int, n: lua_Integer) {
let n = n.try_into().expect("cannot convert index from lua_Integer");
lua_rawseti_(L, idx, n)
}
#[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);
luaL_checkstack(L, 1, cstr!("not enough stack slots"));
lua_pushlightuserdata(L, p as *mut c_void);
lua_insert(L, -2);
lua_rawset(L, abs_i);
}
#[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);
if lua_rawget(L, LUA_REGISTRYINDEX) != LUA_TTABLE {
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);
}
#[inline(always)]
pub unsafe fn lua_len(L: *mut lua_State, idx: c_int) {
match lua_type(L, idx) {
LUA_TSTRING => {
lua_pushnumber(L, lua_objlen(L, idx) as lua_Number);
}
LUA_TTABLE => {
if luaL_callmeta(L, idx, cstr!("__len")) == 0 {
lua_pushnumber(L, lua_objlen(L, idx) as lua_Number);
}
}
LUA_TUSERDATA if luaL_callmeta(L, idx, cstr!("__len")) != 0 => {}
_ => {
luaL_error(
L,
cstr!("attempt to get length of a %s value"),
lua_typename(L, lua_type(L, idx)),
);
}
}
}
#[inline(always)]
pub unsafe fn lua_pushglobaltable(L: *mut lua_State) {
lua_pushvalue(L, LUA_GLOBALSINDEX);
}
#[inline(always)]
pub unsafe fn lua_resume(
L: *mut lua_State,
from: *mut lua_State,
narg: c_int,
nres: *mut c_int,
) -> c_int {
let ret = lua_resume_(L, from, narg);
if (ret == LUA_OK || ret == LUA_YIELD) && !(nres.is_null()) {
*nres = lua_gettop(L);
}
ret
}
//
// lauxlib ported functions
//
#[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 {
if !msg.is_null() {
luaL_error(L, cstr!("stack overflow (%s)"), msg);
} else {
lua_pushliteral(L, "stack overflow");
lua_error(L);
}
}
}
#[inline(always)]
pub unsafe fn luaL_getmetafield(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int {
if luaL_getmetafield_(L, obj, e) != 0 {
lua_type(L, -1)
} else {
LUA_TNIL
}
}
#[inline(always)]
pub unsafe fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_int {
if luaL_newmetatable_(L, tname) != 0 {
lua_pushstring(L, tname);
lua_setfield(L, -2, cstr!("__name"));
1
} else {
0
}
}
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 {
extern "C" {
fn free(p: *mut c_void);
}
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_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_pushfstring(
L,
cstr!("attempt to load a text chunk (mode is '%s')"),
mode,
);
return LUA_ERRSYNTAX;
}
}
if chunk_is_text {
let data = luau_compile(data, size, ptr::null_mut(), &mut size);
let ok = luau_load(L, name, data, size, 0) == 0;
free(data as *mut c_void);
if !ok {
return LUA_ERRSYNTAX;
}
} else {
if 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())
}
#[inline(always)]
pub unsafe fn luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer {
let mut isnum = 0;
luaL_checkstack(L, 1, cstr!("not enough stack slots"));
lua_len(L, idx);
let res = lua_tointegerx(L, -1, &mut isnum);
lua_pop(L, 1);
if isnum == 0 {
luaL_error(L, cstr!("object length is not an integer"));
}
res
}
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);
match t {
LUA_TNIL => {
lua_pushliteral(L, "nil");
}
LUA_TSTRING | LUA_TNUMBER => {
lua_pushvalue(L, idx);
}
LUA_TBOOLEAN => {
if lua_toboolean(L, idx) == 0 {
lua_pushliteral(L, "false");
} else {
lua_pushliteral(L, "true");
}
}
_ => {
let tt = luaL_getmetafield(L, idx, cstr!("__name"));
let name = if tt == LUA_TSTRING {
lua_tostring(L, -1)
} else {
lua_typename(L, t)
};
lua_pushfstring(L, cstr!("%s: %p"), name, lua_topointer(L, idx));
if tt != LUA_TNIL {
lua_replace(L, -2);
}
}
};
} else if lua_isstring(L, -1) == 0 {
luaL_error(L, cstr!("'__tostring' must return a string"));
}
lua_tolstring(L, -1, len)
}
#[inline(always)]
pub unsafe fn luaL_setmetatable(L: *mut lua_State, tname: *const c_char) {
luaL_checkstack(L, 1, cstr!("not enough stack slots"));
luaL_getmetatable(L, tname);
lua_setmetatable(L, -2);
}
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"));
lua_pushstring_(L, fname);
if lua_gettable(L, abs_i) == LUA_TTABLE {
return 1;
}
lua_pop(L, 1);
lua_newtable(L);
lua_pushstring_(L, fname);
lua_pushvalue(L, -2);
lua_settable(L, abs_i);
0
}
pub unsafe fn luaL_requiref(
L: *mut lua_State,
modname: *const c_char,
openf: lua_CFunction,
glb: c_int,
) {
luaL_checkstack(L, 3, cstr!("not enough stack slots available"));
luaL_getsubtable(L, LUA_REGISTRYINDEX, cstr!("_LOADED"));
if lua_getfield(L, -1, modname) == LUA_TNIL {
lua_pop(L, 1);
lua_pushcfunction(L, openf);
lua_pushstring(L, modname);
lua_call(L, 1, 1);
lua_pushvalue(L, -1);
lua_setfield(L, -3, modname);
}
if glb != 0 {
lua_pushvalue(L, -1);
lua_setglobal(L, modname);
}
lua_replace(L, -2);
}

View file

@ -1,15 +1,11 @@
//! 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,
self, lua_CFunction, lua_Integer, lua_Number, lua_State, lua_Unsigned, LUA_REGISTRYINDEX,
};
use super::luacode;
#[repr(C)]
pub struct luaL_Reg {
@ -112,8 +108,8 @@ pub unsafe fn luaL_typename(L: *mut lua_State, i: c_int) -> *const c_char {
}
#[inline(always)]
pub unsafe fn luaL_getmetatable(L: *mut lua_State, n: *const c_char) {
lua::lua_getfield_(L, LUA_REGISTRYINDEX, n);
pub unsafe fn luaL_getmetatable(L: *mut lua_State, n: *const c_char) -> c_int {
lua::lua_getfield(L, LUA_REGISTRYINDEX, n)
}
#[inline(always)]
@ -130,59 +126,6 @@ pub unsafe fn luaL_unref(L: *mut lua_State, t: c_int, r#ref: c_int) {
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

@ -74,7 +74,6 @@ 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,
ud: *mut c_void,
ptr: *mut c_void,
osize: usize,
@ -169,15 +168,12 @@ extern "C" {
//
// Get functions (Lua -> stack)
//
#[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);
#[link_name = "lua_rawget"]
pub fn lua_rawget_(L: *mut lua_State, idx: c_int);
pub fn lua_gettable(L: *mut lua_State, idx: c_int) -> c_int;
pub fn lua_getfield(L: *mut lua_State, idx: c_int, k: *const c_char) -> c_int;
pub fn lua_rawgetfield(L: *mut lua_State, idx: c_int, k: *const c_char) -> c_int;
pub fn lua_rawget(L: *mut lua_State, idx: c_int) -> c_int;
#[link_name = "lua_rawgeti"]
pub fn lua_rawgeti_(L: *mut lua_State, idx: c_int, n: c_int);
pub fn lua_rawgeti_(L: *mut lua_State, idx: c_int, n: c_int) -> 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);
@ -382,8 +378,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) -> c_int {
lua_getfield(L, LUA_GLOBALSINDEX, var)
}
#[inline(always)]

View file

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

View file

@ -2,9 +2,38 @@
#![allow(non_camel_case_types, non_snake_case, dead_code)]
pub use lauxlib::*;
pub use lua::*;
pub use lualib::*;
use std::os::raw::c_int;
#[cfg(feature = "lua54")]
pub use lua54::*;
#[cfg(feature = "lua53")]
pub use lua53::*;
#[cfg(feature = "lua52")]
pub use lua52::*;
#[cfg(any(feature = "lua51", feature = "luajit"))]
pub use lua51::*;
#[cfg(feature = "luau")]
pub use luau::*;
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
pub const LUA_MAX_UPVALUES: c_int = 255;
#[cfg(any(feature = "lua51", all(feature = "luajit", not(feature = "vendored"))))]
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;
// 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;
// The minimum alignment guaranteed by the architecture. This value is used to
// add fast paths for low alignment values.
@ -56,18 +85,6 @@ pub(crate) fn keep_lua_symbols() {
}
}
mod lauxlib;
mod lua;
mod lualib;
#[cfg(any(
feature = "lua52",
feature = "lua51",
feature = "luajit",
feature = "luau"
))]
mod compat53;
#[cfg(feature = "lua54")]
pub mod lua54;

View file

@ -1481,16 +1481,22 @@ impl Lua {
/// Resets thread (coroutine) and returns to the cache for later use.
#[cfg(feature = "async")]
#[cfg(any(feature = "lua54", all(feature = "luajit", feature = "vendored")))]
pub(crate) fn recycle_thread(&self, thread: &mut Thread) {
unsafe {
let extra = &mut *self.extra.get();
let thread_state = ffi::lua_tothread(extra.ref_thread, thread.0.index);
if extra.recycled_thread_cache.len() < extra.recycled_thread_cache.capacity()
&& ffi::lua_resetthreadx(self.state, thread_state) == ffi::LUA_OK
{
extra.recycled_thread_cache.push(thread.0.index);
thread.0.index = 0;
pub(crate) unsafe fn recycle_thread(&self, thread: &mut Thread) {
let extra = &mut *self.extra.get();
let thread_state = ffi::lua_tothread(extra.ref_thread, thread.0.index);
if extra.recycled_thread_cache.len() < extra.recycled_thread_cache.capacity() {
#[cfg(feature = "lua54")]
let status = ffi::lua_resetthread(thread_state);
#[cfg(feature = "lua54")]
if status != ffi::LUA_OK {
return;
}
#[cfg(all(feature = "luajit", feature = "vendored"))]
ffi::lua_resetthread(self.state, thread_state);
#[cfg(feature = "luau")]
ffi::lua_resetthread(thread_state);
extra.recycled_thread_cache.push(thread.0.index);
thread.0.index = 0;
}
}

View file

@ -192,10 +192,16 @@ impl<'lua> Thread<'lua> {
lua.push_ref(&self.0);
let thread_state = ffi::lua_tothread(lua.state, -1);
let ret = ffi::lua_resetthreadx(lua.state, thread_state);
if ret != ffi::LUA_OK {
return Err(pop_error(thread_state, ret));
#[cfg(feature = "lua54")]
let status = ffi::lua_resetthread(thread_state);
#[cfg(feature = "lua54")]
if status != ffi::LUA_OK {
return Err(pop_error(thread_state, status));
}
#[cfg(all(feature = "luajit", feature = "vendored"))]
ffi::lua_resetthread(lua.state, thread_state);
#[cfg(feature = "luau")]
ffi::lua_resetthread(thread_state);
lua.push_ref(&func.0);
ffi::lua_xmove(lua.state, thread_state, 1);
@ -285,7 +291,9 @@ impl<'lua, R> AsyncThread<'lua, R> {
impl<'lua, R> Drop for AsyncThread<'lua, R> {
fn drop(&mut self) {
if self.recycle {
self.thread.0.lua.recycle_thread(&mut self.thread);
unsafe {
self.thread.0.lua.recycle_thread(&mut self.thread);
}
}
}
}