diff --git a/mlua-sys/Cargo.toml b/mlua-sys/Cargo.toml index 53a414a..99fce40 100644 --- a/mlua-sys/Cargo.toml +++ b/mlua-sys/Cargo.toml @@ -12,14 +12,15 @@ license = "MIT" links = "lua" build = "build/main.rs" description = """ -Low level (FFI) bindings to Lua 5.4/5.3/5.2/5.1 (including LuaJIT) and Luau +Low level (FFI) bindings to Lua 5.5/5.4/5.3/5.2/5.1 (including LuaJIT) and Luau """ [package.metadata.docs.rs] -features = ["lua54", "vendored"] +features = ["lua55", "vendored"] rustdoc-args = ["--cfg", "docsrs"] [features] +lua55 = [] lua54 = [] lua53 = [] lua52 = [] @@ -34,12 +35,13 @@ external = [] module = [] [dependencies] +libc = "0.2" [build-dependencies] cc = "1.0" cfg-if = "1.0" pkg-config = "0.3.17" -lua-src = { version = ">= 548.1.0, < 548.2.0", optional = true } +lua-src = { version = ">= 550.0.0, < 550.1.0", optional = true } luajit-src = { version = ">= 210.6.0, < 210.7.0", optional = true } luau0-src = { version = "0.17.0", optional = true } diff --git a/mlua-sys/README.md b/mlua-sys/README.md index 927ebbd..def6e91 100644 --- a/mlua-sys/README.md +++ b/mlua-sys/README.md @@ -1,8 +1,9 @@ # mlua-sys -Low level (FFI) bindings to Lua 5.4/5.3/5.2/5.1 (including LuaJIT) and [Luau]. +Low level (FFI) bindings to Lua 5.5/5.4/5.3/5.2/5.1 (including [LuaJIT]) and [Luau]. Intended to be consumed by the [mlua] crate. +[LuaJIT]: https://github.com/LuaJIT/LuaJIT [Luau]: https://github.com/luau-lang/luau [mlua]: https://crates.io/crates/mlua diff --git a/mlua-sys/build/find_normal.rs b/mlua-sys/build/find_normal.rs index dbbc18c..b91b1c0 100644 --- a/mlua-sys/build/find_normal.rs +++ b/mlua-sys/build/find_normal.rs @@ -31,18 +31,16 @@ pub fn probe_lua() { // Find using `pkg-config` + #[cfg(feature = "lua55")] + let (incl_bound, excl_bound, alt_probe, ver) = ("5.5", "5.6", ["lua5.5", "lua-5.5", "lua55"], "5.5"); #[cfg(feature = "lua54")] - let (incl_bound, excl_bound, alt_probe, ver) = - ("5.4", "5.5", ["lua5.4", "lua-5.4", "lua54"], "5.4"); + let (incl_bound, excl_bound, alt_probe, ver) = ("5.4", "5.5", ["lua5.4", "lua-5.4", "lua54"], "5.4"); #[cfg(feature = "lua53")] - let (incl_bound, excl_bound, alt_probe, ver) = - ("5.3", "5.4", ["lua5.3", "lua-5.3", "lua53"], "5.3"); + let (incl_bound, excl_bound, alt_probe, ver) = ("5.3", "5.4", ["lua5.3", "lua-5.3", "lua53"], "5.3"); #[cfg(feature = "lua52")] - let (incl_bound, excl_bound, alt_probe, ver) = - ("5.2", "5.3", ["lua5.2", "lua-5.2", "lua52"], "5.2"); + let (incl_bound, excl_bound, alt_probe, ver) = ("5.2", "5.3", ["lua5.2", "lua-5.2", "lua52"], "5.2"); #[cfg(feature = "lua51")] - let (incl_bound, excl_bound, alt_probe, ver) = - ("5.1", "5.2", ["lua5.1", "lua-5.1", "lua51"], "5.1"); + let (incl_bound, excl_bound, alt_probe, ver) = ("5.1", "5.2", ["lua5.1", "lua-5.1", "lua51"], "5.1"); #[cfg(feature = "luajit")] let (incl_bound, excl_bound, alt_probe, ver) = ("2.0.4", "2.2", [], "JIT"); @@ -54,9 +52,7 @@ pub fn probe_lua() { if lua.is_err() { for pkg in alt_probe { - lua = pkg_config::Config::new() - .cargo_metadata(true) - .probe(pkg); + lua = pkg_config::Config::new().cargo_metadata(true).probe(pkg); if lua.is_ok() { break; diff --git a/mlua-sys/build/find_vendored.rs b/mlua-sys/build/find_vendored.rs index e3ddbec..7810525 100644 --- a/mlua-sys/build/find_vendored.rs +++ b/mlua-sys/build/find_vendored.rs @@ -1,6 +1,9 @@ #![allow(dead_code)] pub fn probe_lua() { + #[cfg(feature = "lua55")] + let artifacts = lua_src::Build::new().build(lua_src::Lua55); + #[cfg(feature = "lua54")] let artifacts = lua_src::Build::new().build(lua_src::Lua54); diff --git a/mlua-sys/build/main.rs b/mlua-sys/build/main.rs index 53074f8..5bb8ddb 100644 --- a/mlua-sys/build/main.rs +++ b/mlua-sys/build/main.rs @@ -1,19 +1,21 @@ cfg_if::cfg_if! { - if #[cfg(all(feature = "lua54", not(any(feature = "lua53", feature = "lua52", feature = "lua51", feature = "luajit", feature = "luau"))))] { + if #[cfg(all(feature = "lua55", not(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "lua51", feature = "luajit", feature = "luau"))))] { include!("main_inner.rs"); - } else if #[cfg(all(feature = "lua53", not(any(feature = "lua54", feature = "lua52", feature = "lua51", feature = "luajit", feature = "luau"))))] { + } else if #[cfg(all(feature = "lua54", not(any(feature = "lua55", feature = "lua53", feature = "lua52", feature = "lua51", feature = "luajit", feature = "luau"))))] { include!("main_inner.rs"); - } else if #[cfg(all(feature = "lua52", not(any(feature = "lua54", feature = "lua53", feature = "lua51", feature = "luajit", feature = "luau"))))] { + } else if #[cfg(all(feature = "lua53", not(any(feature = "lua55", feature = "lua54", feature = "lua52", feature = "lua51", feature = "luajit", feature = "luau"))))] { include!("main_inner.rs"); - } else if #[cfg(all(feature = "lua51", not(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "luajit", feature = "luau"))))] { + } else if #[cfg(all(feature = "lua52", not(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua51", feature = "luajit", feature = "luau"))))] { include!("main_inner.rs"); - } else if #[cfg(all(feature = "luajit", not(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "lua51", feature = "luau"))))] { + } else if #[cfg(all(feature = "lua51", not(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua52", feature = "luajit", feature = "luau"))))] { include!("main_inner.rs"); - } else if #[cfg(all(feature = "luau", not(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "lua51", feature = "luajit"))))] { + } else if #[cfg(all(feature = "luajit", not(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua52", feature = "lua51", feature = "luau"))))] { + include!("main_inner.rs"); + } else if #[cfg(all(feature = "luau", not(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua52", feature = "lua51", feature = "luajit"))))] { include!("main_inner.rs"); } else { fn main() { - compile_error!("You can enable only one of the features: lua54, lua53, lua52, lua51, luajit, luajit52, luau"); + compile_error!("You can enable only one of the features: lua55, lua54, lua53, lua52, lua51, luajit, luajit52, luau"); } } } diff --git a/mlua-sys/src/lib.rs b/mlua-sys/src/lib.rs index 784b5d3..e6672c8 100644 --- a/mlua-sys/src/lib.rs +++ b/mlua-sys/src/lib.rs @@ -1,4 +1,4 @@ -//! Low level bindings to Lua 5.4/5.3/5.2/5.1 (including LuaJIT) and Luau. +//! Low level bindings to Lua 5.5/5.4/5.3/5.2/5.1 (including LuaJIT) and Luau. #![allow(non_camel_case_types, non_snake_case)] #![allow(clippy::missing_safety_doc)] @@ -8,6 +8,9 @@ use std::os::raw::c_int; +#[cfg(any(feature = "lua55", doc))] +pub use lua55::*; + #[cfg(any(feature = "lua54", doc))] pub use lua54::*; @@ -23,7 +26,7 @@ pub use lua51::*; #[cfg(any(feature = "luau", doc))] pub use luau::*; -#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] +#[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua52"))] #[doc(hidden)] pub const LUA_MAX_UPVALUES: c_int = 255; @@ -87,6 +90,10 @@ pub const SYS_MIN_ALIGN: usize = if cfg!(any( #[macro_use] mod macros; +#[cfg(any(feature = "lua55", doc))] +#[cfg_attr(docsrs, doc(cfg(feature = "lua55")))] +pub mod lua55; + #[cfg(any(feature = "lua54", doc))] #[cfg_attr(docsrs, doc(cfg(feature = "lua54")))] pub mod lua54; diff --git a/mlua-sys/src/lua55/lauxlib.rs b/mlua-sys/src/lua55/lauxlib.rs new file mode 100644 index 0000000..daf346a --- /dev/null +++ b/mlua-sys/src/lua55/lauxlib.rs @@ -0,0 +1,211 @@ +//! Contains definitions from `lauxlib.h`. + +use std::os::raw::{c_char, c_int, c_uint, c_void}; +use std::ptr; + +use super::lua::{self, lua_CFunction, lua_Integer, lua_Number, lua_State}; + +// Extra error code for 'luaL_loadfilex' +pub const LUA_ERRFILE: c_int = lua::LUA_ERRERR + 1; + +// Key, in the registry, for table of loaded modules +pub const LUA_LOADED_TABLE: *const c_char = cstr!("_LOADED"); + +// Key, in the registry, for table of preloaded loaders +pub const LUA_PRELOAD_TABLE: *const c_char = cstr!("_PRELOAD"); + +#[repr(C)] +pub struct luaL_Reg { + pub name: *const c_char, + pub func: lua_CFunction, +} + +#[cfg_attr(all(windows, raw_dylib), link(name = "lua55", kind = "raw-dylib"))] +unsafe extern "C-unwind" { + pub fn luaL_checkversion_(L: *mut lua_State, ver: lua_Number, sz: usize); + + pub fn luaL_getmetafield(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int; + pub fn luaL_callmeta(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int; + 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, extramsg: *const c_char) -> c_int; + pub fn luaL_checklstring(L: *mut lua_State, arg: c_int, l: *mut usize) -> *const c_char; + pub fn luaL_optlstring(L: *mut lua_State, arg: c_int, def: *const c_char, l: *mut usize) + -> *const c_char; + pub fn luaL_checknumber(L: *mut lua_State, arg: c_int) -> lua_Number; + pub fn luaL_optnumber(L: *mut lua_State, arg: c_int, def: lua_Number) -> lua_Number; + pub fn luaL_checkinteger(L: *mut lua_State, arg: c_int) -> lua_Integer; + pub fn luaL_optinteger(L: *mut lua_State, arg: c_int, def: lua_Integer) -> lua_Integer; + + pub fn luaL_checkstack(L: *mut lua_State, sz: c_int, msg: *const c_char); + 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); + + pub fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_int; + pub fn luaL_setmetatable(L: *mut lua_State, tname: *const c_char); + 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_checkoption( + L: *mut lua_State, + arg: c_int, + def: *const c_char, + lst: *const *const c_char, + ) -> c_int; + + pub fn luaL_fileresult(L: *mut lua_State, stat: c_int, fname: *const c_char) -> c_int; + pub fn luaL_execresult(L: *mut lua_State, stat: c_int) -> c_int; + pub fn luaL_alloc(L: *mut lua_State, ptr: *mut c_void, osize: usize, nsize: usize) -> *mut c_void; +} + +// Pre-defined references +pub const LUA_NOREF: c_int = -2; +pub const LUA_REFNIL: c_int = -1; + +#[cfg_attr(all(windows, raw_dylib), link(name = "lua55", kind = "raw-dylib"))] +unsafe extern "C-unwind" { + 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#ref: c_int); + + pub fn luaL_loadfilex(L: *mut lua_State, filename: *const c_char, mode: *const c_char) -> c_int; +} + +#[inline(always)] +pub unsafe fn luaL_loadfile(L: *mut lua_State, f: *const c_char) -> c_int { + luaL_loadfilex(L, f, ptr::null()) +} + +#[cfg_attr(all(windows, raw_dylib), link(name = "lua55", kind = "raw-dylib"))] +unsafe extern "C-unwind" { + pub fn luaL_loadbufferx( + L: *mut lua_State, + buff: *const c_char, + sz: usize, + name: *const c_char, + mode: *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; + + #[link_name = "luaL_makeseed"] + pub fn luaL_makeseed_(L: *mut lua_State) -> c_uint; + + pub fn luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer; + + // TODO: luaL_addgsub + + pub fn luaL_gsub( + L: *mut lua_State, + s: *const c_char, + p: *const c_char, + r: *const c_char, + ) -> *const c_char; + + pub fn luaL_setfuncs(L: *mut lua_State, l: *const luaL_Reg, nup: c_int); + + pub fn luaL_getsubtable(L: *mut lua_State, idx: c_int, fname: *const c_char) -> c_int; + + pub fn luaL_traceback(L: *mut lua_State, L1: *mut lua_State, msg: *const c_char, level: c_int); + + pub fn luaL_requiref(L: *mut lua_State, modname: *const c_char, openf: lua_CFunction, glb: c_int); +} + +// +// Some useful macros (implemented as Rust functions) +// + +// TODO: luaL_newlibtable, luaL_newlib + +#[inline(always)] +pub unsafe fn luaL_argcheck(L: *mut lua_State, cond: c_int, arg: c_int, extramsg: *const c_char) { + if cond == 0 { + luaL_argerror(L, arg, extramsg); + } +} + +#[inline(always)] +pub unsafe fn luaL_checkstring(L: *mut lua_State, n: c_int) -> *const c_char { + luaL_checklstring(L, n, ptr::null_mut()) +} + +#[inline(always)] +pub unsafe fn luaL_optstring(L: *mut lua_State, n: c_int, d: *const c_char) -> *const c_char { + luaL_optlstring(L, n, d, ptr::null_mut()) +} + +#[inline(always)] +pub unsafe fn luaL_typename(L: *mut lua_State, i: c_int) -> *const c_char { + lua::lua_typename(L, lua::lua_type(L, i)) +} + +#[inline(always)] +pub unsafe fn luaL_dofile(L: *mut lua_State, filename: *const c_char) -> c_int { + let status = luaL_loadfile(L, filename); + if status == 0 { + lua::lua_pcall(L, 0, lua::LUA_MULTRET, 0) + } else { + status + } +} + +#[inline(always)] +pub unsafe fn luaL_dostring(L: *mut lua_State, s: *const c_char) -> c_int { + let status = luaL_loadstring(L, s); + if status == 0 { + lua::lua_pcall(L, 0, lua::LUA_MULTRET, 0) + } else { + status + } +} + +#[inline(always)] +pub unsafe fn luaL_getmetatable(L: *mut lua_State, n: *const c_char) { + lua::lua_getfield(L, lua::LUA_REGISTRYINDEX, n); +} + +// luaL_opt would be implemented here but it is undocumented, so it's omitted + +#[inline(always)] +pub unsafe fn luaL_loadbuffer(L: *mut lua_State, s: *const c_char, sz: usize, n: *const c_char) -> c_int { + luaL_loadbufferx(L, s, sz, n, ptr::null()) +} + +pub unsafe fn luaL_loadbufferenv( + L: *mut lua_State, + data: *const c_char, + size: usize, + name: *const c_char, + mode: *const c_char, + mut env: c_int, +) -> c_int { + if env != 0 { + env = lua::lua_absindex(L, env); + } + let status = luaL_loadbufferx(L, data, size, name, mode); + if status == lua::LUA_OK && env != 0 { + lua::lua_pushvalue(L, env); + lua::lua_setupvalue(L, -2, 1); + } + status +} + +pub unsafe fn luaL_makeseed(L: *mut lua_State) -> c_uint { + #[cfg(macos)] + return libc::arc4random(); + #[cfg(linux)] + { + let mut seed = 0u32; + let buf = &mut seed as *mut _ as *mut c_void; + if libc::getrandom(buf, 4, libc::GRND_NONBLOCK) == 4 { + return seed; + } + } + luaL_makeseed_(L) +} + +// +// TODO: Generic Buffer Manipulation +// diff --git a/mlua-sys/src/lua55/lua.rs b/mlua-sys/src/lua55/lua.rs new file mode 100644 index 0000000..8f55152 --- /dev/null +++ b/mlua-sys/src/lua55/lua.rs @@ -0,0 +1,578 @@ +//! Contains definitions from `lua.h`. + +use std::ffi::CStr; +use std::marker::{PhantomData, PhantomPinned}; +use std::os::raw::{c_char, c_double, c_int, c_uchar, c_uint, c_void}; +use std::{mem, ptr}; + +// Mark for precompiled code (`Lua`) +pub const LUA_SIGNATURE: &[u8] = b"\x1bLua"; + +// Option for multiple returns in 'lua_pcall' and 'lua_call' +pub const LUA_MULTRET: c_int = -1; + +// Size of the Lua stack +#[doc(hidden)] +pub const LUAI_MAXSTACK: c_int = libc::INT_MAX; + +// Size of a raw memory area associated with a Lua state with very fast access. +pub const LUA_EXTRASPACE: usize = mem::size_of::<*const ()>(); + +// +// Pseudo-indices +// +pub const LUA_REGISTRYINDEX: c_int = -(libc::INT_MAX / 2 + 1000); + +pub const fn lua_upvalueindex(i: c_int) -> c_int { + LUA_REGISTRYINDEX - i +} + +// +// Thread status +// +pub const LUA_OK: c_int = 0; +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; +pub const LUA_ERRERR: c_int = 5; + +/// A raw Lua state associated with a thread. +#[repr(C)] +pub struct lua_State { + _data: [u8; 0], + _marker: PhantomData<(*mut u8, PhantomPinned)>, +} + +// +// Basic types +// +pub const LUA_TNONE: c_int = -1; + +pub const LUA_TNIL: c_int = 0; +pub const LUA_TBOOLEAN: c_int = 1; +pub const LUA_TLIGHTUSERDATA: c_int = 2; +pub const LUA_TNUMBER: c_int = 3; +pub const LUA_TSTRING: c_int = 4; +pub const LUA_TTABLE: c_int = 5; +pub const LUA_TFUNCTION: c_int = 6; +pub const LUA_TUSERDATA: c_int = 7; +pub const LUA_TTHREAD: c_int = 8; + +pub const LUA_NUMTYPES: c_int = 9; + +/// Minimum Lua stack available to a C function +pub const LUA_MINSTACK: c_int = 20; + +// Predefined values in the registry +// index 1 is reserved for the reference mechanism +pub const LUA_RIDX_GLOBALS: lua_Integer = 2; +pub const LUA_RIDX_MAINTHREAD: lua_Integer = 3; +pub const LUA_RIDX_LAST: lua_Integer = 3; + +/// A Lua number, usually equivalent to `f64` +pub type lua_Number = c_double; + +/// A Lua integer, usually equivalent to `i64` +pub type lua_Integer = i64; + +/// A Lua unsigned integer, usually equivalent to `u64` +pub type lua_Unsigned = u64; + +/// Type for continuation-function contexts +pub type lua_KContext = isize; + +/// Type for native C functions that can be passed to Lua +pub type lua_CFunction = unsafe extern "C-unwind" fn(L: *mut lua_State) -> c_int; + +/// Type for continuation functions +pub type lua_KFunction = + unsafe extern "C-unwind" fn(L: *mut lua_State, status: c_int, ctx: lua_KContext) -> c_int; + +// Type for functions that read/write blocks when loading/dumping Lua chunks +#[rustfmt::skip] +pub type lua_Reader = + unsafe extern "C-unwind" fn(L: *mut lua_State, ud: *mut c_void, sz: *mut usize) -> *const c_char; +#[rustfmt::skip] +pub type lua_Writer = + unsafe extern "C-unwind" fn(L: *mut lua_State, p: *const c_void, sz: usize, ud: *mut c_void) -> c_int; + +/// Type for memory-allocation functions (no unwinding) +#[rustfmt::skip] +pub type lua_Alloc = + unsafe extern "C" fn(ud: *mut c_void, ptr: *mut c_void, osize: usize, nsize: usize) -> *mut c_void; + +/// Type for warning functions +pub type lua_WarnFunction = unsafe extern "C-unwind" fn(ud: *mut c_void, msg: *const c_char, tocont: c_int); + +#[cfg_attr(all(windows, raw_dylib), link(name = "lua55", kind = "raw-dylib"))] +unsafe extern "C-unwind" { + // + // State manipulation + // + pub fn lua_newstate(f: lua_Alloc, ud: *mut c_void, seed: c_uint) -> *mut lua_State; + pub fn lua_close(L: *mut lua_State); + pub fn lua_newthread(L: *mut lua_State) -> *mut lua_State; + pub fn lua_closethread(L: *mut lua_State, from: *mut lua_State) -> c_int; + + pub fn lua_atpanic(L: *mut lua_State, panicf: lua_CFunction) -> lua_CFunction; + + pub fn lua_version(L: *mut lua_State) -> lua_Number; + + // + // Basic stack manipulation + // + 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); + pub fn lua_rotate(L: *mut lua_State, idx: c_int, n: c_int); + 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; + + pub fn lua_xmove(from: *mut lua_State, to: *mut lua_State, n: c_int); + + // + // Access functions (stack -> 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; + 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; + + pub fn lua_tonumberx(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Number; + pub fn lua_tointegerx(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Integer; + 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; + #[link_name = "lua_rawlen"] + fn lua_rawlen_(L: *mut lua_State, idx: c_int) -> lua_Unsigned; + pub fn lua_tocfunction(L: *mut lua_State, idx: c_int) -> Option; + pub fn lua_touserdata(L: *mut lua_State, idx: c_int) -> *mut c_void; + pub fn lua_tothread(L: *mut lua_State, idx: c_int) -> *mut lua_State; + pub fn lua_topointer(L: *mut lua_State, idx: c_int) -> *const c_void; +} + +// lua_rawlen's return type changed from size_t to lua_Unsigned int in Lua 5.4. +// This adapts the crate API to the new Lua ABI. +#[inline(always)] +pub unsafe fn lua_rawlen(L: *mut lua_State, idx: c_int) -> usize { + lua_rawlen_(L, idx) as usize +} + +// +// Comparison and arithmetic functions +// +pub const LUA_OPADD: c_int = 0; +pub const LUA_OPSUB: c_int = 1; +pub const LUA_OPMUL: c_int = 2; +pub const LUA_OPMOD: c_int = 3; +pub const LUA_OPPOW: c_int = 4; +pub const LUA_OPDIV: c_int = 5; +pub const LUA_OPIDIV: c_int = 6; +pub const LUA_OPBAND: c_int = 7; +pub const LUA_OPBOR: c_int = 8; +pub const LUA_OPBXOR: c_int = 9; +pub const LUA_OPSHL: c_int = 10; +pub const LUA_OPSHR: c_int = 11; +pub const LUA_OPUNM: c_int = 12; +pub const LUA_OPBNOT: c_int = 13; + +pub const LUA_OPEQ: c_int = 0; +pub const LUA_OPLT: c_int = 1; +pub const LUA_OPLE: c_int = 2; + +#[cfg_attr(all(windows, raw_dylib), link(name = "lua55", kind = "raw-dylib"))] +unsafe extern "C-unwind" { + pub fn lua_arith(L: *mut lua_State, op: c_int); + pub fn lua_rawequal(L: *mut lua_State, idx1: c_int, idx2: c_int) -> c_int; + pub fn lua_compare(L: *mut lua_State, idx1: c_int, idx2: c_int, op: c_int) -> c_int; +} + +#[cfg_attr(all(windows, raw_dylib), link(name = "lua55", kind = "raw-dylib"))] +unsafe extern "C-unwind" { + // + // Push functions (C -> stack) + // + 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); + pub fn lua_pushlstring(L: *mut lua_State, s: *const c_char, len: usize) -> *const c_char; + pub fn lua_pushexternalstring( + L: *mut lua_State, + s: *const c_char, + len: usize, + falloc: lua_Alloc, + ud: *mut c_void, + ) -> *const c_char; + pub fn lua_pushstring(L: *mut lua_State, s: *const c_char) -> *const c_char; + // lua_pushvfstring + pub fn lua_pushfstring(L: *mut lua_State, fmt: *const c_char, ...) -> *const c_char; + pub fn lua_pushcclosure(L: *mut lua_State, f: lua_CFunction, n: c_int); + pub fn lua_pushboolean(L: *mut lua_State, b: c_int); + pub fn lua_pushlightuserdata(L: *mut lua_State, p: *mut c_void); + pub fn lua_pushthread(L: *mut lua_State) -> c_int; + + // + // Get functions (Lua -> stack) + // + pub fn lua_getglobal(L: *mut lua_State, name: *const c_char) -> 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_geti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int; + pub fn lua_rawget(L: *mut lua_State, idx: c_int) -> c_int; + pub fn lua_rawgeti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int; + 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_newuserdatauv(L: *mut lua_State, sz: usize, nuvalue: c_int) -> *mut c_void; + pub fn lua_getmetatable(L: *mut lua_State, objindex: c_int) -> c_int; + pub fn lua_getiuservalue(L: *mut lua_State, idx: c_int, n: c_int) -> c_int; + + // + // Set functions (stack -> Lua) + // + pub fn lua_setglobal(L: *mut lua_State, name: *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); + 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); + 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; + pub fn lua_setiuservalue(L: *mut lua_State, idx: c_int, n: c_int) -> c_int; + + // + // 'load' and 'call' functions (load and run Lua code) + // + pub fn lua_callk( + L: *mut lua_State, + nargs: c_int, + nresults: c_int, + ctx: lua_KContext, + k: Option, + ); + pub fn lua_pcallk( + L: *mut lua_State, + nargs: c_int, + nresults: c_int, + errfunc: c_int, + ctx: lua_KContext, + k: Option, + ) -> c_int; + + pub fn lua_load( + L: *mut lua_State, + reader: lua_Reader, + data: *mut c_void, + chunkname: *const c_char, + mode: *const c_char, + ) -> c_int; + + pub fn lua_dump(L: *mut lua_State, writer: lua_Writer, data: *mut c_void, strip: c_int) -> c_int; +} + +#[inline(always)] +pub unsafe fn lua_call(L: *mut lua_State, n: c_int, r: c_int) { + lua_callk(L, n, r, 0, None) +} + +#[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) +} + +#[cfg_attr(all(windows, raw_dylib), link(name = "lua55", kind = "raw-dylib"))] +unsafe extern "C-unwind" { + // + // Coroutine functions + // + pub fn lua_yieldk( + L: *mut lua_State, + nresults: c_int, + ctx: lua_KContext, + k: Option, + ) -> c_int; + pub fn lua_resume(L: *mut lua_State, from: *mut lua_State, narg: c_int, nres: *mut c_int) -> c_int; + pub fn lua_status(L: *mut lua_State) -> c_int; + pub fn lua_isyieldable(L: *mut lua_State) -> c_int; +} + +#[inline(always)] +pub unsafe fn lua_yield(L: *mut lua_State, n: c_int) -> c_int { + lua_yieldk(L, n, 0, None) +} + +// +// Warning-related functions +// +#[cfg_attr(all(windows, raw_dylib), link(name = "lua55", kind = "raw-dylib"))] +unsafe extern "C-unwind" { + pub fn lua_setwarnf(L: *mut lua_State, f: Option, ud: *mut c_void); + pub fn lua_warning(L: *mut lua_State, msg: *const c_char, tocont: c_int); +} + +// +// Garbage-collection options +// +pub const LUA_GCSTOP: c_int = 0; +pub const LUA_GCRESTART: c_int = 1; +pub const LUA_GCCOLLECT: c_int = 2; +pub const LUA_GCCOUNT: c_int = 3; +pub const LUA_GCCOUNTB: c_int = 4; +pub const LUA_GCSTEP: c_int = 5; +pub const LUA_GCISRUNNING: c_int = 6; +pub const LUA_GCGEN: c_int = 7; +pub const LUA_GCINC: c_int = 8; +pub const LUA_GCPARAM: c_int = 9; + +// Parameters for GC generational mode +pub const LUA_GCPMINORMUL: c_int = 0; // control minor collections +pub const LUA_GCPMAJORMINOR: c_int = 1; // control shift major->minor +pub const LUA_GCPMINORMAJOR: c_int = 2; // control shift minor->major + +// Parameters for GC incremental mode +pub const LUA_GCPPAUSE: c_int = 3; // size of pause between successive GCs +pub const LUA_GCPSTEPMUL: c_int = 4; // GC "speed" +pub const LUA_GCPSTEPSIZE: c_int = 5; // GC granularity + +pub const LUA_GCPNUM: c_int = 6; // number of parameters + +#[cfg_attr(all(windows, raw_dylib), link(name = "lua55", kind = "raw-dylib"))] +unsafe extern "C-unwind" { + pub fn lua_gc(L: *mut lua_State, what: c_int, ...) -> c_int; +} + +#[cfg_attr(all(windows, raw_dylib), link(name = "lua55", kind = "raw-dylib"))] +unsafe extern "C-unwind" { + // + // Miscellaneous functions + // + #[link_name = "lua_error"] + fn lua_error_(L: *mut lua_State) -> c_int; + pub fn lua_next(L: *mut lua_State, idx: c_int) -> c_int; + pub fn lua_concat(L: *mut lua_State, n: c_int); + pub fn lua_len(L: *mut lua_State, idx: c_int); + pub fn lua_numbertocstring(L: *mut lua_State, idx: c_int, buff: *mut c_char) -> c_uint; + 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); + + pub fn lua_toclose(L: *mut lua_State, idx: c_int); + pub fn lua_closeslot(L: *mut lua_State, idx: c_int); +} + +// lua_error does not return but is declared to return int, and Rust translates +// ! to void which can cause link-time errors if the platform linker is aware +// of return types and requires they match (for example: wasm does this). +#[inline(always)] +pub unsafe fn lua_error(L: *mut lua_State) -> ! { + lua_error_(L); + unreachable!(); +} + +// +// Some useful macros (implemented as Rust functions) +// +#[inline(always)] +pub unsafe fn lua_getextraspace(L: *mut lua_State) -> *mut c_void { + (L as *mut c_char).sub(LUA_EXTRASPACE) as *mut c_void +} + +#[inline(always)] +pub unsafe fn lua_tonumber(L: *mut lua_State, i: c_int) -> lua_Number { + lua_tonumberx(L, i, ptr::null_mut()) +} + +#[inline(always)] +pub unsafe fn lua_tointeger(L: *mut lua_State, i: c_int) -> lua_Integer { + lua_tointegerx(L, i, ptr::null_mut()) +} + +#[inline(always)] +pub unsafe fn lua_pop(L: *mut lua_State, n: c_int) { + lua_settop(L, -n - 1) +} + +#[inline(always)] +pub unsafe fn lua_newtable(L: *mut lua_State) { + lua_createtable(L, 0, 0) +} + +#[inline(always)] +pub unsafe fn lua_register(L: *mut lua_State, n: *const c_char, f: lua_CFunction) { + lua_pushcfunction(L, f); + lua_setglobal(L, n) +} + +#[inline(always)] +pub unsafe fn lua_pushcfunction(L: *mut lua_State, f: lua_CFunction) { + lua_pushcclosure(L, f, 0) +} + +#[inline(always)] +pub unsafe fn lua_isfunction(L: *mut lua_State, n: c_int) -> c_int { + (lua_type(L, n) == LUA_TFUNCTION) as c_int +} + +#[inline(always)] +pub unsafe fn lua_istable(L: *mut lua_State, n: c_int) -> c_int { + (lua_type(L, n) == LUA_TTABLE) as c_int +} + +#[inline(always)] +pub unsafe fn lua_islightuserdata(L: *mut lua_State, n: c_int) -> c_int { + (lua_type(L, n) == LUA_TLIGHTUSERDATA) as c_int +} + +#[inline(always)] +pub unsafe fn lua_isnil(L: *mut lua_State, n: c_int) -> c_int { + (lua_type(L, n) == LUA_TNIL) as c_int +} + +#[inline(always)] +pub unsafe fn lua_isboolean(L: *mut lua_State, n: c_int) -> c_int { + (lua_type(L, n) == LUA_TBOOLEAN) as c_int +} + +#[inline(always)] +pub unsafe fn lua_isthread(L: *mut lua_State, n: c_int) -> c_int { + (lua_type(L, n) == LUA_TTHREAD) as c_int +} + +#[inline(always)] +pub unsafe fn lua_isnone(L: *mut lua_State, n: c_int) -> c_int { + (lua_type(L, n) == LUA_TNONE) as c_int +} + +#[inline(always)] +pub unsafe fn lua_isnoneornil(L: *mut lua_State, n: c_int) -> c_int { + (lua_type(L, n) <= 0) as c_int +} + +#[inline(always)] +pub unsafe fn lua_pushliteral(L: *mut lua_State, s: &'static CStr) { + lua_pushstring(L, s.as_ptr()); +} + +#[inline(always)] +pub unsafe fn lua_pushglobaltable(L: *mut lua_State) -> c_int { + lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS) +} + +#[inline(always)] +pub unsafe fn lua_tolightuserdata(L: *mut lua_State, idx: c_int) -> *mut c_void { + if lua_islightuserdata(L, idx) != 0 { + return lua_touserdata(L, idx); + } + ptr::null_mut() +} + +#[inline(always)] +pub unsafe fn lua_tostring(L: *mut lua_State, i: c_int) -> *const c_char { + lua_tolstring(L, i, ptr::null_mut()) +} + +#[inline(always)] +pub unsafe fn lua_insert(L: *mut lua_State, idx: c_int) { + lua_rotate(L, idx, 1) +} + +#[inline(always)] +pub unsafe fn lua_remove(L: *mut lua_State, idx: c_int) { + lua_rotate(L, idx, -1); + lua_pop(L, 1) +} + +#[inline(always)] +pub unsafe fn lua_replace(L: *mut lua_State, idx: c_int) { + lua_copy(L, -1, idx); + lua_pop(L, 1) +} + +#[inline(always)] +pub unsafe fn lua_xpush(from: *mut lua_State, to: *mut lua_State, idx: c_int) { + lua_pushvalue(from, idx); + lua_xmove(from, to, 1); +} + +#[inline(always)] +pub unsafe fn lua_newuserdata(L: *mut lua_State, sz: usize) -> *mut c_void { + lua_newuserdatauv(L, sz, 1) +} + +#[inline(always)] +pub unsafe fn lua_getuservalue(L: *mut lua_State, idx: c_int) -> c_int { + lua_getiuservalue(L, idx, 1) +} + +#[inline(always)] +pub unsafe fn lua_setuservalue(L: *mut lua_State, idx: c_int) -> c_int { + lua_setiuservalue(L, idx, 1) +} + +// +// Debug API +// + +// Maximum size for the description of the source of a function in debug information. +const LUA_IDSIZE: usize = 60; + +// Event codes +pub const LUA_HOOKCALL: c_int = 0; +pub const LUA_HOOKRET: c_int = 1; +pub const LUA_HOOKLINE: c_int = 2; +pub const LUA_HOOKCOUNT: c_int = 3; +pub const LUA_HOOKTAILCALL: c_int = 4; + +// Event masks +pub const LUA_MASKCALL: c_int = 1 << (LUA_HOOKCALL as usize); +pub const LUA_MASKRET: c_int = 1 << (LUA_HOOKRET as usize); +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 = unsafe extern "C-unwind" fn(L: *mut lua_State, ar: *mut lua_Debug); + +#[cfg_attr(all(windows, raw_dylib), link(name = "lua55", kind = "raw-dylib"))] +unsafe extern "C-unwind" { + pub fn lua_getstack(L: *mut lua_State, level: c_int, ar: *mut lua_Debug) -> c_int; + pub fn lua_getinfo(L: *mut lua_State, what: *const c_char, ar: *mut lua_Debug) -> c_int; + pub fn lua_getlocal(L: *mut lua_State, ar: *const lua_Debug, n: c_int) -> *const c_char; + pub fn lua_setlocal(L: *mut lua_State, ar: *const lua_Debug, n: c_int) -> *const c_char; + 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; + + pub fn lua_upvalueid(L: *mut lua_State, fidx: c_int, n: c_int) -> *mut c_void; + 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: Option, mask: c_int, count: c_int); + pub fn lua_gethook(L: *mut lua_State) -> Option; + pub fn lua_gethookmask(L: *mut lua_State) -> c_int; + pub fn lua_gethookcount(L: *mut lua_State) -> c_int; +} + +#[repr(C)] +pub struct lua_Debug { + pub event: c_int, + pub name: *const c_char, // (n) + pub namewhat: *const c_char, // (n) 'global', 'local', 'field', 'method' + pub what: *const c_char, // (S) 'Lua', 'C', 'main', 'tail' + pub source: *const c_char, // (S) + pub srclen: usize, // (S) + pub currentline: c_int, // (l) + pub linedefined: c_int, // (S) + pub lastlinedefined: c_int, // (S) + pub nups: c_uchar, // (u) number of upvalues + pub nparams: c_uchar, // (u) number of parameters + pub isvararg: c_char, // (u) + pub extraargs: c_uchar, // (t) number of extra arguments + pub istailcall: c_char, // (t) + pub ftransfer: c_int, // (r) index of first value transferred + pub ntransfer: c_int, // (r) number of transferred values + pub short_src: [c_char; LUA_IDSIZE], // (S) + // lua.h mentions this is for private use + i_ci: *mut c_void, +} diff --git a/mlua-sys/src/lua55/lualib.rs b/mlua-sys/src/lua55/lualib.rs new file mode 100644 index 0000000..33903ad --- /dev/null +++ b/mlua-sys/src/lua55/lualib.rs @@ -0,0 +1,55 @@ +//! Contains definitions from `lualib.h`. + +use std::os::raw::{c_char, c_int}; + +use super::lua::lua_State; + +pub const LUA_GLIBK: c_int = 1; + +pub const LUA_LOADLIBNAME: *const c_char = cstr!("package"); +pub const LUA_LOADLIBK: c_int = LUA_GLIBK << 1; + +pub const LUA_COLIBNAME: *const c_char = cstr!("coroutine"); +pub const LUA_COLIBK: c_int = LUA_GLIBK << 2; + +pub const LUA_DBLIBNAME: *const c_char = cstr!("debug"); +pub const LUA_DBLIBK: c_int = LUA_GLIBK << 3; + +pub const LUA_IOLIBNAME: *const c_char = cstr!("io"); +pub const LUA_IOLIBK: c_int = LUA_GLIBK << 4; + +pub const LUA_MATHLIBNAME: *const c_char = cstr!("math"); +pub const LUA_MATHLIBK: c_int = LUA_GLIBK << 5; + +pub const LUA_OSLIBNAME: *const c_char = cstr!("os"); +pub const LUA_OSLIBK: c_int = LUA_GLIBK << 6; + +pub const LUA_STRLIBNAME: *const c_char = cstr!("string"); +pub const LUA_STRLIBK: c_int = LUA_GLIBK << 7; + +pub const LUA_TABLIBNAME: *const c_char = cstr!("table"); +pub const LUA_TABLIBK: c_int = LUA_GLIBK << 8; + +pub const LUA_UTF8LIBNAME: *const c_char = cstr!("utf8"); +pub const LUA_UTF8LIBK: c_int = LUA_GLIBK << 9; + +#[cfg_attr(all(windows, raw_dylib), link(name = "lua55", kind = "raw-dylib"))] +unsafe extern "C-unwind" { + pub fn luaopen_base(L: *mut lua_State) -> c_int; + pub fn luaopen_package(L: *mut lua_State) -> c_int; + pub fn luaopen_coroutine(L: *mut lua_State) -> c_int; + pub fn luaopen_debug(L: *mut lua_State) -> c_int; + pub fn luaopen_io(L: *mut lua_State) -> c_int; + pub fn luaopen_math(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; + pub fn luaopen_table(L: *mut lua_State) -> c_int; + pub fn luaopen_utf8(L: *mut lua_State) -> c_int; + + // open all builtin libraries + pub fn luaL_openselectedlibs(L: *mut lua_State, load: c_int, preload: c_int); +} + +pub unsafe fn luaL_openlibs(L: *mut lua_State) { + luaL_openselectedlibs(L, !0, 0); +} diff --git a/mlua-sys/src/lua55/mod.rs b/mlua-sys/src/lua55/mod.rs new file mode 100644 index 0000000..8b653a4 --- /dev/null +++ b/mlua-sys/src/lua55/mod.rs @@ -0,0 +1,9 @@ +//! Low level bindings to Lua 5.5. + +pub use lauxlib::*; +pub use lua::*; +pub use lualib::*; + +pub mod lauxlib; +pub mod lua; +pub mod lualib;