Lua 5.1 support

This commit is contained in:
Alex Orlenko 2019-10-14 22:21:30 +01:00
parent 676ffc0dfd
commit c4fd7a9faf
25 changed files with 1276 additions and 291 deletions

View file

@ -3,7 +3,7 @@ name = "mlua"
version = "0.1.0"
authors = ["Aleksandr Orlenko <zxteam@pm.me>", "kyren <catherine@chucklefish.org>"]
edition = "2018"
description = "High level bindings to Lua 5.3 for writing modules"
description = "High level bindings to Lua 5.3/5.1 for writing modules"
repository = "https://github.com/khvzak/mlua"
documentation = "https://docs.rs/mlua"
readme = "README.md"
@ -18,6 +18,10 @@ members = [
"mlua_derive",
]
[features]
default = ["lua53"]
lua53 = []
[dependencies]
num-traits = { version = "0.2.6" }
bstr = { version = "0.2", features = ["std"], default_features = false }

View file

@ -45,8 +45,13 @@ fn use_custom_lua<S: AsRef<str>>(include_dir: &S, lib_dir: &S, lua_lib: &S) -> R
}
}
let mut static_link = "";
if env::var("LUA_LINK").unwrap_or(String::new()) == "static" {
static_link = "static=";
}
println!("cargo:rustc-link-search=native={}", lib_dir.as_ref());
println!("cargo:rustc-link-lib=static={}", lua_lib.as_ref());
println!("cargo:rustc-link-lib={}{}", static_link, lua_lib.as_ref());
Ok(version_found)
}
@ -91,6 +96,7 @@ fn main() {
println!("cargo:rerun-if-env-changed=LUA_INC");
println!("cargo:rerun-if-env-changed=LUA_LIB");
println!("cargo:rerun-if-env-changed=LUA_LIB_NAME");
println!("cargo:rerun-if-env-changed=LUA_LINK");
println!("cargo:rerun-if-changed=src/ffi/glue/glue.c");
if include_dir != "" && lib_dir != "" && lua_lib != "" {
@ -101,10 +107,35 @@ fn main() {
// Find lua via pkg-config
let lua = pkg_config::Config::new()
.range_version((Bound::Included("5.3"), Bound::Excluded("5.4")))
.probe("lua")
.unwrap();
#[cfg(feature = "lua53")]
{
let mut lua = pkg_config::Config::new()
.range_version((Bound::Included("5.3"), Bound::Excluded("5.4")))
.probe("lua");
build_glue(&lua.include_paths);
if lua.is_err() {
lua = pkg_config::Config::new().probe("lua5.3");
}
match lua {
Ok(lua) => build_glue(&lua.include_paths),
Err(err) => panic!(err),
};
}
#[cfg(not(feature = "lua53"))]
{
let mut lua = pkg_config::Config::new()
.range_version((Bound::Included("5.1"), Bound::Excluded("5.2")))
.probe("lua");
if lua.is_err() {
lua = pkg_config::Config::new().probe("lua5.1");
}
match lua {
Ok(lua) => build_glue(&lua.include_paths),
Err(err) => panic!(err),
};
}
}

View file

@ -31,6 +31,7 @@ pub enum Error {
/// Lua garbage collector error, aka `LUA_ERRGCMM`.
///
/// The Lua VM returns this error when there is an error running a `__gc` metamethod.
#[cfg(feature = "lua53")]
GarbageCollectorError(StdString),
/// A mutable callback has triggered Lua code that has called the same mutable callback again.
///
@ -137,6 +138,7 @@ impl fmt::Display for Error {
Error::MemoryError(ref msg) => {
write!(fmt, "memory error: {}", msg)
}
#[cfg(feature = "lua53")]
Error::GarbageCollectorError(ref msg) => {
write!(fmt, "garbage collector error: {}", msg)
}

668
src/ffi/compat53.rs Normal file
View file

@ -0,0 +1,668 @@
// The MIT License (MIT)
//
// Copyright (c) 2019 A. Orlenko
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// Based on github.com/keplerproject/lua-compat-5.3
use std::mem;
use std::os::raw::{c_char, c_int, c_void};
use std::ptr;
use super::lauxlib::{
luaL_Reg, luaL_callmeta, luaL_checkstack, luaL_checktype, luaL_error, luaL_getmetafield_51,
luaL_getmetatable, luaL_loadbuffer, luaL_newmetatable_51,
};
use super::lua::{
self, lua_CFunction, lua_Debug, lua_Integer, lua_Number, lua_State, lua_call, lua_concat,
lua_createtable, lua_equal, lua_error, lua_getfenv, lua_getfield_51, lua_getinfo,
lua_getmetatable, lua_getstack, lua_gettable_51, lua_gettop, lua_insert, lua_isnumber,
lua_isstring, lua_istable, lua_lessthan, lua_newtable, lua_newuserdata, lua_next, lua_objlen,
lua_pop, lua_pushboolean, lua_pushcclosure, lua_pushcfunction, lua_pushfstring,
lua_pushinteger, lua_pushlightuserdata, lua_pushliteral, lua_pushlstring_51, lua_pushnil,
lua_pushnumber, lua_pushstring_51, lua_pushthread, lua_pushvalue, lua_rawequal, lua_rawget_51,
lua_rawgeti_51, lua_rawset, lua_remove, lua_replace, lua_resume_51, lua_setfenv, lua_setfield,
lua_setglobal, lua_setmetatable, lua_settable, lua_settop, lua_toboolean, lua_tointeger,
lua_tolstring, lua_tonumber, lua_topointer, lua_tostring, lua_touserdata, lua_type,
lua_typename,
};
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_getstack(L, le, &mut ar) != 0 {
li = le;
le *= 2;
}
// do a binary search
while li < le {
let m = (li + le) / 2;
if lua_getstack(L, m, &mut ar) != 0 {
li = m + 1
} else {
le = m;
}
}
le - 1
}
unsafe fn compat53_checkmode(
L: *mut lua_State,
mode: *const c_char,
modename: *const c_char,
err: c_int,
) -> c_int {
unsafe fn strchr(s: *const c_char, c: c_char) -> *const c_char {
let mut st = s;
while *st != 0 && *st != c {
st = st.offset(1);
}
if *st == c {
st
} else {
ptr::null()
}
}
if mode != ptr::null() && strchr(mode, *modename) == ptr::null() {
lua_pushfstring(
L,
cstr!("attempt to load a %s chunk (mode is '%s')"),
modename,
mode,
);
return err;
}
lua::LUA_OK
}
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::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, ar: *mut lua_Debug) -> c_int {
let top = lua_gettop(L);
lua_getinfo(L, cstr!("f"), ar); // push function
lua_pushvalue(L, lua::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;
}
}
unsafe fn compat53_pushfuncname(L: *mut lua_State, 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, 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,
);
}
}
unsafe fn compat53_call_lua(L: *mut lua_State, code: &str, nargs: c_int, nret: c_int) {
lua_rawgetp(L, lua::LUA_REGISTRYINDEX, code.as_ptr() as *const c_void);
if lua_type(L, -1) != lua::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::LUA_REGISTRYINDEX, code.as_ptr() as *const c_void);
}
lua_insert(L, -nargs - 1);
lua_call(L, nargs, nret);
}
//
// lua ported functions
//
#[inline(always)]
pub fn lua_upvalueindex(i: c_int) -> c_int {
lua::LUA_GLOBALSINDEX - i
}
pub unsafe fn lua_absindex(L: *mut lua_State, mut idx: c_int) -> c_int {
if idx < 0 && idx > lua::LUA_REGISTRYINDEX {
idx += lua_gettop(L) + 1;
}
idx
}
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);
}
}
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);
}
pub unsafe fn lua_isinteger(L: *mut lua_State, idx: c_int) -> c_int {
if lua_type(L, idx) == lua::LUA_TNUMBER {
let n = lua_tonumber(L, idx);
let i = lua_tointeger(L, idx);
if i as f64 == n {
return 1;
}
}
return 0;
}
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 != ptr::null_mut() {
*isnum = if n != 0.0 || lua_isnumber(L, i) != 0 {
1
} else {
0
};
}
return n;
}
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);
if ok != 0 {
if n == n as lua_Integer as lua_Number {
if isnum != ptr::null_mut() {
*isnum = 1;
}
return n as lua_Integer;
}
}
if isnum != ptr::null_mut() {
*isnum = 0;
}
return 0;
}
pub unsafe fn lua_rawlen(L: *mut lua_State, idx: c_int) -> usize {
lua_objlen(L, idx)
}
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::LUA_OPEQ => lua_equal(L, idx1, idx2),
lua::LUA_OPLT => lua_lessthan(L, idx1, idx2),
lua::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")),
}
}
pub unsafe fn lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char {
if l == 0 {
lua_pushlstring_51(L, cstr!(""), 0);
} else {
lua_pushlstring_51(L, s, l);
}
lua_tostring(L, -1)
}
pub unsafe fn lua_pushstring(L: *mut lua_State, s: *const c_char) -> *const c_char {
lua_pushstring_51(L, s);
lua_tostring(L, -1)
}
pub unsafe fn lua_gettable(L: *mut lua_State, idx: c_int) -> c_int {
lua_gettable_51(L, idx);
lua_type(L, -1)
}
pub unsafe fn lua_getfield(L: *mut lua_State, idx: c_int, k: *const c_char) -> c_int {
lua_getfield_51(L, idx, k);
lua_type(L, -1)
}
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)
}
// A new version which returns c_int
pub unsafe fn lua_rawget(L: *mut lua_State, idx: c_int) -> c_int {
lua_rawget_51(L, idx);
lua_type(L, -1)
}
// A new version which returns c_int
pub unsafe fn lua_rawgeti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int {
lua_rawgeti_51(L, idx, n);
lua_type(L, -1)
}
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)
}
pub unsafe fn lua_getuservalue(L: *mut lua_State, idx: c_int) -> c_int {
lua_getfenv(L, idx);
lua_type(L, -1)
}
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);
}
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);
}
pub unsafe fn lua_setuservalue(L: *mut lua_State, idx: c_int) {
luaL_checktype(L, -1, lua::LUA_TTABLE);
lua_setfenv(L, idx);
}
pub unsafe fn lua_resume(L: *mut lua_State, _from: *mut lua_State, narg: c_int) -> c_int {
lua_resume_51(L, narg)
}
pub unsafe fn lua_len(L: *mut lua_State, idx: c_int) {
match lua_type(L, idx) {
lua::LUA_TSTRING => {
lua_pushnumber(L, lua_objlen(L, idx) as lua_Number);
}
lua::LUA_TTABLE => {
if luaL_callmeta(L, idx, cstr!("__len")) == 0 {
lua_pushnumber(L, lua_objlen(L, idx) as lua_Number);
}
}
lua::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)),
);
}
}
}
// TODO: lua_stringtonumber
pub unsafe fn lua_getextraspace(L: *mut lua_State) -> *mut c_void {
use super::glue::LUA_EXTRASPACE;
luaL_checkstack(L, 4, cstr!("not enough stack slots available"));
lua_pushliteral(L, "__compat53_extraspace");
lua_pushvalue(L, -1);
lua_rawget(L, lua::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::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 == ptr::null_mut() {
lua_pop(L, 1);
_ptr = lua_newuserdata(L, LUA_EXTRASPACE as usize);
if is_main != 0 {
// mem::size_of::<c_void>() == 1
ptr::write_bytes(_ptr, 0, LUA_EXTRASPACE as usize);
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 != ptr::null_mut() {
ptr::copy_nonoverlapping(mptr, _ptr, LUA_EXTRASPACE as usize)
} else {
ptr::write_bytes(_ptr, 0, LUA_EXTRASPACE as usize);
}
lua_pop(L, 1);
lua_pushthread(L);
lua_pushvalue(L, -2);
lua_rawset(L, -4);
}
}
lua_pop(L, 2);
return _ptr;
}
#[inline(always)]
pub unsafe fn lua_pushglobaltable(L: *mut lua_State) {
lua_pushvalue(L, lua::LUA_GLOBALSINDEX);
}
//
// lauxlib ported functions
//
pub unsafe fn luaL_checkversion(_L: *mut lua_State) {
// Void
}
pub unsafe fn luaL_getmetafield(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int {
if luaL_getmetafield_51(L, obj, e) != 0 {
lua_type(L, -1)
} else {
lua::LUA_TNIL
}
}
pub unsafe fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_int {
if luaL_newmetatable_51(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,
buff: *const c_char,
sz: usize,
name: *const c_char,
mode: *const c_char,
) -> c_int {
let status = if sz > 0 && *buff as u8 == lua::LUA_SIGNATURE[0] {
compat53_checkmode(L, mode, cstr!("binary"), lua::LUA_ERRSYNTAX)
} else {
compat53_checkmode(L, mode, cstr!("text"), lua::LUA_ERRSYNTAX)
};
if status != lua::LUA_OK {
return status;
}
luaL_loadbuffer(L, buff, sz, name)
}
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::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 = std::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 != ptr::null() {
lua_pushfstring(L, cstr!("%s\n"), msg);
}
lua_pushliteral(L, "stack traceback:");
while lua_getstack(L1, level, &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, cstr!("Slnt"), &mut ar);
lua_pushfstring(L, cstr!("\n\t%s:"), cstr!("ok") /*ar.short_src*/);
if ar.currentline > 0 {
lua_pushfstring(L, cstr!("%d:"), ar.currentline);
}
lua_pushliteral(L, " in ");
compat53_pushfuncname(L, &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::LUA_TNIL => {
lua_pushliteral(L, "nil");
}
lua::LUA_TSTRING | lua::LUA_TNUMBER => {
lua_pushvalue(L, idx);
}
lua::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::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::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_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_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 == ptr::null_mut() || 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;
}
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 != ptr::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
}
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 {
return 1;
}
lua_pop(L, 1);
lua_newtable(L);
lua_pushstring(L, fname);
lua_pushvalue(L, -2);
lua_settable(L, abs_i);
return 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::LUA_REGISTRYINDEX, cstr!("_LOADED"));
if lua_getfield(L, -1, modname) == lua::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,5 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2019 A. Orlenko
// Copyright (c) 2014 J.C. Moyer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
@ -29,6 +30,10 @@
#include <lua.h>
#include <lualib.h>
#ifndef LUA_EXTRASPACE
#define LUA_EXTRASPACE (sizeof(void*))
#endif
// Macros taken from https://gcc.gnu.org/onlinedocs/cpp/Stringification.html
#define xstr(s) str(s)
#define str(s) #s
@ -43,23 +48,30 @@ typedef struct rs_item {
};
} rs_item;
#define TY_INT 0
#define TY_LUAINT 1
#define TY_STR 2
#define TY_TYPE 3
#define TY_COMMENT 4
#define TY_RAW 5
#define TY_INT 0
#define RS_INT(name, val) \
{ TY_INT, name, .int_val = val }
#if LUA_VERSION_NUM == 503
#define TY_LUAINT 1
#define RS_LUAINT(name, val) \
{ TY_LUAINT, name, .lua_int_val = val }
#endif
#define TY_STR 2
#define RS_STR(name, val) \
{ TY_STR, name, .str_val = val }
#define TY_TYPE 3
#define RS_TYPE(name, val) \
{ TY_TYPE, name, .str_val = val }
#define TY_COMMENT 4
#define RS_COMMENT(val) \
{ TY_COMMENT, NULL, .str_val = val }
#define TY_RAW 5
#define RS_RAW(val) \
{ TY_RAW, NULL, .str_val = val }
@ -102,7 +114,7 @@ size_t escape(const char *in, char *out, size_t szout) {
size_t written = 0;
char cur;
while (cur = *in++) {
while ((cur = *in++)) {
switch (cur) {
case '\\':
if (!try_write(&out, cur, 2, &written, szout))
@ -127,10 +139,12 @@ int write_int_item(FILE *f, const char *name, int value) {
return fprintf(f, "pub const %s: c_int = %d;\n", name, value);
}
#if LUA_VERSION_NUM == 503
int write_lua_int_item(FILE *f, const char *name, LUA_INTEGER value) {
return fprintf(f, "pub const %s: LUA_INTEGER = " LUA_INTEGER_FMT ";\n", name,
value);
}
#endif
int write_str_item(FILE *f, const char *name, const char *value) {
size_t len = strlen(value);
@ -157,8 +171,10 @@ int write_item(FILE *f, const rs_item *c) {
switch (c->type) {
case TY_INT:
return write_int_item(f, c->name, c->int_val);
#if LUA_VERSION_NUM == 503
case TY_LUAINT:
return write_lua_int_item(f, c->name, c->lua_int_val);
#endif
case TY_STR:
return write_str_item(f, c->name, c->str_val);
case TY_TYPE:
@ -205,43 +221,37 @@ int main(int argc, const char **argv) {
// == luaconf.h ==========================================================
RS_COMMENT("luaconf.h"),
RS_STR("LUA_VDIR", LUA_VDIR),
RS_STR("LUA_PATH_DEFAULT", LUA_PATH_DEFAULT),
RS_STR("LUA_CPATH_DEFAULT", LUA_CPATH_DEFAULT),
RS_STR("LUA_DIRSEP", LUA_DIRSEP),
RS_INT("LUA_EXTRASPACE", LUA_EXTRASPACE),
RS_INT("LUA_IDSIZE", LUA_IDSIZE),
// RS_INT("LUAI_MAXSHORTLEN", LUAI_MAXSHORTLEN),
// RS_TYPE("LUA_KCONTEXT", xstr(LUA_KCONTEXT)),
RS_INT("LUAI_BITSINT", LUAI_BITSINT),
// LUA_INT32? LUAI_UMEM? LUAI_MEM?
RS_INT("LUAI_MAXSTACK", LUAI_MAXSTACK),
RS_INT("LUAL_BUFFERSIZE", LUAL_BUFFERSIZE),
RS_TYPE("LUA_NUMBER",
sizeof(LUA_NUMBER) > sizeof(float) ? "c_double" : "c_float"),
RS_TYPE("LUA_UNSIGNED", rs_uint_type(sizeof(LUA_UNSIGNED))),
RS_TYPE("LUA_INTEGER", rs_int_type(sizeof(LUA_INTEGER))),
RS_LUAINT("LUA_MAXINTEGER", LUA_MAXINTEGER),
RS_LUAINT("LUA_MININTEGER", LUA_MININTEGER),
#if LUA_VERSION_NUM == 503
RS_TYPE("LUA_UNSIGNED", rs_uint_type(sizeof(LUA_UNSIGNED))),
#endif
// == lua.h ==============================================================
RS_COMMENT("lua.h"),
RS_STR("LUA_VERSION_MAJOR", LUA_VERSION_MAJOR),
RS_STR("LUA_VERSION_MINOR", LUA_VERSION_MINOR),
RS_INT("LUA_VERSION_NUM", LUA_VERSION_NUM),
RS_STR("LUA_VERSION_RELEASE", LUA_VERSION_RELEASE),
RS_STR("LUA_VERSION", LUA_VERSION),
RS_STR("LUA_RELEASE", LUA_RELEASE),
RS_STR("LUA_COPYRIGHT", LUA_COPYRIGHT),
RS_STR("LUA_AUTHORS", LUA_AUTHORS),
RS_INT("LUA_REGISTRYINDEX", LUA_REGISTRYINDEX),
#if LUA_VERSION_NUM == 501
RS_INT("LUA_ENVIRONINDEX", LUA_ENVIRONINDEX),
RS_INT("LUA_GLOBALSINDEX", LUA_GLOBALSINDEX),
#endif
// == lauxlib.h ==========================================================
RS_COMMENT("lauxlib.h"),
#if LUA_VERSION_NUM == 503
RS_INT("LUAL_NUMSIZES", LUAL_NUMSIZES),
RS_STR("LUA_FILEHANDLE", LUA_FILEHANDLE),
#endif
// == lualib.h ===========================================================
@ -251,8 +261,10 @@ int main(int argc, const char **argv) {
RS_STR("LUA_IOLIBNAME", LUA_IOLIBNAME),
RS_STR("LUA_OSLIBNAME", LUA_OSLIBNAME),
RS_STR("LUA_STRLIBNAME", LUA_STRLIBNAME),
#if LUA_VERSION_NUM == 503
RS_STR("LUA_UTF8LIBNAME", LUA_UTF8LIBNAME),
RS_STR("LUA_BITLIBNAME", LUA_BITLIBNAME),
#endif
RS_STR("LUA_MATHLIBNAME", LUA_MATHLIBNAME),
RS_STR("LUA_DBLIBNAME", LUA_DBLIBNAME),
RS_STR("LUA_LOADLIBNAME", LUA_LOADLIBNAME),

View file

@ -1,5 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2019 A. Orlenko
// Copyright (c) 2014 J.C. Moyer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
@ -26,10 +27,16 @@ use std::os::raw::{c_char, c_int, c_long, c_void};
use std::ptr;
use super::lua::{self, lua_CFunction, lua_Integer, lua_Number, lua_State};
use super::luaconf::LUAL_BUFFERSIZE;
#[cfg(feature = "lua53")]
pub use super::glue::LUAL_NUMSIZES;
pub use super::glue::LUA_FILEHANDLE;
#[cfg(not(feature = "lua53"))]
pub use super::compat53::{
luaL_checkversion, luaL_getmetafield, luaL_getsubtable, luaL_len, luaL_loadbufferx,
luaL_newmetatable, luaL_requiref, luaL_setfuncs, luaL_setmetatable, luaL_testudata,
luaL_tolstring, luaL_traceback,
};
// extra error code for 'luaL_load'
pub const LUA_ERRFILE: c_int = lua::LUA_ERRERR + 1;
@ -40,6 +47,7 @@ pub struct luaL_Reg {
pub func: lua_CFunction,
}
#[cfg(feature = "lua53")]
#[inline(always)]
pub unsafe fn luaL_checkversion(L: *mut lua_State) {
luaL_checkversion_(
@ -50,10 +58,17 @@ pub unsafe fn luaL_checkversion(L: *mut lua_State) {
}
extern "C" {
#[cfg(feature = "lua53")]
pub fn luaL_checkversion_(L: *mut lua_State, ver: lua_Number, sz: usize);
#[cfg(feature = "lua53")]
pub fn luaL_getmetafield(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int;
#[cfg(not(feature = "lua53"))]
#[link_name = "luaL_getmetafield"]
pub fn luaL_getmetafield_51(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;
#[cfg(feature = "lua53")]
pub fn luaL_tolstring(L: *mut lua_State, idx: c_int, len: *mut usize) -> *const c_char;
pub fn luaL_argerror(L: *mut lua_State, arg: c_int, l: *const c_char) -> c_int;
pub fn luaL_checklstring(L: *mut lua_State, arg: c_int, l: *mut usize) -> *const c_char;
@ -72,13 +87,20 @@ extern "C" {
pub fn luaL_checktype(L: *mut lua_State, arg: c_int, t: c_int);
pub fn luaL_checkany(L: *mut lua_State, arg: c_int);
#[cfg(feature = "lua53")]
pub fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_int;
#[cfg(not(feature = "lua53"))]
#[link_name = "luaL_newmetatable"]
pub fn luaL_newmetatable_51(L: *mut lua_State, tname: *const c_char) -> c_int;
#[cfg(feature = "lua53")]
pub fn luaL_setmetatable(L: *mut lua_State, tname: *const c_char);
#[cfg(feature = "lua53")]
pub fn luaL_testudata(L: *mut lua_State, ud: c_int, tname: *const c_char) -> *mut c_void;
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);
pub fn luaL_error(L: *mut lua_State, fmt: *const c_char, ...) -> c_int;
pub fn luaL_error(L: *mut lua_State, fmt: *const c_char, ...) -> !;
// TODO: test this
pub fn luaL_checkoption(
@ -88,7 +110,9 @@ extern "C" {
lst: *const *const c_char,
) -> c_int;
#[cfg(feature = "lua53")]
pub fn luaL_fileresult(L: *mut lua_State, stat: c_int, fname: *const c_char) -> c_int;
#[cfg(feature = "lua53")]
pub fn luaL_execresult(L: *mut lua_State, stat: c_int) -> c_int;
}
@ -100,16 +124,21 @@ extern "C" {
pub fn luaL_ref(L: *mut lua_State, t: c_int) -> c_int;
pub fn luaL_unref(L: *mut lua_State, t: c_int, r: c_int);
#[cfg(feature = "lua53")]
pub fn luaL_loadfilex(L: *mut lua_State, filename: *const c_char, mode: *const c_char)
-> c_int;
#[cfg(not(feature = "lua53"))]
pub fn luaL_loadfile(L: *mut lua_State, filename: *const c_char) -> c_int;
}
#[cfg(feature = "lua53")]
#[inline(always)]
pub unsafe fn luaL_loadfile(L: *mut lua_State, f: *const c_char) -> c_int {
luaL_loadfilex(L, f, ptr::null())
}
extern "C" {
#[cfg(feature = "lua53")]
pub fn luaL_loadbufferx(
L: *mut lua_State,
buff: *const c_char,
@ -117,10 +146,18 @@ extern "C" {
name: *const c_char,
mode: *const c_char,
) -> c_int;
#[cfg(not(feature = "lua53"))]
pub fn luaL_loadbuffer(
L: *mut lua_State,
buff: *const c_char,
sz: usize,
name: *const c_char,
) -> c_int;
pub fn luaL_loadstring(L: *mut lua_State, s: *const c_char) -> c_int;
pub fn luaL_newstate() -> *mut lua_State;
#[cfg(feature = "lua53")]
pub fn luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer;
pub fn luaL_gsub(
@ -130,12 +167,16 @@ extern "C" {
r: *const c_char,
) -> *const c_char;
#[cfg(feature = "lua53")]
pub fn luaL_setfuncs(L: *mut lua_State, l: *const luaL_Reg, nup: c_int);
#[cfg(feature = "lua53")]
pub fn luaL_getsubtable(L: *mut lua_State, idx: c_int, fname: *const c_char) -> c_int;
#[cfg(feature = "lua53")]
pub fn luaL_traceback(L: *mut lua_State, L1: *mut lua_State, msg: *const c_char, level: c_int);
#[cfg(feature = "lua53")]
pub fn luaL_requiref(
L: *mut lua_State,
modname: *const c_char,
@ -238,6 +279,7 @@ pub unsafe fn luaL_getmetatable(L: *mut lua_State, n: *const c_char) {
// luaL_opt would be implemented here but it is undocumented, so it's omitted
#[cfg(feature = "lua53")]
#[inline(always)]
pub unsafe fn luaL_loadbuffer(
L: *mut lua_State,
@ -248,46 +290,6 @@ pub unsafe fn luaL_loadbuffer(
luaL_loadbufferx(L, s, sz, n, ptr::null())
}
#[repr(C)]
pub struct luaL_Buffer {
pub b: *mut c_char,
pub size: usize,
pub n: usize,
pub L: *mut lua_State,
pub initb: [c_char; LUAL_BUFFERSIZE as usize],
}
// TODO: Test this thoroughly
#[inline(always)]
pub unsafe fn luaL_addchar(B: *mut luaL_Buffer, c: c_char) {
// (B)->n < (B) -> size || luaL_prepbuffsize((B), 1)
if (*B).n < (*B).size {
luaL_prepbuffsize(B, 1);
}
// (B)->b[(B)->n++] = (c)
let offset = (*B).b.offset((*B).n as isize);
ptr::write(offset, c);
(*B).n += 1;
}
#[inline(always)]
pub unsafe fn luaL_addsize(B: *mut luaL_Buffer, s: usize) {
(*B).n += s;
}
extern "C" {
pub fn luaL_buffinit(L: *mut lua_State, B: *mut luaL_Buffer);
pub fn luaL_prepbuffsize(B: *mut luaL_Buffer, sz: usize) -> *mut c_char;
pub fn luaL_addlstring(B: *mut luaL_Buffer, s: *const c_char, l: usize);
pub fn luaL_addstring(B: *mut luaL_Buffer, s: *const c_char);
pub fn luaL_addvalue(B: *mut luaL_Buffer);
pub fn luaL_pushresult(B: *mut luaL_Buffer);
pub fn luaL_pushresultsize(B: *mut luaL_Buffer, sz: usize);
pub fn luaL_buffinitsize(L: *mut lua_State, B: *mut luaL_Buffer, sz: usize) -> *mut c_char;
}
pub unsafe fn luaL_prepbuffer(B: *mut luaL_Buffer) -> *mut c_char {
luaL_prepbuffsize(B, LUAL_BUFFERSIZE as usize)
}
// TODO: Add buffer API
// omitted: old module system compatibility

View file

@ -1,5 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2019 A. Orlenko
// Copyright (c) 2014 J.C. Moyer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
@ -22,20 +23,33 @@
//! Contains definitions from `lua.h`.
use std::os::raw::{c_char, c_int, c_uchar, c_void};
#[cfg(feature = "lua53")]
use std::os::raw::c_uchar;
use std::os::raw::{c_char, c_int, c_void};
use std::ptr;
use super::luaconf;
pub use super::glue::{LUA_RELEASE, LUA_VERSION, LUA_VERSION_NUM};
pub use super::glue::LUA_REGISTRYINDEX;
pub use super::glue::{LUA_AUTHORS, LUA_COPYRIGHT, LUA_RELEASE, LUA_VERSION};
pub use super::glue::{LUA_VERSION_MAJOR, LUA_VERSION_MINOR, LUA_VERSION_NUM, LUA_VERSION_RELEASE};
#[cfg(not(feature = "lua53"))]
pub use super::glue::{LUA_ENVIRONINDEX, LUA_GLOBALSINDEX};
pub const LUA_SIGNATURE: &'static [u8] = b"\x1bLua";
// option for multiple returns in 'lua_pcall' and 'lua_call'
pub const LUA_MULTRET: c_int = -1;
#[cfg(not(feature = "lua53"))]
pub use super::compat53::{
lua_absindex, lua_compare, lua_copy, lua_getextraspace, lua_getfield, 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_rawsetp, lua_resume, lua_rotate,
lua_seti, lua_setuservalue, lua_tointegerx, lua_tonumberx, lua_upvalueindex,
};
#[cfg(feature = "lua53")]
#[inline(always)]
pub fn lua_upvalueindex(i: c_int) -> c_int {
LUA_REGISTRYINDEX - i
@ -47,7 +61,11 @@ pub const LUA_YIELD: c_int = 1;
pub const LUA_ERRRUN: c_int = 2;
pub const LUA_ERRSYNTAX: c_int = 3;
pub const LUA_ERRMEM: c_int = 4;
#[cfg(feature = "lua53")]
pub const LUA_ERRGCMM: c_int = 5;
#[cfg(not(feature = "lua53"))]
pub const LUA_ERRERR: c_int = 5;
#[cfg(feature = "lua53")]
pub const LUA_ERRERR: c_int = 6;
pub type lua_State = c_void;
@ -65,14 +83,18 @@ pub const LUA_TFUNCTION: c_int = 6;
pub const LUA_TUSERDATA: c_int = 7;
pub const LUA_TTHREAD: c_int = 8;
#[cfg(feature = "lua53")]
pub const LUA_NUMTAGS: c_int = 9;
// minimum stack available to a C function
pub const LUA_MINSTACK: c_int = 20;
// predefined values in the registry
#[cfg(feature = "lua53")]
pub const LUA_RIDX_MAINTHREAD: lua_Integer = 1;
#[cfg(feature = "lua53")]
pub const LUA_RIDX_GLOBALS: lua_Integer = 2;
#[cfg(feature = "lua53")]
pub const LUA_RIDX_LAST: lua_Integer = LUA_RIDX_GLOBALS;
/// A Lua number, usually equivalent to `f64`.
@ -82,15 +104,18 @@ pub type lua_Number = luaconf::LUA_NUMBER;
pub type lua_Integer = luaconf::LUA_INTEGER;
// unsigned integer type
#[cfg(feature = "lua53")]
pub type lua_Unsigned = luaconf::LUA_UNSIGNED;
// type for continuation-function contexts
#[cfg(feature = "lua53")]
pub type lua_KContext = luaconf::LUA_KCONTEXT;
/// Type for native functions that can be passed to Lua.
pub type lua_CFunction = unsafe extern "C" fn(L: *mut lua_State) -> c_int;
// Type for continuation functions
#[cfg(feature = "lua53")]
pub type lua_KFunction =
unsafe extern "C" fn(L: *mut lua_State, status: c_int, ctx: lua_KContext) -> c_int;
@ -116,14 +141,24 @@ extern "C" {
pub fn lua_atpanic(L: *mut lua_State, panicf: lua_CFunction) -> lua_CFunction;
#[cfg(feature = "lua53")]
pub fn lua_version(L: *mut lua_State) -> *const lua_Number;
// basic stack manipulation
#[cfg(feature = "lua53")]
pub fn lua_absindex(L: *mut lua_State, idx: c_int) -> c_int;
pub fn lua_gettop(L: *mut lua_State) -> c_int;
pub fn lua_settop(L: *mut lua_State, idx: c_int);
pub fn lua_pushvalue(L: *mut lua_State, idx: c_int);
#[cfg(not(feature = "lua53"))]
pub fn lua_remove(L: *mut lua_State, idx: c_int);
#[cfg(not(feature = "lua53"))]
pub fn lua_insert(L: *mut lua_State, idx: c_int);
#[cfg(not(feature = "lua53"))]
pub fn lua_replace(L: *mut lua_State, idx: c_int);
#[cfg(feature = "lua53")]
pub fn lua_rotate(L: *mut lua_State, idx: c_int, n: c_int);
#[cfg(feature = "lua53")]
pub fn lua_copy(L: *mut lua_State, fromidx: c_int, toidx: c_int);
pub fn lua_checkstack(L: *mut lua_State, sz: c_int) -> c_int;
@ -133,15 +168,25 @@ extern "C" {
pub fn lua_isnumber(L: *mut lua_State, idx: c_int) -> c_int;
pub fn lua_isstring(L: *mut lua_State, idx: c_int) -> c_int;
pub fn lua_iscfunction(L: *mut lua_State, idx: c_int) -> c_int;
#[cfg(feature = "lua53")]
pub fn lua_isinteger(L: *mut lua_State, idx: c_int) -> c_int;
pub fn lua_isuserdata(L: *mut lua_State, idx: c_int) -> c_int;
pub fn lua_type(L: *mut lua_State, idx: c_int) -> c_int;
pub fn lua_typename(L: *mut lua_State, tp: c_int) -> *const c_char;
#[cfg(not(feature = "lua53"))]
pub fn lua_tonumber(L: *mut lua_State, idx: c_int) -> lua_Number;
#[cfg(feature = "lua53")]
pub fn lua_tonumberx(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Number;
#[cfg(not(feature = "lua53"))]
pub fn lua_tointeger(L: *mut lua_State, idx: c_int) -> lua_Integer;
#[cfg(feature = "lua53")]
pub fn lua_tointegerx(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Integer;
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;
#[cfg(not(feature = "lua53"))]
pub fn lua_objlen(L: *mut lua_State, idx: c_int) -> usize;
#[cfg(feature = "lua53")]
pub fn lua_rawlen(L: *mut lua_State, idx: c_int) -> usize;
pub fn lua_tocfunction(L: *mut lua_State, idx: c_int) -> lua_CFunction;
pub fn lua_touserdata(L: *mut lua_State, idx: c_int) -> *mut c_void;
@ -150,22 +195,37 @@ extern "C" {
}
// Comparison and arithmetic functions
#[cfg(feature = "lua53")]
pub const LUA_OPADD: c_int = 0;
#[cfg(feature = "lua53")]
pub const LUA_OPSUB: c_int = 1;
#[cfg(feature = "lua53")]
pub const LUA_OPMUL: c_int = 2;
#[cfg(feature = "lua53")]
pub const LUA_OPMOD: c_int = 3;
#[cfg(feature = "lua53")]
pub const LUA_OPPOW: c_int = 4;
#[cfg(feature = "lua53")]
pub const LUA_OPDIV: c_int = 5;
#[cfg(feature = "lua53")]
pub const LUA_OPIDIV: c_int = 6;
#[cfg(feature = "lua53")]
pub const LUA_OPBAND: c_int = 7;
#[cfg(feature = "lua53")]
pub const LUA_OPBOR: c_int = 8;
#[cfg(feature = "lua53")]
pub const LUA_OPBXOR: c_int = 9;
#[cfg(feature = "lua53")]
pub const LUA_OPSHL: c_int = 10;
#[cfg(feature = "lua53")]
pub const LUA_OPSHR: c_int = 11;
#[cfg(feature = "lua53")]
pub const LUA_OPUNM: c_int = 12;
#[cfg(feature = "lua53")]
pub const LUA_OPBNOT: c_int = 13;
extern "C" {
#[cfg(feature = "lua53")]
pub fn lua_arith(L: *mut lua_State, op: c_int);
}
@ -174,7 +234,12 @@ pub const LUA_OPLT: c_int = 1;
pub const LUA_OPLE: c_int = 2;
extern "C" {
#[cfg(not(feature = "lua53"))]
pub fn lua_equal(L: *mut lua_State, idx1: c_int, idx2: c_int) -> c_int;
pub fn lua_rawequal(L: *mut lua_State, idx1: c_int, idx2: c_int) -> c_int;
#[cfg(not(feature = "lua53"))]
pub fn lua_lessthan(L: *mut lua_State, idx1: c_int, idx2: c_int) -> c_int;
#[cfg(feature = "lua53")]
pub fn lua_compare(L: *mut lua_State, idx1: c_int, idx2: c_int, op: c_int) -> c_int;
}
@ -183,8 +248,19 @@ extern "C" {
pub fn lua_pushnil(L: *mut lua_State);
pub fn lua_pushnumber(L: *mut lua_State, n: lua_Number);
pub fn lua_pushinteger(L: *mut lua_State, n: lua_Integer);
#[cfg(feature = "lua53")]
pub fn lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char;
#[cfg(not(feature = "lua53"))]
#[link_name = "lua_pushlstring"]
pub fn lua_pushlstring_51(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char;
#[cfg(feature = "lua53")]
pub fn lua_pushstring(L: *mut lua_State, s: *const c_char) -> *const c_char;
#[cfg(not(feature = "lua53"))]
#[link_name = "lua_pushstring"]
pub fn lua_pushstring_51(L: *mut lua_State, s: *const c_char) -> *const c_char;
// TODO: omitted:
// lua_pushvfstring
pub fn lua_pushfstring(L: *mut lua_State, fmt: *const c_char, ...) -> *const c_char;
@ -196,35 +272,70 @@ extern "C" {
// get functions (Lua -> stack)
extern "C" {
#[cfg(feature = "lua53")]
pub fn lua_getglobal(L: *mut lua_State, var: *const c_char) -> c_int;
#[cfg(feature = "lua53")]
pub fn lua_gettable(L: *mut lua_State, idx: c_int) -> c_int;
#[cfg(not(feature = "lua53"))]
#[link_name = "lua_gettable"]
pub fn lua_gettable_51(L: *mut lua_State, idx: c_int) -> c_int;
#[cfg(feature = "lua53")]
pub fn lua_getfield(L: *mut lua_State, idx: c_int, k: *const c_char) -> c_int;
#[cfg(not(feature = "lua53"))]
#[link_name = "lua_getfield"]
pub fn lua_getfield_51(L: *mut lua_State, idx: c_int, k: *const c_char) -> c_int;
#[cfg(feature = "lua53")]
pub fn lua_geti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int;
#[cfg(feature = "lua53")]
pub fn lua_rawget(L: *mut lua_State, idx: c_int) -> c_int;
#[cfg(not(feature = "lua53"))]
#[link_name = "lua_rawget"]
pub fn lua_rawget_51(L: *mut lua_State, idx: c_int);
#[cfg(feature = "lua53")]
pub fn lua_rawgeti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int;
#[cfg(not(feature = "lua53"))]
#[link_name = "lua_rawgeti"]
pub fn lua_rawgeti_51(L: *mut lua_State, idx: c_int, n: lua_Integer);
#[cfg(feature = "lua53")]
pub fn lua_rawgetp(L: *mut lua_State, idx: c_int, p: *const c_void) -> c_int;
pub fn lua_createtable(L: *mut lua_State, narr: c_int, nrec: c_int);
pub fn lua_newuserdata(L: *mut lua_State, sz: usize) -> *mut c_void;
pub fn lua_getmetatable(L: *mut lua_State, objindex: c_int) -> c_int;
#[cfg(feature = "lua53")]
pub fn lua_getuservalue(L: *mut lua_State, idx: c_int) -> c_int;
#[cfg(not(feature = "lua53"))]
pub fn lua_getfenv(L: *mut lua_State, idx: c_int);
}
// set functions (stack -> Lua)
extern "C" {
#[cfg(feature = "lua53")]
pub fn lua_setglobal(L: *mut lua_State, var: *const c_char);
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);
#[cfg(feature = "lua53")]
pub fn lua_seti(L: *mut lua_State, idx: c_int, n: lua_Integer);
pub fn lua_rawset(L: *mut lua_State, idx: c_int);
pub fn lua_rawseti(L: *mut lua_State, idx: c_int, n: lua_Integer);
#[cfg(feature = "lua53")]
pub fn lua_rawsetp(L: *mut lua_State, idx: c_int, p: *const c_void);
pub fn lua_setmetatable(L: *mut lua_State, objindex: c_int) -> c_int;
#[cfg(feature = "lua53")]
pub fn lua_setuservalue(L: *mut lua_State, idx: c_int);
#[cfg(not(feature = "lua53"))]
pub fn lua_setfenv(L: *mut lua_State, idx: c_int) -> c_int;
}
// 'load' and 'call' functions (load and run Lua code)
extern "C" {
#[cfg(feature = "lua53")]
pub fn lua_callk(
L: *mut lua_State,
nargs: c_int,
@ -232,6 +343,7 @@ extern "C" {
ctx: lua_KContext,
k: Option<lua_KFunction>,
);
#[cfg(feature = "lua53")]
pub fn lua_pcallk(
L: *mut lua_State,
nargs: c_int,
@ -240,6 +352,10 @@ extern "C" {
ctx: lua_KContext,
k: Option<lua_KFunction>,
) -> c_int;
#[cfg(not(feature = "lua53"))]
pub fn lua_call(L: *mut lua_State, nargs: c_int, nresults: c_int);
#[cfg(not(feature = "lua53"))]
pub fn lua_pcall(L: *mut lua_State, nargs: c_int, nresults: c_int, errfunc: c_int) -> c_int;
pub fn lua_load(
L: *mut lua_State,
reader: lua_Reader,
@ -247,6 +363,7 @@ extern "C" {
chunkname: *const c_char,
mode: *const c_char,
) -> c_int;
// FIXME
pub fn lua_dump(
L: *mut lua_State,
writer: lua_Writer,
@ -255,11 +372,13 @@ extern "C" {
) -> c_int;
}
#[cfg(feature = "lua53")]
#[inline(always)]
pub unsafe fn lua_call(L: *mut lua_State, n: c_int, r: c_int) {
lua_callk(L, n, r, 0, None)
}
#[cfg(feature = "lua53")]
#[inline(always)]
pub unsafe fn lua_pcall(L: *mut lua_State, n: c_int, r: c_int, f: c_int) -> c_int {
lua_pcallk(L, n, r, f, 0, None)
@ -267,17 +386,28 @@ pub unsafe fn lua_pcall(L: *mut lua_State, n: c_int, r: c_int, f: c_int) -> c_in
// coroutine functions
extern "C" {
#[cfg(feature = "lua53")]
pub fn lua_yieldk(
L: *mut lua_State,
nresults: c_int,
ctx: lua_KContext,
k: Option<lua_KFunction>,
) -> c_int;
#[cfg(not(feature = "lua53"))]
pub fn lua_yield(L: *mut lua_State, nresults: c_int) -> c_int;
#[cfg(feature = "lua53")]
pub fn lua_resume(L: *mut lua_State, from: *mut lua_State, narg: c_int) -> c_int;
#[cfg(not(feature = "lua53"))]
#[link_name = "lua_resume"]
pub fn lua_resume_51(L: *mut lua_State, narg: c_int) -> c_int;
pub fn lua_status(L: *mut lua_State) -> c_int;
#[cfg(feature = "lua53")]
pub fn lua_isyieldable(L: *mut lua_State) -> c_int;
}
#[cfg(feature = "lua53")]
#[inline(always)]
pub unsafe fn lua_yield(L: *mut lua_State, n: c_int) -> c_int {
lua_yieldk(L, n, 0, None)
@ -292,6 +422,7 @@ pub const LUA_GCCOUNTB: c_int = 4;
pub const LUA_GCSTEP: c_int = 5;
pub const LUA_GCSETPAUSE: c_int = 6;
pub const LUA_GCSETSTEPMUL: c_int = 7;
#[cfg(feature = "lua53")]
pub const LUA_GCISRUNNING: c_int = 9;
extern "C" {
@ -303,7 +434,9 @@ extern "C" {
pub fn lua_error(L: *mut lua_State) -> !;
pub fn lua_next(L: *mut lua_State, idx: c_int) -> c_int;
pub fn lua_concat(L: *mut lua_State, n: c_int);
#[cfg(feature = "lua53")]
pub fn lua_len(L: *mut lua_State, idx: c_int);
#[cfg(feature = "lua53")]
pub fn lua_stringtonumber(L: *mut lua_State, s: *const c_char) -> usize;
pub fn lua_getallocf(L: *mut lua_State, ud: *mut *mut c_void) -> lua_Alloc;
pub fn lua_setallocf(L: *mut lua_State, f: lua_Alloc, ud: *mut c_void);
@ -311,16 +444,19 @@ extern "C" {
// some useful macros
// here, implemented as Rust functions
#[cfg(feature = "lua53")]
#[inline(always)]
pub unsafe fn lua_getextraspace(L: *mut lua_State) -> *mut c_void {
L.offset(-super::glue::LUA_EXTRASPACE as isize) as *mut c_void
}
#[cfg(feature = "lua53")]
#[inline(always)]
pub unsafe fn lua_tonumber(L: *mut lua_State, i: c_int) -> lua_Number {
lua_tonumberx(L, i, ptr::null_mut())
}
#[cfg(feature = "lua53")]
#[inline(always)]
pub unsafe fn lua_tointeger(L: *mut lua_State, i: c_int) -> lua_Integer {
lua_tointegerx(L, i, ptr::null_mut())
@ -387,7 +523,6 @@ pub unsafe fn lua_isnoneornil(L: *mut lua_State, n: c_int) -> c_int {
(lua_type(L, n) <= 0) as c_int
}
// TODO: Test
#[inline(always)]
pub unsafe fn lua_pushliteral(L: *mut lua_State, s: &'static str) -> *const c_char {
use std::ffi::CString;
@ -395,6 +530,19 @@ pub unsafe fn lua_pushliteral(L: *mut lua_State, s: &'static str) -> *const c_ch
lua_pushlstring(L, c_str.as_ptr(), c_str.as_bytes().len())
}
#[cfg(not(feature = "lua53"))]
#[inline(always)]
pub unsafe fn lua_setglobal(L: *mut lua_State, var: *const c_char) {
lua_setfield(L, LUA_GLOBALSINDEX, var)
}
#[cfg(not(feature = "lua53"))]
#[inline(always)]
pub unsafe fn lua_getglobal(L: *mut lua_State, var: *const c_char) -> c_int {
lua_getfield(L, LUA_GLOBALSINDEX, var)
}
#[cfg(feature = "lua53")]
#[inline(always)]
pub unsafe fn lua_pushglobaltable(L: *mut lua_State) -> c_int {
lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS)
@ -405,17 +553,20 @@ pub unsafe fn lua_tostring(L: *mut lua_State, i: c_int) -> *const c_char {
lua_tolstring(L, i, ptr::null_mut())
}
#[cfg(feature = "lua53")]
#[inline(always)]
pub unsafe fn lua_insert(L: *mut lua_State, idx: c_int) {
lua_rotate(L, idx, 1)
}
#[cfg(feature = "lua53")]
#[inline(always)]
pub unsafe fn lua_remove(L: *mut lua_State, idx: c_int) {
lua_rotate(L, idx, -1);
lua_pop(L, 1)
}
#[cfg(feature = "lua53")]
#[inline(always)]
pub unsafe fn lua_replace(L: *mut lua_State, idx: c_int) {
lua_copy(L, -1, idx);
@ -437,7 +588,7 @@ pub const LUA_MASKLINE: c_int = 1 << (LUA_HOOKLINE as usize);
pub const LUA_MASKCOUNT: c_int = 1 << (LUA_HOOKCOUNT as usize);
/// Type for functions to be called on debug events.
pub type lua_Hook = Option<extern "C" fn(L: *mut lua_State, ar: *mut lua_Debug)>;
pub type lua_Hook = extern "C" fn(L: *mut lua_State, ar: *mut lua_Debug);
extern "C" {
pub fn lua_getstack(L: *mut lua_State, level: c_int, ar: *mut lua_Debug) -> c_int;
@ -447,15 +598,18 @@ extern "C" {
pub fn lua_getupvalue(L: *mut lua_State, funcindex: c_int, n: c_int) -> *const c_char;
pub fn lua_setupvalue(L: *mut lua_State, funcindex: c_int, n: c_int) -> *const c_char;
#[cfg(feature = "lua53")]
pub fn lua_upvalueid(L: *mut lua_State, fidx: c_int, n: c_int) -> *mut c_void;
#[cfg(feature = "lua53")]
pub fn lua_upvaluejoin(L: *mut lua_State, fidx1: c_int, n1: c_int, fidx2: c_int, n2: c_int);
pub fn lua_sethook(L: *mut lua_State, func: lua_Hook, mask: c_int, count: c_int);
pub fn lua_gethook(L: *mut lua_State) -> lua_Hook;
pub fn lua_gethook(L: *mut lua_State) -> Option<lua_Hook>;
pub fn lua_gethookmask(L: *mut lua_State) -> c_int;
pub fn lua_gethookcount(L: *mut lua_State) -> c_int;
}
#[cfg(feature = "lua53")]
#[repr(C)]
pub struct lua_Debug {
pub event: c_int,
@ -474,3 +628,20 @@ pub struct lua_Debug {
// lua.h mentions this is for private use
i_ci: *mut c_void,
}
#[cfg(not(feature = "lua53"))]
#[repr(C)]
pub struct lua_Debug {
pub event: c_int,
pub name: *const c_char,
pub namewhat: *const c_char,
pub what: *const c_char,
pub source: *const c_char,
pub currentline: c_int,
pub nups: c_int,
pub linedefined: c_int,
pub lastlinedefined: c_int,
pub short_src: [c_char; luaconf::LUA_IDSIZE as usize],
// lua.h mentions this is for private use
i_ci: c_int,
}

View file

@ -1,5 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2019 A. Orlenko
// Copyright (c) 2014 J.C. Moyer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
@ -25,24 +26,13 @@
pub use super::glue::LUAL_BUFFERSIZE;
pub use super::glue::LUA_INTEGER;
pub use super::glue::LUA_NUMBER;
#[cfg(feature = "lua53")]
pub use super::glue::LUA_UNSIGNED;
pub use super::glue::LUA_IDSIZE;
pub use super::glue::{LUA_MAXINTEGER, LUA_MININTEGER};
pub use super::glue::LUAI_MAXSTACK;
#[cfg(feature = "lua53")]
pub use super::glue::LUAL_NUMSIZES;
#[cfg(feature = "lua53")]
pub type LUA_KCONTEXT = isize; // intptr_t
use std::os::raw::c_int;
#[inline(always)]
pub unsafe fn lua_numtointeger(n: LUA_NUMBER, p: *mut LUA_INTEGER) -> c_int {
if n >= (LUA_MININTEGER as LUA_NUMBER) && n < -(LUA_MININTEGER as LUA_NUMBER) {
*p = n as LUA_INTEGER;
1
} else {
0
}
}

View file

@ -1,5 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2019 A. Orlenko
// Copyright (c) 2014 J.C. Moyer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
@ -27,18 +28,24 @@ use std::os::raw::c_int;
use super::lua::lua_State;
pub use super::glue::{
LUA_BITLIBNAME, LUA_COLIBNAME, LUA_DBLIBNAME, LUA_IOLIBNAME, LUA_LOADLIBNAME, LUA_MATHLIBNAME,
LUA_OSLIBNAME, LUA_STRLIBNAME, LUA_TABLIBNAME, LUA_UTF8LIBNAME,
LUA_COLIBNAME, LUA_DBLIBNAME, LUA_IOLIBNAME, LUA_LOADLIBNAME, LUA_MATHLIBNAME, LUA_OSLIBNAME,
LUA_STRLIBNAME, LUA_TABLIBNAME,
};
#[cfg(feature = "lua53")]
pub use super::glue::{LUA_BITLIBNAME, LUA_UTF8LIBNAME};
extern "C" {
pub fn luaopen_base(L: *mut lua_State) -> c_int;
#[cfg(feature = "lua53")]
pub fn luaopen_coroutine(L: *mut lua_State) -> c_int;
pub fn luaopen_table(L: *mut lua_State) -> c_int;
pub fn luaopen_io(L: *mut lua_State) -> c_int;
pub fn luaopen_os(L: *mut lua_State) -> c_int;
pub fn luaopen_string(L: *mut lua_State) -> c_int;
#[cfg(feature = "lua53")]
pub fn luaopen_utf8(L: *mut lua_State) -> c_int;
#[cfg(feature = "lua53")]
pub fn luaopen_bit32(L: *mut lua_State) -> c_int;
pub fn luaopen_math(L: *mut lua_State) -> c_int;
pub fn luaopen_debug(L: *mut lua_State) -> c_int;

View file

@ -1,5 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2019 A. Orlenko
// Copyright (c) 2014 J.C. Moyer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
@ -29,22 +30,23 @@ use std::os::raw::c_int;
// This is more or less in the order it appears in the Lua manual, with the
// exception of constants, which appear scattered throughout the manual text.
// luaconf.h functions
pub use self::luaconf::lua_numtointeger;
// C API types
pub use self::lua::{
lua_Alloc, lua_CFunction, lua_Debug, lua_Hook, lua_Integer, lua_KContext, lua_KFunction,
lua_Number, lua_Reader, lua_State, lua_Unsigned, lua_Writer,
lua_Alloc, lua_CFunction, lua_Debug, lua_Hook, lua_Integer, lua_Number, lua_Reader, lua_State,
lua_Writer,
};
#[cfg(feature = "lua53")]
pub use self::lua::{lua_KContext, lua_KFunction, lua_Unsigned};
#[cfg(not(feature = "lua53"))]
pub use self::lua::lua_setfenv;
// C API functions
pub use self::lua::{
lua_absindex,
lua_arith,
lua_atpanic,
lua_call,
lua_callk,
lua_checkstack,
lua_close,
lua_compare,
@ -84,7 +86,6 @@ pub use self::lua::{
lua_istable,
lua_isthread,
lua_isuserdata,
lua_isyieldable,
lua_len,
lua_load,
lua_newstate,
@ -93,7 +94,6 @@ pub use self::lua::{
lua_newuserdata,
lua_next,
lua_pcall,
lua_pcallk,
lua_pop,
lua_pushboolean,
lua_pushcclosure,
@ -135,7 +135,6 @@ pub use self::lua::{
lua_setupvalue,
lua_setuservalue,
lua_status,
lua_stringtonumber,
lua_toboolean,
lua_tocfunction,
lua_tointeger,
@ -149,61 +148,76 @@ pub use self::lua::{
lua_touserdata,
lua_type,
lua_typename,
lua_upvalueid,
lua_upvalueindex,
lua_upvaluejoin,
lua_version,
lua_xmove,
lua_yield,
lua_yieldk,
};
#[cfg(feature = "lua53")]
pub use self::lua::{
lua_arith, lua_callk, lua_isyieldable, lua_pcallk, lua_stringtonumber, lua_upvalueid,
lua_upvaluejoin, lua_version, lua_yieldk,
};
// auxiliary library types
pub use self::lauxlib::{luaL_Buffer, luaL_Reg};
pub use self::lauxlib::luaL_Reg;
// auxiliary library functions
pub use self::lauxlib::{
luaL_addchar, luaL_addlstring, luaL_addsize, luaL_addstring, luaL_addvalue, luaL_argcheck,
luaL_argerror, luaL_buffinit, luaL_buffinitsize, luaL_callmeta, luaL_checkany, luaL_checkint,
luaL_checkinteger, luaL_checklong, luaL_checklstring, luaL_checknumber, luaL_checkoption,
luaL_checkstack, luaL_checkstring, luaL_checktype, luaL_checkudata, luaL_checkversion,
luaL_dofile, luaL_dostring, luaL_error, luaL_execresult, luaL_fileresult, luaL_getmetafield,
luaL_getmetatable, luaL_getsubtable, luaL_gsub, luaL_len, luaL_loadbuffer, luaL_loadbufferx,
luaL_loadfile, luaL_loadfilex, luaL_loadstring, luaL_newlib, luaL_newlibtable,
luaL_argcheck, luaL_argerror, luaL_callmeta, luaL_checkany, luaL_checkint, luaL_checkinteger,
luaL_checklong, luaL_checklstring, luaL_checknumber, luaL_checkoption, luaL_checkstack,
luaL_checkstring, luaL_checktype, luaL_checkudata, luaL_dofile, luaL_dostring, luaL_error,
luaL_getmetafield, luaL_getmetatable, luaL_getsubtable, luaL_gsub, luaL_len, luaL_loadbuffer,
luaL_loadbufferx, luaL_loadfile, luaL_loadstring, luaL_newlib, luaL_newlibtable,
luaL_newmetatable, luaL_newstate, luaL_optint, luaL_optinteger, luaL_optlong, luaL_optlstring,
luaL_optnumber, luaL_optstring, luaL_prepbuffer, luaL_prepbuffsize, luaL_pushresult,
luaL_pushresultsize, luaL_ref, luaL_requiref, luaL_setfuncs, luaL_setmetatable, luaL_testudata,
luaL_tolstring, luaL_traceback, luaL_typename, luaL_unref, luaL_where,
luaL_optnumber, luaL_optstring, luaL_ref, luaL_requiref, luaL_setfuncs, luaL_setmetatable,
luaL_testudata, luaL_tolstring, luaL_traceback, luaL_typename, luaL_unref, luaL_where,
};
#[cfg(feature = "lua53")]
pub use self::lauxlib::{luaL_checkversion, luaL_execresult, luaL_fileresult, luaL_loadfilex};
// lualib.h functions
pub use self::lualib::{
luaL_openlibs, luaopen_base, luaopen_bit32, luaopen_coroutine, luaopen_debug, luaopen_io,
luaopen_math, luaopen_os, luaopen_package, luaopen_string, luaopen_table, luaopen_utf8,
luaL_openlibs, luaopen_base, luaopen_debug, luaopen_io, luaopen_math, luaopen_os,
luaopen_package, luaopen_string, luaopen_table,
};
#[cfg(feature = "lua53")]
pub use self::lualib::{luaopen_bit32, luaopen_coroutine, luaopen_utf8};
// constants from lua.h
pub use self::lua::{
LUA_ERRERR, LUA_ERRGCMM, LUA_ERRMEM, LUA_ERRRUN, LUA_ERRSYNTAX, LUA_GCCOLLECT, LUA_GCCOUNT,
LUA_GCCOUNTB, LUA_GCISRUNNING, LUA_GCRESTART, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL, LUA_GCSTEP,
LUA_GCSTOP, LUA_HOOKCALL, LUA_HOOKCOUNT, LUA_HOOKLINE, LUA_HOOKRET, LUA_HOOKTAILCALL,
LUA_MASKCALL, LUA_MASKCOUNT, LUA_MASKLINE, LUA_MASKRET, LUA_MINSTACK, LUA_MULTRET, LUA_OK,
LUA_OPADD, LUA_OPBAND, LUA_OPBNOT, LUA_OPBOR, LUA_OPBXOR, LUA_OPDIV, LUA_OPEQ, LUA_OPIDIV,
LUA_OPLE, LUA_OPLT, LUA_OPMOD, LUA_OPMUL, LUA_OPPOW, LUA_OPSHL, LUA_OPSHR, LUA_OPSUB,
LUA_OPUNM, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS, LUA_RIDX_MAINTHREAD, LUA_TBOOLEAN,
LUA_TFUNCTION, LUA_TLIGHTUSERDATA, LUA_TNIL, LUA_TNONE, LUA_TNUMBER, LUA_TSTRING, LUA_TTABLE,
LUA_TTHREAD, LUA_TUSERDATA, LUA_YIELD,
LUA_ERRERR, LUA_ERRMEM, LUA_ERRRUN, LUA_ERRSYNTAX, LUA_GCCOLLECT, LUA_GCCOUNT, LUA_GCCOUNTB,
LUA_GCRESTART, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL, LUA_GCSTEP, LUA_GCSTOP, LUA_HOOKCALL,
LUA_HOOKCOUNT, LUA_HOOKLINE, LUA_HOOKRET, LUA_HOOKTAILCALL, LUA_MASKCALL, LUA_MASKCOUNT,
LUA_MASKLINE, LUA_MASKRET, LUA_MINSTACK, LUA_MULTRET, LUA_OK, LUA_OPEQ, LUA_OPLE, LUA_OPLT,
LUA_REGISTRYINDEX, LUA_TBOOLEAN, LUA_TFUNCTION, LUA_TLIGHTUSERDATA, LUA_TNIL, LUA_TNONE,
LUA_TNUMBER, LUA_TSTRING, LUA_TTABLE, LUA_TTHREAD, LUA_TUSERDATA, LUA_YIELD,
};
#[cfg(feature = "lua53")]
pub use self::lua::{
LUA_ERRGCMM, LUA_GCISRUNNING, LUA_OPADD, LUA_OPBAND, LUA_OPBNOT, LUA_OPBOR, LUA_OPBXOR,
LUA_OPDIV, LUA_OPIDIV, LUA_OPMOD, LUA_OPMUL, LUA_OPPOW, LUA_OPSHL, LUA_OPSHR, LUA_OPSUB,
LUA_OPUNM, LUA_RIDX_GLOBALS, LUA_RIDX_MAINTHREAD,
};
#[cfg(not(feature = "lua53"))]
pub use self::lua::{LUA_ENVIRONINDEX, LUA_GLOBALSINDEX};
// constants from lauxlib.h
pub use self::lauxlib::{LUA_ERRFILE, LUA_FILEHANDLE, LUA_NOREF, LUA_REFNIL};
pub use self::lauxlib::{LUA_ERRFILE, LUA_NOREF, LUA_REFNIL};
// constants from lualib.h
pub use self::lualib::{
LUA_BITLIBNAME, LUA_COLIBNAME, LUA_DBLIBNAME, LUA_IOLIBNAME, LUA_LOADLIBNAME, LUA_MATHLIBNAME,
LUA_OSLIBNAME, LUA_STRLIBNAME, LUA_TABLIBNAME, LUA_UTF8LIBNAME,
LUA_COLIBNAME, LUA_DBLIBNAME, LUA_IOLIBNAME, LUA_LOADLIBNAME, LUA_MATHLIBNAME, LUA_OSLIBNAME,
LUA_STRLIBNAME, LUA_TABLIBNAME,
};
#[cfg(feature = "lua53")]
pub use self::lualib::{LUA_BITLIBNAME, LUA_UTF8LIBNAME};
// Not actually defined in lua.h / luaconf.h
pub const LUA_MAX_UPVALUES: c_int = 255;
@ -212,6 +226,9 @@ mod glue {
include!(concat!(env!("OUT_DIR"), "/glue.rs"));
}
#[cfg(not(feature = "lua53"))]
mod compat53;
mod lauxlib;
mod lua;
mod luaconf;

View file

@ -16,6 +16,8 @@ use crate::table::Table;
use crate::thread::Thread;
use crate::types::{Callback, Integer, LightUserData, LuaRef, Number, RegistryKey};
use crate::userdata::{AnyUserData, MetaMethod, UserData, UserDataMethods};
#[cfg(not(feature = "lua53"))]
use crate::util::set_main_state;
use crate::util::{
assert_stack, callback_error, check_stack, get_main_state, get_userdata, get_wrapped_error,
init_error_registry, init_userdata_metatable, pop_error, protect_lua, protect_lua_closure,
@ -34,9 +36,41 @@ pub struct Lua {
unsafe impl Send for Lua {}
impl Lua {
// Creates a new Lua state and loads standard library without the debug library.
#[doc(hidden)]
pub fn new() -> Lua {
unsafe {
let state = ffi::luaL_newstate();
ffi::luaL_requiref(state, cstr!("_G"), ffi::luaopen_base, 1);
#[cfg(feature = "lua53")]
ffi::luaL_requiref(state, cstr!("coroutine"), ffi::luaopen_coroutine, 1);
ffi::luaL_requiref(state, cstr!("table"), ffi::luaopen_table, 1);
ffi::luaL_requiref(state, cstr!("io"), ffi::luaopen_io, 1);
ffi::luaL_requiref(state, cstr!("os"), ffi::luaopen_os, 1);
ffi::luaL_requiref(state, cstr!("string"), ffi::luaopen_string, 1);
#[cfg(feature = "lua53")]
ffi::luaL_requiref(state, cstr!("utf8"), ffi::luaopen_utf8, 1);
ffi::luaL_requiref(state, cstr!("math"), ffi::luaopen_math, 1);
ffi::luaL_requiref(state, cstr!("package"), ffi::luaopen_package, 1);
#[cfg(feature = "lua53")]
ffi::lua_pop(state, 9);
#[cfg(not(feature = "lua53"))]
ffi::lua_pop(state, 7);
Lua::init_from_ptr(state)
}
}
/// Constructs a new Lua instance from the existing state.
pub unsafe fn init_from_ptr(state: *mut ffi::lua_State) -> Lua {
#[cfg(feature = "lua53")]
let main_state = get_main_state(state);
#[cfg(not(feature = "lua53"))]
let main_state = {
set_main_state(state);
state
};
let main_state_top = ffi::lua_gettop(state);
let ref_thread = mlua_expect!(
@ -113,6 +147,7 @@ impl Lua {
}
/// Returns true if the garbage collector is currently running automatically.
#[cfg(feature = "lua53")]
pub fn gc_is_running(&self) -> bool {
unsafe { ffi::lua_gc(self.main_state, ffi::LUA_GCISRUNNING, 0) != 0 }
}
@ -231,7 +266,10 @@ impl Lua {
ffi::LUA_OK => {
if let Some(env) = env {
self.push_value(env)?;
#[cfg(feature = "lua53")]
ffi::lua_setupvalue(self.state, -2, 1);
#[cfg(not(feature = "lua53"))]
ffi::lua_setfenv(self.state, -2);
}
Ok(Function(self.pop_ref()))
}
@ -421,7 +459,10 @@ impl Lua {
unsafe {
let _sg = StackGuard::new(self.state);
assert_stack(self.state, 2);
#[cfg(feature = "lua53")]
ffi::lua_rawgeti(self.state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS);
#[cfg(not(feature = "lua53"))]
ffi::lua_pushvalue(self.state, ffi::LUA_GLOBALSINDEX);
Table(self.pop_ref())
}
}

View file

@ -175,6 +175,12 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
assert_stack(lua.state, 1);
lua.push_ref(&u.0);
ffi::lua_getuservalue(lua.state, -1);
#[cfg(not(feature = "lua53"))]
{
ffi::lua_pushinteger(lua.state, 1);
ffi::lua_gettable(lua.state, -2);
ffi::lua_remove(lua.state, -2);
}
return ffi::lua_touserdata(lua.state, -1)
== check_data.as_ptr() as *mut c_void;
}
@ -239,7 +245,16 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
assert_stack(lua.state, 6);
push_userdata(lua.state, ())?;
#[cfg(feature = "lua53")]
ffi::lua_pushlightuserdata(lua.state, data.as_ptr() as *mut c_void);
#[cfg(not(feature = "lua53"))]
protect_lua_closure(lua.state, 0, 1, |state| {
// Lua 5.1 allows to store only table. Then we will wrap the value.
ffi::lua_createtable(state, 1, 0);
ffi::lua_pushinteger(state, 1);
ffi::lua_pushlightuserdata(state, data.as_ptr() as *mut c_void);
ffi::lua_settable(state, -3);
})?;
ffi::lua_setuservalue(lua.state, -2);
protect_lua_closure(lua.state, 0, 1, move |state| {

View file

@ -335,6 +335,14 @@ impl<'lua> AnyUserData<'lua> {
/// [`get_user_value`]: #method.get_user_value
pub fn set_user_value<V: ToLua<'lua>>(&self, v: V) -> Result<()> {
let lua = self.0.lua;
#[cfg(not(feature = "lua53"))]
let v = {
// Lua 5.1 allows to store only table. Then we will wrap the value.
let t = lua.create_table()?;
t.raw_set(1, v)?;
crate::Value::Table(t)
};
#[cfg(feature = "lua53")]
let v = v.to_lua(lua)?;
unsafe {
let _sg = StackGuard::new(lua.state);
@ -358,6 +366,9 @@ impl<'lua> AnyUserData<'lua> {
ffi::lua_getuservalue(lua.state, -1);
lua.pop_value()
};
#[cfg(not(feature = "lua53"))]
return crate::Table::from_lua(res, lua)?.get(1);
#[cfg(feature = "lua53")]
V::from_lua(res, lua)
}

View file

@ -192,7 +192,8 @@ pub unsafe fn pop_error(state: *mut ffi::lua_State, err_code: c_int) -> Error {
Error::SyntaxError {
// This seems terrible, but as far as I can tell, this is exactly what the
// stock Lua REPL does.
incomplete_input: err_string.ends_with("<eof>"),
incomplete_input: err_string.ends_with("<eof>")
|| err_string.ends_with("'<eof>'"),
message: err_string,
}
}
@ -204,6 +205,7 @@ pub unsafe fn pop_error(state: *mut ffi::lua_State, err_code: c_int) -> Error {
Error::RuntimeError(err_string)
}
ffi::LUA_ERRMEM => Error::MemoryError(err_string),
#[cfg(feature = "lua53")]
ffi::LUA_ERRGCMM => Error::GarbageCollectorError(err_string),
_ => mlua_panic!("unrecognized lua error code"),
}
@ -441,9 +443,23 @@ pub unsafe extern "C" fn error_traceback(state: *mut ffi::lua_State) -> c_int {
1
}
// Does not call lua_checkstack, uses 2 stack spaces.
#[cfg(not(feature = "lua53"))]
pub unsafe fn set_main_state(state: *mut ffi::lua_State) {
ffi::lua_pushlightuserdata(state, &MAIN_THREAD_REGISTRY_KEY as *const u8 as *mut c_void);
ffi::lua_pushthread(state);
ffi::lua_rawset(state, ffi::LUA_REGISTRYINDEX);
}
// Does not call lua_checkstack, uses 1 stack space.
pub unsafe fn get_main_state(state: *mut ffi::lua_State) -> *mut ffi::lua_State {
#[cfg(feature = "lua53")]
ffi::lua_rawgeti(state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_MAINTHREAD);
#[cfg(not(feature = "lua53"))]
{
ffi::lua_pushlightuserdata(state, &MAIN_THREAD_REGISTRY_KEY as *const u8 as *mut c_void);
ffi::lua_rawget(state, ffi::LUA_REGISTRYINDEX);
}
let main_state = ffi::lua_tothread(state, -1);
ffi::lua_pop(state, 1);
main_state
@ -735,6 +751,8 @@ unsafe fn get_destructed_userdata_metatable(state: *mut ffi::lua_State) {
ffi::lua_rawget(state, ffi::LUA_REGISTRYINDEX);
}
#[cfg(not(feature = "lua53"))]
static MAIN_THREAD_REGISTRY_KEY: u8 = 0;
static ERROR_METATABLE_REGISTRY_KEY: u8 = 0;
static PANIC_METATABLE_REGISTRY_KEY: u8 = 0;
static DESTRUCTED_USERDATA_METATABLE: u8 = 0;

View file

@ -1,53 +0,0 @@
#[allow(non_camel_case_types)]
type lua_State = std::os::raw::c_void;
#[allow(non_camel_case_types)]
type lua_CFunction = unsafe extern "C" fn(L: *mut lua_State) -> std::os::raw::c_int;
extern "C" {
fn luaL_newstate() -> *mut lua_State;
fn luaL_requiref(
L: *mut lua_State,
modname: *const std::os::raw::c_char,
openf: lua_CFunction,
glb: std::os::raw::c_int,
);
fn lua_settop(L: *mut lua_State, idx: std::os::raw::c_int);
fn luaopen_base(L: *mut lua_State) -> std::os::raw::c_int;
fn luaopen_coroutine(L: *mut lua_State) -> std::os::raw::c_int;
fn luaopen_table(L: *mut lua_State) -> std::os::raw::c_int;
fn luaopen_io(L: *mut lua_State) -> std::os::raw::c_int;
fn luaopen_os(L: *mut lua_State) -> std::os::raw::c_int;
fn luaopen_string(L: *mut lua_State) -> std::os::raw::c_int;
fn luaopen_math(L: *mut lua_State) -> std::os::raw::c_int;
fn luaopen_package(L: *mut lua_State) -> std::os::raw::c_int;
}
#[allow(unused)]
fn make_lua() -> mlua::Lua {
macro_rules! cstr {
($s:expr) => {
concat!($s, "\0") as *const str as *const ::std::os::raw::c_char
};
}
unsafe {
let state = luaL_newstate();
// Do not open the debug library, it can be used to cause unsafety.
luaL_requiref(state, cstr!("_G"), luaopen_base, 1);
luaL_requiref(state, cstr!("coroutine"), luaopen_coroutine, 1);
luaL_requiref(state, cstr!("table"), luaopen_table, 1);
luaL_requiref(state, cstr!("io"), luaopen_io, 1);
luaL_requiref(state, cstr!("os"), luaopen_os, 1);
luaL_requiref(state, cstr!("string"), luaopen_string, 1);
luaL_requiref(state, cstr!("math"), luaopen_math, 1);
luaL_requiref(state, cstr!("package"), luaopen_package, 1);
lua_settop(state, -8 - 1);
mlua::Lua::init_from_ptr(state)
}
}

View file

@ -1,21 +1,19 @@
use bstr::{BStr, BString};
use mlua::Result;
include!("_lua.rs");
use mlua::{Lua, Result};
#[test]
fn byte_string_round_trip() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
lua.load(
r#"
invalid_sequence_identifier = "\xa0\xa1"
invalid_2_octet_sequence_2nd = "\xc3\x28"
invalid_3_octet_sequence_2nd = "\xe2\x28\xa1"
invalid_3_octet_sequence_3rd = "\xe2\x82\x28"
invalid_4_octet_sequence_2nd = "\xf0\x28\x8c\xbc"
invalid_4_octet_sequence_3rd = "\xf0\x90\x28\xbc"
invalid_4_octet_sequence_4th = "\xf0\x28\x8c\x28"
invalid_sequence_identifier = "\160\161"
invalid_2_octet_sequence_2nd = "\195\040"
invalid_3_octet_sequence_2nd = "\226\040\161"
invalid_3_octet_sequence_3rd = "\226\130\040"
invalid_4_octet_sequence_2nd = "\240\040\140\188"
invalid_4_octet_sequence_3rd = "\240\144\040\188"
invalid_4_octet_sequence_4th = "\240\040\140\040"
an_actual_string = "Hello, world!"
"#,

View file

@ -1,10 +1,8 @@
use mlua::{Function, Result, String};
include!("_lua.rs");
use mlua::{Function, Lua, Result, String};
#[test]
fn test_function() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
let globals = lua.globals();
lua.load(
@ -24,7 +22,7 @@ fn test_function() -> Result<()> {
#[test]
fn test_bind() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
let globals = lua.globals();
lua.load(
@ -54,7 +52,7 @@ fn test_bind() -> Result<()> {
#[test]
fn test_rust_function() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
let globals = lua.globals();
lua.load(

View file

@ -1,18 +1,19 @@
use std::sync::Arc;
use mlua::{Error, Result, UserData};
include!("_lua.rs");
use mlua::{Lua, Result, UserData};
#[test]
fn test_gc_control() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
assert!(lua.gc_is_running());
lua.gc_stop();
assert!(!lua.gc_is_running());
lua.gc_restart();
assert!(lua.gc_is_running());
#[cfg(feature = "lua53")]
{
assert!(lua.gc_is_running());
lua.gc_stop();
assert!(!lua.gc_is_running());
lua.gc_restart();
assert!(lua.gc_is_running());
}
struct MyUserdata(Arc<()>);
impl UserData for MyUserdata {}
@ -30,9 +31,12 @@ fn test_gc_control() -> Result<()> {
Ok(())
}
#[cfg(feature = "lua53")]
#[test]
fn test_gc_error() {
let lua = make_lua();
use mlua::Error;
let lua = Lua::new();
match lua
.load(
r#"

View file

@ -1,13 +1,11 @@
use std::cell::Cell;
use std::rc::Rc;
use mlua::{Error, Function, MetaMethod, Result, String, UserData, UserDataMethods};
include!("_lua.rs");
use mlua::{Error, Function, Lua, MetaMethod, Result, String, UserData, UserDataMethods};
#[test]
fn scope_func() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
let rc = Rc::new(Cell::new(0));
lua.scope(|scope| {
@ -34,7 +32,7 @@ fn scope_func() -> Result<()> {
#[test]
fn scope_drop() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
struct MyUserdata(Rc<()>);
impl UserData for MyUserdata {
@ -65,7 +63,7 @@ fn scope_drop() -> Result<()> {
#[test]
fn scope_capture() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
let mut i = 0;
lua.scope(|scope| {
@ -83,7 +81,7 @@ fn scope_capture() -> Result<()> {
#[test]
fn outer_lua_access() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
let table = lua.create_table()?;
lua.scope(|scope| {
@ -114,7 +112,7 @@ fn scope_userdata_methods() -> Result<()> {
}
}
let lua = make_lua();
let lua = Lua::new();
let i = Cell::new(42);
let f: Function = lua
@ -156,7 +154,7 @@ fn scope_userdata_functions() -> Result<()> {
}
}
let lua = make_lua();
let lua = Lua::new();
let dummy = 0;
let f = lua
@ -192,7 +190,7 @@ fn scope_userdata_mismatch() -> Result<()> {
}
}
let lua = make_lua();
let lua = Lua::new();
lua.load(
r#"

View file

@ -1,13 +1,11 @@
use std::borrow::Cow;
use mlua::{Result, String};
include!("_lua.rs");
use mlua::{Lua, Result, String};
#[test]
fn compare() {
fn with_str<F: FnOnce(String)>(s: &str, f: F) {
f(make_lua().create_string(s).unwrap());
f(Lua::new().create_string(s).unwrap());
}
// Tests that all comparisons we want to have are usable
@ -24,12 +22,12 @@ fn compare() {
#[test]
fn string_views() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
lua.load(
r#"
ok = "null bytes are valid utf-8, wh\0 knew?"
err = "but \xff isn't :("
err = "but \255 isn't :("
empty = ""
"#,
)
@ -58,7 +56,7 @@ fn string_views() -> Result<()> {
#[test]
fn raw_string() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
let rs = lua.create_string(&[0, 1, 2, 3, 0, 1, 2, 3])?;
assert_eq!(rs.as_bytes(), &[0, 1, 2, 3, 0, 1, 2, 3]);

View file

@ -1,10 +1,8 @@
use mlua::{Nil, Result, Table, Value};
include!("_lua.rs");
use mlua::{Lua, Nil, Result, Table, Value};
#[test]
fn test_set_get() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
let globals = lua.globals();
globals.set("foo", "bar")?;
@ -17,7 +15,7 @@ fn test_set_get() -> Result<()> {
#[test]
fn test_table() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
let globals = lua.globals();
@ -91,7 +89,7 @@ fn test_table() -> Result<()> {
#[test]
fn test_table_scope() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
let globals = lua.globals();
lua.load(
@ -119,7 +117,7 @@ fn test_table_scope() -> Result<()> {
#[test]
fn test_metatable() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
let table = lua.create_table()?;
let metatable = lua.create_table()?;
@ -141,7 +139,7 @@ fn test_metatable() -> Result<()> {
#[test]
fn test_table_error() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
let globals = lua.globals();
lua.load(

View file

@ -3,13 +3,13 @@ use std::panic::catch_unwind;
use std::sync::Arc;
use std::{error, f32, f64, fmt};
use mlua::{Error, ExternalError, Function, Nil, Result, String, Table, UserData, Value, Variadic};
include!("_lua.rs");
use mlua::{
Error, ExternalError, Function, Lua, Nil, Result, String, Table, UserData, Value, Variadic,
};
#[test]
fn test_load() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
let func = lua.load("return 1+2").into_function()?;
let result: i32 = func.call(())?;
assert_eq!(result, 3);
@ -21,7 +21,7 @@ fn test_load() -> Result<()> {
#[test]
fn test_exec() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
let globals = lua.globals();
lua.load(
@ -56,7 +56,7 @@ fn test_exec() -> Result<()> {
#[test]
fn test_eval() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
assert_eq!(lua.load("1 + 1").eval::<i32>()?, 2);
assert_eq!(lua.load("false == false").eval::<bool>()?, true);
@ -77,7 +77,7 @@ fn test_eval() -> Result<()> {
#[test]
fn test_lua_multi() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
lua.load(
r#"
@ -108,7 +108,7 @@ fn test_lua_multi() -> Result<()> {
#[test]
fn test_coercion() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
lua.load(
r#"
@ -148,7 +148,7 @@ fn test_error() -> Result<()> {
}
}
let lua = make_lua();
let lua = Lua::new();
let globals = lua.globals();
lua.load(
@ -183,6 +183,13 @@ fn test_error() -> Result<()> {
end, 3)
local function handler(err)
if string.match(_VERSION, ' 5%.1$') then
-- Special case for Lua 5.1
local caps = string.match(err, ': (%d+)$')
if caps then
err = caps
end
end
testvar = testvar + err
return "should be ignored"
end
@ -260,7 +267,7 @@ fn test_error() -> Result<()> {
assert!(understand_recursion.call::<_, ()>(()).is_err());
match catch_unwind(|| -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
let globals = lua.globals();
lua.load(
@ -288,7 +295,7 @@ fn test_error() -> Result<()> {
};
match catch_unwind(|| -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
let globals = lua.globals();
lua.load(
@ -321,7 +328,7 @@ fn test_error() -> Result<()> {
#[test]
fn test_result_conversions() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
let globals = lua.globals();
let err = lua.create_function(|_, ()| {
@ -352,7 +359,7 @@ fn test_result_conversions() -> Result<()> {
#[test]
fn test_num_conversion() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
assert_eq!(
lua.coerce_integer(Value::String(lua.create_string("1")?))?,
@ -382,7 +389,10 @@ fn test_num_conversion() -> Result<()> {
assert_eq!(lua.load("1.0").eval::<i64>()?, 1);
assert_eq!(lua.load("1.0").eval::<f64>()?, 1.0);
#[cfg(feature = "lua53")]
assert_eq!(lua.load("1.0").eval::<String>()?, "1.0");
#[cfg(not(feature = "lua53"))]
assert_eq!(lua.load("1.0").eval::<String>()?, "1");
assert_eq!(lua.load("1.5").eval::<i64>()?, 1);
assert_eq!(lua.load("1.5").eval::<f64>()?, 1.5);
@ -404,7 +414,7 @@ fn test_num_conversion() -> Result<()> {
#[test]
fn test_pcall_xpcall() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
let globals = lua.globals();
// make sure that we handle not enough arguments
@ -413,6 +423,18 @@ fn test_pcall_xpcall() -> Result<()> {
assert!(lua.load("xpcall()").exec().is_err());
assert!(lua.load("xpcall(function() end)").exec().is_err());
// Lua5.3 compatible version of xpcall
#[cfg(not(feature = "lua53"))]
lua.load(
r#"
local xpcall_orig = xpcall
function xpcall(f, err, ...)
return xpcall_orig(function() return f(unpack(arg)) end, err)
end
"#,
)
.exec()?;
// Make sure that the return values from are correct on success
let (r, e) = lua
@ -444,7 +466,13 @@ fn test_pcall_xpcall() -> Result<()> {
assert_eq!(globals.get::<_, String>("pcall_error")?, "testerror");
assert_eq!(globals.get::<_, bool>("xpcall_statusr")?, false);
#[cfg(feature = "lua53")]
assert_eq!(globals.get::<_, String>("xpcall_error")?, "testerror");
#[cfg(not(feature = "lua53"))]
assert!(globals
.get::<_, String>("xpcall_error")?
.to_str()?
.ends_with(": testerror"));
// Make sure that weird xpcall error recursion at least doesn't cause unsafety or panics.
lua.load(
@ -464,7 +492,7 @@ fn test_pcall_xpcall() -> Result<()> {
#[test]
fn test_recursive_mut_callback_error() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
let mut v = Some(Box::new(123));
let f = lua.create_function_mut::<_, (), _>(move |lua, mutate: bool| {
@ -499,7 +527,7 @@ fn test_recursive_mut_callback_error() -> Result<()> {
#[test]
fn test_set_metatable_nil() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
lua.load(
r#"
a = {}
@ -512,7 +540,7 @@ fn test_set_metatable_nil() -> Result<()> {
#[test]
fn test_named_registry_value() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
lua.set_named_registry_value::<_, i32>("test", 42)?;
let f = lua.create_function(move |lua, ()| {
@ -533,7 +561,7 @@ fn test_named_registry_value() -> Result<()> {
#[test]
fn test_registry_value() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
let mut r = Some(lua.create_registry_value::<i32>(42)?);
let f = lua.create_function_mut(move |lua, ()| {
@ -557,7 +585,7 @@ fn test_drop_registry_value() -> Result<()> {
impl UserData for MyUserdata {}
let lua = make_lua();
let lua = Lua::new();
let rc = Arc::new(());
let r = lua.create_registry_value(MyUserdata(rc.clone()))?;
@ -575,8 +603,8 @@ fn test_drop_registry_value() -> Result<()> {
#[test]
fn test_lua_registry_ownership() -> Result<()> {
let lua1 = make_lua();
let lua2 = make_lua();
let lua1 = Lua::new();
let lua2 = Lua::new();
let r1 = lua1.create_registry_value("hello")?;
let r2 = lua2.create_registry_value("hello")?;
@ -591,8 +619,8 @@ fn test_lua_registry_ownership() -> Result<()> {
#[test]
fn test_mismatched_registry_key() -> Result<()> {
let lua1 = make_lua();
let lua2 = make_lua();
let lua1 = Lua::new();
let lua2 = Lua::new();
let r = lua1.create_registry_value("hello")?;
match lua2.remove_registry_value(r) {
@ -605,7 +633,7 @@ fn test_mismatched_registry_key() -> Result<()> {
#[test]
fn too_many_returns() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
let f = lua.create_function(|_, ()| Ok(Variadic::from_iter(1..1000000)))?;
assert!(f.call::<_, Vec<u32>>(()).is_err());
Ok(())
@ -613,7 +641,7 @@ fn too_many_returns() -> Result<()> {
#[test]
fn too_many_arguments() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
lua.load("function test(...) end").exec()?;
let args = Variadic::from_iter(1..1000000);
assert!(lua
@ -626,7 +654,7 @@ fn too_many_arguments() -> Result<()> {
#[test]
fn too_many_recursions() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
let f = lua
.create_function(move |lua, ()| lua.globals().get::<_, Function>("f")?.call::<_, ()>(()))?;
lua.globals().set("f", f)?;
@ -642,7 +670,7 @@ fn too_many_recursions() -> Result<()> {
#[test]
fn too_many_binds() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
let globals = lua.globals();
lua.load(
r#"
@ -663,7 +691,7 @@ fn too_many_binds() -> Result<()> {
#[test]
fn large_args() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
let globals = lua.globals();
globals.set(
@ -698,7 +726,7 @@ fn large_args() -> Result<()> {
#[test]
fn large_args_ref() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
let f = lua.create_function(|_, args: Variadic<String>| {
for i in 0..args.len() {
@ -714,7 +742,7 @@ fn large_args_ref() -> Result<()> {
#[test]
fn chunk_env() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
let assert: Function = lua.globals().get("assert")?;
@ -756,7 +784,7 @@ fn chunk_env() -> Result<()> {
#[test]
fn context_thread() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
let f = lua
.load(
@ -767,7 +795,32 @@ fn context_thread() -> Result<()> {
)
.into_function()?;
#[cfg(feature = "lua53")]
f.call::<_, ()>(lua.current_thread())?;
#[cfg(not(feature = "lua53"))]
f.call::<_, ()>(Nil)?;
Ok(())
}
#[test]
#[cfg(not(feature = "lua53"))]
fn context_thread_51() -> Result<()> {
let lua = Lua::new();
let thread = lua.create_thread(
lua.load(
r#"
function (thread)
assert(coroutine.running() == thread)
end
"#,
)
.eval()?,
)?;
thread.resume::<_, ()>(thread.clone())?;
Ok(())
}

View file

@ -1,12 +1,10 @@
use std::panic::catch_unwind;
use mlua::{Error, Function, Result, Thread, ThreadStatus};
include!("_lua.rs");
use mlua::{Error, Function, Lua, Result, Thread, ThreadStatus};
#[test]
fn test_thread() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
let thread = lua.create_thread(
lua.load(
@ -97,11 +95,18 @@ fn test_thread() -> Result<()> {
#[test]
fn coroutine_from_closure() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
let thrd_main = lua.create_function(|_, ()| Ok(()))?;
lua.globals().set("main", thrd_main)?;
#[cfg(feature = "lua53")]
let thrd: Thread = lua.load("coroutine.create(main)").eval()?;
#[cfg(not(feature = "lua53"))]
let thrd: Thread = lua
.load("coroutine.create(function(...) return main(unpack(arg)) end)")
.eval()?;
thrd.resume::<_, ()>(())?;
Ok(())
@ -111,7 +116,7 @@ fn coroutine_from_closure() -> Result<()> {
fn coroutine_panic() {
match catch_unwind(|| -> Result<()> {
// check that coroutines propagate panics correctly
let lua = make_lua();
let lua = Lua::new();
let thrd_main = lua.create_function(|_, ()| -> Result<()> {
panic!("test_panic");
})?;

View file

@ -1,12 +1,10 @@
use std::os::raw::c_void;
use mlua::{Function, LightUserData, Result};
include!("_lua.rs");
use mlua::{Function, LightUserData, Lua, Result};
#[test]
fn test_lightuserdata() -> Result<()> {
let lua = make_lua();
let lua = Lua::new();
let globals = lua.globals();
lua.load(

View file

@ -1,11 +1,10 @@
use std::sync::Arc;
use mlua::{
AnyUserData, ExternalError, Function, MetaMethod, Result, String, UserData, UserDataMethods,
AnyUserData, ExternalError, Function, Lua, MetaMethod, Result, String, UserData,
UserDataMethods,
};
include!("_lua.rs");
#[test]
fn test_user_data() -> Result<()> {
struct UserData1(i64);
@ -14,7 +13,7 @@ fn test_user_data() -> Result<()> {
impl UserData for UserData1 {};
impl UserData for UserData2 {};
let lua = make_lua();
let lua = Lua::new();
let userdata1 = lua.create_userdata(UserData1(1))?;
let userdata2 = lua.create_userdata(UserData2(Box::new(2)))?;
@ -43,7 +42,7 @@ fn test_methods() -> Result<()> {
}
}
let lua = make_lua();
let lua = Lua::new();
let globals = lua.globals();
let userdata = lua.create_userdata(MyUserData(42))?;
globals.set("userdata", userdata.clone())?;
@ -96,7 +95,7 @@ fn test_metamethods() -> Result<()> {
}
}
let lua = make_lua();
let lua = Lua::new();
let globals = lua.globals();
globals.set("userdata1", MyUserData(7))?;
globals.set("userdata2", MyUserData(3))?;
@ -127,7 +126,7 @@ fn test_gc_userdata() -> Result<()> {
}
}
let lua = make_lua();
let lua = Lua::new();
lua.globals().set("userdata", MyUserdata { id: 123 })?;
assert!(lua
@ -160,7 +159,7 @@ fn detroys_userdata() -> Result<()> {
let rc = Arc::new(());
let lua = make_lua();
let lua = Lua::new();
lua.globals().set("userdata", MyUserdata(rc.clone()))?;
assert_eq!(Arc::strong_count(&rc), 2);
@ -179,7 +178,7 @@ fn user_value() -> Result<()> {
struct MyUserData;
impl UserData for MyUserData {}
let lua = make_lua();
let lua = Lua::new();
let ud = lua.create_userdata(MyUserData)?;
ud.set_user_value("hello")?;
assert_eq!(ud.get_user_value::<String>()?, "hello");
@ -205,7 +204,7 @@ fn test_functions() -> Result<()> {
}
}
let lua = make_lua();
let lua = Lua::new();
let globals = lua.globals();
let userdata = lua.create_userdata(MyUserData(42))?;
globals.set("userdata", userdata.clone())?;