From 6dc127f4eb500398ffd81edcb24d45353b0ff4cf Mon Sep 17 00:00:00 2001 From: Alex Orlenko Date: Mon, 14 Feb 2022 18:41:18 +0000 Subject: [PATCH] Refactor ffi module Initial Luau support work --- Cargo.toml | 2 + build/find_vendored.rs | 2 + build/main.rs | 226 ++--------- src/ffi/compat53.rs | 233 +++++------ src/ffi/glue/glue.c | 289 ------------- src/ffi/lauxlib.rs | 313 +------------- src/ffi/lua.rs | 855 +++------------------------------------ src/ffi/lua51/lauxlib.rs | 145 +++++++ src/ffi/lua51/lua.rs | 380 +++++++++++++++++ src/ffi/lua51/lualib.rs | 42 ++ src/ffi/lua51/mod.rs | 9 + src/ffi/lua52/lauxlib.rs | 184 +++++++++ src/ffi/lua52/lua.rs | 467 +++++++++++++++++++++ src/ffi/lua52/lualib.rs | 31 ++ src/ffi/lua52/mod.rs | 9 + src/ffi/lua53/lauxlib.rs | 184 +++++++++ src/ffi/lua53/lua.rs | 494 ++++++++++++++++++++++ src/ffi/lua53/lualib.rs | 33 ++ src/ffi/lua53/mod.rs | 9 + src/ffi/lua54/lauxlib.rs | 186 +++++++++ src/ffi/lua54/lua.rs | 533 ++++++++++++++++++++++++ src/ffi/lua54/lualib.rs | 31 ++ src/ffi/lua54/mod.rs | 9 + src/ffi/luaconf.rs | 36 -- src/ffi/lualib.rs | 70 +--- src/ffi/luau/lua.rs | 421 +++++++++++++++++++ src/ffi/luau/lualib.rs | 113 ++++++ src/ffi/luau/mod.rs | 7 + src/ffi/mod.rs | 302 ++------------ src/lua.rs | 2 +- src/serde/de.rs | 5 +- src/thread.rs | 2 +- src/value.rs | 6 +- tests/async.rs | 6 +- 34 files changed, 3549 insertions(+), 2087 deletions(-) delete mode 100644 src/ffi/glue/glue.c create mode 100644 src/ffi/lua51/lauxlib.rs create mode 100644 src/ffi/lua51/lua.rs create mode 100644 src/ffi/lua51/lualib.rs create mode 100644 src/ffi/lua51/mod.rs create mode 100644 src/ffi/lua52/lauxlib.rs create mode 100644 src/ffi/lua52/lua.rs create mode 100644 src/ffi/lua52/lualib.rs create mode 100644 src/ffi/lua52/mod.rs create mode 100644 src/ffi/lua53/lauxlib.rs create mode 100644 src/ffi/lua53/lua.rs create mode 100644 src/ffi/lua53/lualib.rs create mode 100644 src/ffi/lua53/mod.rs create mode 100644 src/ffi/lua54/lauxlib.rs create mode 100644 src/ffi/lua54/lua.rs create mode 100644 src/ffi/lua54/lualib.rs create mode 100644 src/ffi/lua54/mod.rs delete mode 100644 src/ffi/luaconf.rs create mode 100644 src/ffi/luau/lua.rs create mode 100644 src/ffi/luau/lualib.rs create mode 100644 src/ffi/luau/mod.rs diff --git a/Cargo.toml b/Cargo.toml index b4ff1ec..076188c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ lua52 = [] lua51 = [] luajit = [] luajit52 = ["luajit"] +luau = ["luau-src"] vendored = ["lua-src", "luajit-src"] module = ["mlua_derive"] async = ["futures-core", "futures-task", "futures-util"] @@ -58,6 +59,7 @@ cc = { version = "1.0" } pkg-config = { version = "0.3.17" } lua-src = { version = ">= 540.0.0, < 550.0.0", optional = true } luajit-src = { version = ">= 210.3.1, < 220.0.0", optional = true } +luau-src = { version = "1", optional = true } [dev-dependencies] rustyline = "9.0" diff --git a/build/find_vendored.rs b/build/find_vendored.rs index 3b8902f..4d0d442 100644 --- a/build/find_vendored.rs +++ b/build/find_vendored.rs @@ -17,6 +17,8 @@ pub fn probe_lua() -> Option { } builder.build() }; + #[cfg(feature = "luau")] + let artifacts = luau_src::Build::new().build(); #[cfg(not(feature = "module"))] artifacts.print_cargo_metadata(); diff --git a/build/main.rs b/build/main.rs index f637a80..bdbe664 100644 --- a/build/main.rs +++ b/build/main.rs @@ -1,20 +1,15 @@ -#![allow(unreachable_code)] - -use std::env; -use std::fs::File; -use std::io::{Error, ErrorKind, Result, Write}; -use std::path::{Path, PathBuf}; -use std::process::Command; - #[cfg_attr( - all( - feature = "vendored", - any( - feature = "lua54", - feature = "lua53", - feature = "lua52", - feature = "lua51", - feature = "luajit" + any( + feature = "luau", + all( + feature = "vendored", + any( + feature = "lua54", + feature = "lua53", + feature = "lua52", + feature = "lua51", + feature = "luajit" + ) ) ), path = "find_vendored.rs" @@ -38,174 +33,24 @@ use std::process::Command; feature = "lua53", feature = "lua52", feature = "lua51", - feature = "luajit" + feature = "luajit", + feature = "luau" )), path = "find_dummy.rs" )] mod find; -trait CommandExt { - fn execute(&mut self) -> Result<()>; -} - -impl CommandExt for Command { - /// Execute the command and return an error if it exited with a failure status. - fn execute(&mut self) -> Result<()> { - self.status() - .and_then(|status| { - if status.success() { - Ok(()) - } else { - Err(Error::new(ErrorKind::Other, "non-zero exit code")) - } - }) - .map_err(|_| { - Error::new( - ErrorKind::Other, - format!("The command {:?} did not run successfully.", self), - ) - }) - } -} - -// `include_path` is optional as Lua headers can be also found in compiler standard paths -fn build_glue(include_path: Option>) { - let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); - - let mut config = cc::Build::new(); - if let Some(include_path) = include_path { - config.include(include_path.as_ref()); - } - - // Compile and run glue.c - let glue = build_dir.join("glue"); - - config - .get_compiler() - .to_command() - .arg("src/ffi/glue/glue.c") - .arg("-o") - .arg(&glue) - .execute() - .unwrap(); - - Command::new(glue) - .arg(build_dir.join("glue.rs")) - .execute() - .unwrap(); -} - -// When cross-compiling, we cannot use `build_glue` as we cannot run the generated -// executable. Instead, let's take a stab at synthesizing the likely values. -// If you're cross-compiling and using a non-vendored library then there is a chance -// that the values selected here may be incorrect, but we have no way to determine -// that here. -fn generate_glue() -> Result<()> { - let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); - let mut glue = File::create(build_dir.join("glue.rs"))?; - writeln!( - glue, - "/* This file was generated by build/main.rs; do not modify by hand */" - )?; - writeln!(glue, "use std::os::raw::*;")?; - - writeln!(glue, "/* luaconf.h */")?; - let pointer_bit_width: usize = env::var("CARGO_CFG_TARGET_POINTER_WIDTH") - .unwrap() - .parse() - .unwrap(); - writeln!( - glue, - "pub const LUA_EXTRASPACE: c_int = {} / 8;", - pointer_bit_width - )?; - - // This is generally hardcoded to this size - writeln!(glue, "pub const LUA_IDSIZE: c_int = 60;")?; - - // Unless the target is restricted, the defaults are 64 bit - writeln!(glue, "pub type LUA_NUMBER = c_double;")?; - writeln!(glue, "pub type LUA_INTEGER = i64;")?; - writeln!(glue, "pub type LUA_UNSIGNED = u64;")?; - - writeln!(glue, "/* lua.h */")?; - let version = if cfg!(any(feature = "luajit", feature = "lua51")) { - (5, 1, 0) - } else if cfg!(feature = "lua52") { - (5, 2, 0) - } else if cfg!(feature = "lua53") { - (5, 3, 0) - } else if cfg!(feature = "lua54") { - (5, 4, 0) - } else { - unreachable!(); - }; - writeln!( - glue, - "pub const LUA_VERSION_NUM: c_int = {};", - (version.0 * 100) + version.1 - )?; - - #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] - writeln!( - glue, - "pub const LUA_REGISTRYINDEX: c_int = -{} - 1000;", - if pointer_bit_width >= 32 { - 1_000_000 - } else { - 15_000 - } - )?; - #[cfg(any(feature = "lua51", feature = "luajit"))] - writeln!(glue, "pub const LUA_REGISTRYINDEX: c_int = -10000;")?; - - // These two are only defined in lua 5.1 - writeln!(glue, "pub const LUA_ENVIRONINDEX: c_int = -10001;")?; - writeln!(glue, "pub const LUA_GLOBALSINDEX: c_int = -10002;")?; - - writeln!(glue, "/* lauxlib.h */")?; - // This is only defined in lua 5.3 and up, but we can always generate its value here, - // even if we don't use it. - // This matches the default definition in lauxlib.h - writeln!(glue, "pub const LUAL_NUMSIZES: c_int = std::mem::size_of::() as c_int * 16 + std::mem::size_of::() as c_int;")?; - - writeln!(glue, "/* lualib.h */")?; - write!( - glue, - r#" -#[cfg(feature = "luajit")] -pub const LUA_BITLIBNAME: &str = "bit"; -#[cfg(not(feature = "luajit"))] -pub const LUA_BITLIBNAME: &str = "bit32"; - -pub const LUA_COLIBNAME: &str = "coroutine"; -pub const LUA_DBLIBNAME: &str = "debug"; -pub const LUA_IOLIBNAME: &str = "io"; -pub const LUA_LOADLIBNAME: &str = "package"; -pub const LUA_MATHLIBNAME: &str = "math"; -pub const LUA_OSLIBNAME: &str = "os"; -pub const LUA_STRLIBNAME: &str = "string"; -pub const LUA_TABLIBNAME: &str = "table"; -pub const LUA_UTF8LIBNAME: &str = "utf8"; - -pub const LUA_JITLIBNAME: &str = "jit"; -pub const LUA_FFILIBNAME: &str = "ffi"; -"# - )?; - - Ok(()) -} - fn main() { #[cfg(not(any( feature = "lua54", feature = "lua53", feature = "lua52", feature = "lua51", - feature = "luajit" + feature = "luajit", + feature = "luau" )))] compile_error!( - "You must enable one of the features: lua54, lua53, lua52, lua51, luajit, luajit52" + "You must enable one of the features: lua54, lua53, lua52, lua51, luajit, luajit52, luau" ); #[cfg(all( @@ -214,29 +59,43 @@ fn main() { feature = "lua53", feature = "lua52", feature = "lua51", - feature = "luajit" + feature = "luajit", + feature = "luau" ) ))] compile_error!( - "You can enable only one of the features: lua54, lua53, lua52, lua51, luajit, luajit52" + "You can enable only one of the features: lua54, lua53, lua52, lua51, luajit, luajit52, luau" ); #[cfg(all( feature = "lua53", - any(feature = "lua52", feature = "lua51", feature = "luajit") + any( + feature = "lua52", + feature = "lua51", + feature = "luajit", + feature = "luau" + ) ))] compile_error!( - "You can enable only one of the features: lua54, lua53, lua52, lua51, luajit, luajit52" + "You can enable only one of the features: lua54, lua53, lua52, lua51, luajit, luajit52, luau" ); - #[cfg(all(feature = "lua52", any(feature = "lua51", feature = "luajit")))] + #[cfg(all( + feature = "lua52", + any(feature = "lua51", feature = "luajit", feature = "luau") + ))] compile_error!( - "You can enable only one of the features: lua54, lua53, lua52, lua51, luajit, luajit52" + "You can enable only one of the features: lua54, lua53, lua52, lua51, luajit, luajit52, luau" ); - #[cfg(all(feature = "lua51", feature = "luajit"))] + #[cfg(all(feature = "lua51", any(feature = "luajit", feature = "luau")))] compile_error!( - "You can enable only one of the features: lua54, lua53, lua52, lua51, luajit, luajit52" + "You can enable only one of the features: lua54, lua53, lua52, lua51, luajit, luajit52, luau" + ); + + #[cfg(all(feature = "luajit", feature = "luau"))] + compile_error!( + "You can enable only one of the features: lua54, lua53, lua52, lua51, luajit, luajit52, luau" ); // We don't support "vendored module" mode on windows @@ -246,14 +105,7 @@ fn main() { + "Please, use `pkg-config` or custom mode to link to a Lua dll." ); - let include_dir = find::probe_lua(); - if env::var("TARGET").unwrap() != env::var("HOST").unwrap() { - // The `probe_lua` call above is still needed here - generate_glue().unwrap(); - } else { - build_glue(include_dir); - println!("cargo:rerun-if-changed=src/ffi/glue/glue.c"); - } + find::probe_lua(); println!("cargo:rerun-if-changed=build"); } diff --git a/src/ffi/compat53.rs b/src/ffi/compat53.rs index f4a2a01..f213e16 100644 --- a/src/ffi/compat53.rs +++ b/src/ffi/compat53.rs @@ -1,68 +1,21 @@ -// The MIT License (MIT) -// -// Copyright (c) 2019-2021 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 +//! Lua 5.3 compatibility layer for Lua 5.1/5.2 +//! +//! Based on github.com/keplerproject/lua-compat-5.3 #![allow(clippy::needless_return)] +use std::convert::TryInto; use std::ffi::CStr; use std::mem; use std::os::raw::{c_char, c_int, c_void}; use std::ptr; - -use super::lauxlib::{ - luaL_callmeta, luaL_error, luaL_getmetafield_old, luaL_loadbuffer, luaL_newmetatable_old, -}; - -#[cfg(any(feature = "lua51", feature = "luajit"))] -use super::lauxlib::{luaL_Reg, luaL_checktype, luaL_getmetatable}; +use std::str::FromStr; #[cfg(feature = "lua52")] -use super::lauxlib::{luaL_checkstack, luaL_getsubtable}; - -use super::lua::{ - self, lua_CFunction, lua_Debug, lua_Integer, lua_Number, lua_State, lua_Writer, lua_call, - lua_createtable, lua_dump_old, lua_error, lua_getfield_old, lua_getstack, lua_gettable_old, - lua_gettop, lua_insert, lua_isstring, lua_istable, lua_newuserdata, lua_pop, lua_pushboolean, - lua_pushcfunction, lua_pushfstring, lua_pushinteger, lua_pushliteral, lua_pushlstring_old, - lua_pushnil, lua_pushnumber, lua_pushthread, lua_pushvalue, lua_rawget_old, lua_rawgeti_old, - lua_rawset, lua_replace, lua_setfield, lua_setglobal, lua_setmetatable, lua_settable, - lua_toboolean, lua_tointeger, lua_tolstring, lua_tonumber, lua_topointer, lua_tostring, - lua_touserdata, lua_type, lua_typename, -}; +use super::lua52::*; #[cfg(any(feature = "lua51", feature = "luajit"))] -use super::lua::{ - lua_checkstack, lua_concat, lua_equal, lua_getfenv, lua_getinfo, lua_getmetatable, - lua_isnumber, lua_lessthan, lua_newtable, lua_next, lua_objlen, lua_pushcclosure, - lua_pushlightuserdata, lua_pushstring_old, lua_rawequal, lua_remove, lua_resume_old, - lua_setfenv, lua_settop, LUA_OPADD, LUA_OPUNM, -}; - -#[cfg(feature = "lua52")] -use super::lua::{ - lua_absindex, lua_getglobal_old, lua_getuservalue_old, lua_pushstring, lua_rawgetp_old, - lua_rawsetp, lua_tonumberx, -}; +use super::lua51::*; unsafe fn compat53_reverse(L: *mut lua_State, mut a: c_int, mut b: c_int) { while a < b { @@ -90,7 +43,7 @@ unsafe fn compat53_countlevels(L: *mut lua_State) -> c_int { while li < le { let m = (li + le) / 2; if lua_getstack(L, m, &mut ar) != 0 { - li = m + 1 + li = m + 1; } else { le = m; } @@ -125,7 +78,7 @@ unsafe fn compat53_checkmode( ); return err; } - lua::LUA_OK + LUA_OK } #[cfg(any(feature = "lua51", feature = "luajit"))] @@ -137,7 +90,7 @@ unsafe fn compat53_findfield(L: *mut lua_State, objidx: c_int, level: c_int) -> 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 { + if lua_type(L, -2) == LUA_TSTRING { // ignore non-string keys if lua_rawequal(L, objidx, -1) != 0 { // found object? @@ -161,7 +114,7 @@ unsafe fn compat53_findfield(L: *mut lua_State, objidx: c_int, level: c_int) -> 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); + lua_pushvalue(L, LUA_GLOBALSINDEX); if compat53_findfield(L, top + 1, 2) != 0 { lua_copy(L, -1, top + 1); // move name to proper place lua_pop(L, 2); // remove pushed values @@ -198,8 +151,8 @@ unsafe fn compat53_pushfuncname(L: *mut lua_State, ar: *mut lua_Debug) { } unsafe fn compat53_call_lua(L: *mut lua_State, code: &str, nargs: c_int, nret: c_int) { - lua_rawgetp(L, lua::LUA_REGISTRYINDEX, code.as_ptr() as *const c_void); - if lua_type(L, -1) != lua::LUA_TFUNCTION { + lua_rawgetp(L, LUA_REGISTRYINDEX, code.as_ptr() as *const c_void); + if lua_type(L, -1) != LUA_TFUNCTION { lua_pop(L, 1); if luaL_loadbuffer( L, @@ -211,7 +164,7 @@ unsafe fn compat53_call_lua(L: *mut lua_State, code: &str, nargs: c_int, nret: c lua_error(L); } lua_pushvalue(L, -1); - lua_rawsetp(L, lua::LUA_REGISTRYINDEX, code.as_ptr() as *const c_void); + lua_rawsetp(L, LUA_REGISTRYINDEX, code.as_ptr() as *const c_void); } lua_insert(L, -nargs - 1); lua_call(L, nargs, nret); @@ -221,24 +174,34 @@ unsafe fn compat53_call_lua(L: *mut lua_State, code: &str, nargs: c_int, nret: c // lua ported functions // -#[cfg(any(feature = "lua51", feature = "luajit"))] -#[inline(always)] -pub fn lua_upvalueindex(i: c_int) -> c_int { - lua::LUA_GLOBALSINDEX - i -} - #[cfg(any(feature = "lua51", feature = "luajit"))] #[inline(always)] pub unsafe fn lua_absindex(L: *mut lua_State, mut idx: c_int) -> c_int { - if idx < 0 && idx > lua::LUA_REGISTRYINDEX { + if idx < 0 && idx > LUA_REGISTRYINDEX { idx += lua_gettop(L) + 1; } idx } +// Comparison and arithmetic functions +#[cfg(any(feature = "lua51", feature = "luajit"))] +pub const LUA_OPADD: c_int = 0; +#[cfg(any(feature = "lua51", feature = "luajit"))] +pub const LUA_OPSUB: c_int = 1; +#[cfg(any(feature = "lua51", feature = "luajit"))] +pub const LUA_OPMUL: c_int = 2; +#[cfg(any(feature = "lua51", feature = "luajit"))] +pub const LUA_OPDIV: c_int = 3; +#[cfg(any(feature = "lua51", feature = "luajit"))] +pub const LUA_OPMOD: c_int = 4; +#[cfg(any(feature = "lua51", feature = "luajit"))] +pub const LUA_OPPOW: c_int = 5; +#[cfg(any(feature = "lua51", feature = "luajit"))] +pub const LUA_OPUNM: c_int = 6; + #[cfg(any(feature = "lua51", feature = "luajit"))] static COMPAT53_ARITH_CODE: &str = r#" -local op,a,b=... +local op,a,b = ... if op == 0 then return a+b elseif op == 1 then return a-b elseif op == 2 then return a*b @@ -290,7 +253,7 @@ pub unsafe fn lua_copy(L: *mut lua_State, fromidx: c_int, toidx: c_int) { #[inline(always)] pub unsafe fn lua_isinteger(L: *mut lua_State, idx: c_int) -> c_int { - if lua_type(L, idx) == lua::LUA_TNUMBER { + if lua_type(L, idx) == LUA_TNUMBER { let n = lua_tonumber(L, idx); let i = lua_tointeger(L, idx); if (n - i as lua_Number).abs() < lua_Number::EPSILON { @@ -300,6 +263,11 @@ pub unsafe fn lua_isinteger(L: *mut lua_State, idx: c_int) -> c_int { return 0; } +#[inline(always)] +pub unsafe fn lua_tointeger(L: *mut lua_State, i: c_int) -> lua_Integer { + lua_tointegerx(L, i, ptr::null_mut()) +} + #[cfg(any(feature = "lua51", feature = "luajit"))] #[inline(always)] pub unsafe fn lua_tonumberx(L: *mut lua_State, i: c_int, isnum: *mut c_int) -> lua_Number { @@ -339,13 +307,20 @@ pub unsafe fn lua_rawlen(L: *mut lua_State, idx: c_int) -> usize { lua_objlen(L, idx) } +#[cfg(any(feature = "lua51", feature = "luajit"))] +pub const LUA_OPEQ: c_int = 0; +#[cfg(any(feature = "lua51", feature = "luajit"))] +pub const LUA_OPLT: c_int = 1; +#[cfg(any(feature = "lua51", feature = "luajit"))] +pub const LUA_OPLE: c_int = 2; + #[cfg(any(feature = "lua51", feature = "luajit"))] #[inline(always)] pub unsafe fn lua_compare(L: *mut lua_State, mut idx1: c_int, mut idx2: c_int, op: c_int) -> c_int { match op { - lua::LUA_OPEQ => lua_equal(L, idx1, idx2), - lua::LUA_OPLT => lua_lessthan(L, idx1, idx2), - lua::LUA_OPLE => { + LUA_OPEQ => lua_equal(L, idx1, idx2), + LUA_OPLT => lua_lessthan(L, idx1, idx2), + LUA_OPLE => { luaL_checkstack(L, 5, cstr!("not enough stack slots")); idx1 = lua_absindex(L, idx1); idx2 = lua_absindex(L, idx2); @@ -364,9 +339,9 @@ pub unsafe fn lua_compare(L: *mut lua_State, mut idx1: c_int, mut idx2: c_int, o #[inline(always)] pub unsafe fn lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char { if l == 0 { - lua_pushlstring_old(L, cstr!(""), 0); + lua_pushlstring_(L, cstr!(""), 0); } else { - lua_pushlstring_old(L, s, l); + lua_pushlstring_(L, s, l); } lua_tostring(L, -1) } @@ -375,35 +350,34 @@ pub unsafe fn lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize) -> #[inline(always)] pub unsafe fn lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char { if l == 0 { - lua_pushlstring_old(L, cstr!(""), 0) + lua_pushlstring_(L, cstr!(""), 0) } else { - lua_pushlstring_old(L, s, l) + lua_pushlstring_(L, s, l) } } #[cfg(any(feature = "lua51", feature = "luajit"))] #[inline(always)] pub unsafe fn lua_pushstring(L: *mut lua_State, s: *const c_char) -> *const c_char { - lua_pushstring_old(L, s); + lua_pushstring_(L, s); lua_tostring(L, -1) } -#[cfg(feature = "lua52")] #[inline(always)] pub unsafe fn lua_getglobal(L: *mut lua_State, var: *const c_char) -> c_int { - lua_getglobal_old(L, var); + lua_getglobal_(L, var); lua_type(L, -1) } #[inline(always)] pub unsafe fn lua_gettable(L: *mut lua_State, idx: c_int) -> c_int { - lua_gettable_old(L, idx); + lua_gettable_(L, idx); lua_type(L, -1) } #[inline(always)] pub unsafe fn lua_getfield(L: *mut lua_State, idx: c_int, k: *const c_char) -> c_int { - lua_getfield_old(L, idx, k); + lua_getfield_(L, idx, k); lua_type(L, -1) } @@ -415,17 +389,15 @@ pub unsafe fn lua_geti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) -> c_i lua_type(L, -1) } -// A new version which returns c_int #[inline(always)] pub unsafe fn lua_rawget(L: *mut lua_State, idx: c_int) -> c_int { - lua_rawget_old(L, idx); + lua_rawget_(L, idx); lua_type(L, -1) } -// A new version which returns c_int #[inline(always)] pub unsafe fn lua_rawgeti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int { - lua_rawgeti_old(L, idx, n); + lua_rawgeti_(L, idx, n.try_into().expect("cannot convert to lua_Integer")); lua_type(L, -1) } @@ -441,7 +413,7 @@ pub unsafe fn lua_rawgetp(L: *mut lua_State, idx: c_int, p: *const c_void) -> c_ #[cfg(feature = "lua52")] #[inline(always)] pub unsafe fn lua_rawgetp(L: *mut lua_State, idx: c_int, p: *const c_void) -> c_int { - lua_rawgetp_old(L, idx, p); + lua_rawgetp_(L, idx, p); lua_type(L, -1) } @@ -455,7 +427,7 @@ pub unsafe fn lua_getuservalue(L: *mut lua_State, idx: c_int) -> c_int { #[cfg(feature = "lua52")] #[inline(always)] pub unsafe fn lua_getuservalue(L: *mut lua_State, idx: c_int) -> c_int { - lua_getuservalue_old(L, idx); + lua_getuservalue_(L, idx); lua_type(L, -1) } @@ -468,6 +440,15 @@ pub unsafe fn lua_seti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) { lua_settable(L, idx); } +#[inline(always)] +pub unsafe fn lua_rawseti(L: *mut lua_State, idx: c_int, n: lua_Integer) { + lua_rawseti_( + L, + idx, + n.try_into().expect("cannot convert index from lua_Integer"), + ) +} + #[cfg(any(feature = "lua51", feature = "luajit"))] #[inline(always)] pub unsafe fn lua_rawsetp(L: *mut lua_State, idx: c_int, p: *const c_void) { @@ -481,7 +462,7 @@ pub unsafe fn lua_rawsetp(L: *mut lua_State, idx: c_int, p: *const c_void) { #[cfg(any(feature = "lua51", feature = "luajit"))] #[inline(always)] pub unsafe fn lua_setuservalue(L: *mut lua_State, idx: c_int) { - luaL_checktype(L, -1, lua::LUA_TTABLE); + luaL_checktype(L, -1, LUA_TTABLE); lua_setfenv(L, idx); } @@ -492,28 +473,22 @@ pub unsafe fn lua_dump( data: *mut c_void, _strip: c_int, ) -> c_int { - lua_dump_old(L, writer, data) -} - -#[cfg(any(feature = "lua51", feature = "luajit"))] -#[inline(always)] -pub unsafe fn lua_resume(L: *mut lua_State, _from: *mut lua_State, narg: c_int) -> c_int { - lua_resume_old(L, narg) + lua_dump_(L, writer, data) } #[cfg(any(feature = "lua51", feature = "luajit"))] #[inline(always)] pub unsafe fn lua_len(L: *mut lua_State, idx: c_int) { match lua_type(L, idx) { - lua::LUA_TSTRING => { + LUA_TSTRING => { lua_pushnumber(L, lua_objlen(L, idx) as lua_Number); } - lua::LUA_TTABLE => { + 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 => {} + LUA_TUSERDATA if luaL_callmeta(L, idx, cstr!("__len")) != 0 => {} _ => { luaL_error( L, @@ -526,26 +501,24 @@ pub unsafe fn lua_len(L: *mut lua_State, idx: c_int) { #[inline(always)] pub unsafe fn lua_stringtonumber(L: *mut lua_State, s: *const c_char) -> usize { - use std::str::FromStr; - let cs = CStr::from_ptr(s); if let Ok(rs) = cs.to_str() { - if let Ok(n) = f64::from_str(rs.trim()) { - lua_pushnumber(L, n as lua_Number); + if let Ok(n) = lua_Number::from_str(rs.trim()) { + lua_pushnumber(L, n); return cs.to_bytes_with_nul().len(); } } 0 } +pub const LUA_EXTRASPACE: usize = mem::size_of::<*const ()>(); + #[allow(clippy::branches_sharing_code)] pub unsafe fn lua_getextraspace(L: *mut lua_State) -> *mut c_void { - 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); + lua_rawget(L, LUA_REGISTRYINDEX); if lua_istable(L, -1) == 0 { lua_pop(L, 1); lua_createtable(L, 0, 2); @@ -555,7 +528,7 @@ pub unsafe fn lua_getextraspace(L: *mut lua_State) -> *mut c_void { lua_setmetatable(L, -2); lua_pushvalue(L, -2); lua_pushvalue(L, -2); - lua_rawset(L, lua::LUA_REGISTRYINDEX); + lua_rawset(L, LUA_REGISTRYINDEX); } lua_replace(L, -2); let is_main = lua_pushthread(L); @@ -563,10 +536,10 @@ pub unsafe fn lua_getextraspace(L: *mut lua_State) -> *mut c_void { let mut _ptr = lua_touserdata(L, -1); if _ptr.is_null() { lua_pop(L, 1); - _ptr = lua_newuserdata(L, LUA_EXTRASPACE as usize); + _ptr = lua_newuserdata(L, LUA_EXTRASPACE); if is_main != 0 { // mem::size_of::() == 1 - ptr::write_bytes(_ptr, 0, LUA_EXTRASPACE as usize); + ptr::write_bytes(_ptr, 0, LUA_EXTRASPACE); lua_pushthread(L); lua_pushvalue(L, -2); lua_rawset(L, -4); @@ -578,9 +551,9 @@ pub unsafe fn lua_getextraspace(L: *mut lua_State) -> *mut c_void { lua_rawget(L, -3); let mptr = lua_touserdata(L, -1); if !mptr.is_null() { - ptr::copy_nonoverlapping(mptr, _ptr, LUA_EXTRASPACE as usize) + ptr::copy_nonoverlapping(mptr, _ptr, LUA_EXTRASPACE) } else { - ptr::write_bytes(_ptr, 0, LUA_EXTRASPACE as usize); + ptr::write_bytes(_ptr, 0, LUA_EXTRASPACE); } lua_pop(L, 1); lua_pushthread(L); @@ -595,7 +568,7 @@ pub unsafe fn lua_getextraspace(L: *mut lua_State) -> *mut c_void { #[cfg(any(feature = "lua51", feature = "luajit"))] #[inline(always)] pub unsafe fn lua_pushglobaltable(L: *mut lua_State) { - lua_pushvalue(L, lua::LUA_GLOBALSINDEX); + lua_pushvalue(L, LUA_GLOBALSINDEX); } // @@ -605,7 +578,7 @@ pub unsafe fn lua_pushglobaltable(L: *mut lua_State) { #[cfg(any(feature = "lua51", feature = "luajit"))] #[inline(always)] pub unsafe fn luaL_checkstack(L: *mut lua_State, sz: c_int, msg: *const c_char) { - if lua_checkstack(L, sz + lua::LUA_MINSTACK) == 0 { + if lua_checkstack(L, sz + LUA_MINSTACK) == 0 { if !msg.is_null() { luaL_error(L, cstr!("stack overflow (%s)"), msg); } else { @@ -615,22 +588,18 @@ pub unsafe fn luaL_checkstack(L: *mut lua_State, sz: c_int, msg: *const c_char) } } -pub unsafe fn luaL_checkversion(_L: *mut lua_State) { - // Void -} - #[inline(always)] pub unsafe fn luaL_getmetafield(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int { - if luaL_getmetafield_old(L, obj, e) != 0 { + if luaL_getmetafield_(L, obj, e) != 0 { lua_type(L, -1) } else { - lua::LUA_TNIL + LUA_TNIL } } #[inline(always)] pub unsafe fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_int { - if luaL_newmetatable_old(L, tname) != 0 { + if luaL_newmetatable_(L, tname) != 0 { lua_pushstring(L, tname); lua_setfield(L, -2, cstr!("__name")); 1 @@ -648,12 +617,12 @@ pub unsafe fn luaL_loadbufferx( 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) + let status = if sz > 0 && *buff as u8 == LUA_SIGNATURE[0] { + compat53_checkmode(L, mode, cstr!("binary"), LUA_ERRSYNTAX) } else { - compat53_checkmode(L, mode, cstr!("text"), lua::LUA_ERRSYNTAX) + compat53_checkmode(L, mode, cstr!("text"), LUA_ERRSYNTAX) }; - if status != lua::LUA_OK { + if status != LUA_OK { return status; } luaL_loadbuffer(L, buff, sz, name) @@ -666,7 +635,7 @@ pub unsafe fn luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer { 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); + lua_pop(L, 1); if isnum == 0 { luaL_error(L, cstr!("object length is not an integer")); } @@ -717,13 +686,13 @@ pub unsafe fn luaL_tolstring(L: *mut lua_State, idx: c_int, len: *mut usize) -> if luaL_callmeta(L, idx, cstr!("__tostring")) == 0 { let t = lua_type(L, idx); match t { - lua::LUA_TNIL => { + LUA_TNIL => { lua_pushliteral(L, "nil"); } - lua::LUA_TSTRING | lua::LUA_TNUMBER => { + LUA_TSTRING | LUA_TNUMBER => { lua_pushvalue(L, idx); } - lua::LUA_TBOOLEAN => { + LUA_TBOOLEAN => { if lua_toboolean(L, idx) == 0 { lua_pushliteral(L, "false"); } else { @@ -732,13 +701,13 @@ pub unsafe fn luaL_tolstring(L: *mut lua_State, idx: c_int, len: *mut usize) -> } _ => { let tt = luaL_getmetafield(L, idx, cstr!("__name")); - let name = if tt == lua::LUA_TSTRING { + let name = if tt == LUA_TSTRING { lua_tostring(L, -1) } else { lua_typename(L, t) }; lua_pushfstring(L, cstr!("%s: %p"), name, lua_topointer(L, idx)); - if tt != lua::LUA_TNIL { + if tt != LUA_TNIL { lua_replace(L, -2); } } @@ -817,8 +786,8 @@ pub unsafe fn luaL_requiref( 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 { + luaL_getsubtable(L, LUA_REGISTRYINDEX, cstr!("_LOADED")); + if lua_getfield(L, -1, modname) == LUA_TNIL { lua_pop(L, 1); lua_pushcfunction(L, openf); lua_pushstring(L, modname); diff --git a/src/ffi/glue/glue.c b/src/ffi/glue/glue.c deleted file mode 100644 index b739a53..0000000 --- a/src/ffi/glue/glue.c +++ /dev/null @@ -1,289 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2019-2021 A. Orlenko -// Copyright (c) 2014 J.C. Moyer -// -// 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. - -#include -#include -#include -#include - -#include -#include -#include - -#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 - -typedef struct rs_item { - int type; - const char *name; - union { - int int_val; - const char *str_val; - LUA_INTEGER lua_int_val; - }; -} rs_item; - - -#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 } - -const char *rs_int_type(int width) { - switch (width) { - default: - case 2: - return "i16"; - case 4: - return "i32"; - case 8: - return "i64"; - case 16: - return "i128"; - } -} - -const char *rs_uint_type(int width) { - switch (width) { - default: - case 2: - return "u16"; - case 4: - return "u32"; - case 8: - return "u64"; - case 16: - return "u128"; - } -} - -int try_write(char **str, char c, size_t n, size_t *written, size_t szstr) { - if (szstr - *written < n) { - return 0; - } - for (; n; n--, *written++) - *(*str)++ = c; - return 1; -} - -// converts \ in a string to \\ so that it can be used as a rust string literal -// ensures that `out` will always have a null terminating character -size_t escape(const char *in, char *out, size_t szout) { - size_t written = 0; - char cur; - - while ((cur = *in++)) { - switch (cur) { - case '\\': - if (!try_write(&out, cur, 2, &written, szout)) - goto finalize; - break; - default: - if (!try_write(&out, cur, 1, &written, szout)) - goto finalize; - break; - } - } - -finalize: - if (written + 1 <= szout) { - *out++ = '\0'; - written++; - } - return written; -} - -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); - size_t bufsz = len * 2 + 1; - char *buf = malloc(bufsz); - int ret; - escape(value, buf, bufsz); - ret = fprintf(f, "pub const %s: &str = \"%s\";\n", name, buf); - free(buf); - return ret; -} - -int write_type(FILE *f, const char *name, const char *value) { - return fprintf(f, "pub type %s = %s;\n", name, value); -} - -int write_comment(FILE *f, const char *value) { - return fprintf(f, "/* %s */\n", value); -} - -int write_raw(FILE *f, const char *value) { return fputs(value, f) >= 0; } - -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: - return write_type(f, c->name, c->str_val); - case TY_COMMENT: - return write_comment(f, c->str_val); - case TY_RAW: - return write_raw(f, c->str_val); - default: - return 0; - } -} - -int write_items_(FILE *f, const rs_item items[], size_t num) { - size_t i; - for (i = 0; i < num; i++) { - if (!write_item(f, &items[i])) - return 0; - } - return 1; -} - -#define write_items(f, cs) write_items_(f, cs, sizeof(cs) / sizeof(cs[0])) - -int main(int argc, const char **argv) { - if (argc <= 1) { - printf("usage: %s \n", argv[0]); - return EXIT_FAILURE; - } - - const char *filename = argv[1]; - - FILE *f = fopen(filename, "w"); - - if (!f) { - printf("could not open file: errno = %d\n", errno); - return EXIT_FAILURE; - } - - const rs_item glue_entries[] = { - RS_COMMENT("this file was generated by glue.c; do not modify it by hand"), - RS_RAW("use std::os::raw::*;\n"), - - // == luaconf.h ========================================================== - - RS_COMMENT("luaconf.h"), - RS_INT("LUA_EXTRASPACE", LUA_EXTRASPACE), - RS_INT("LUA_IDSIZE", LUA_IDSIZE), - RS_TYPE("LUA_NUMBER", - sizeof(LUA_NUMBER) > sizeof(float) ? "c_double" : "c_float"), - RS_TYPE("LUA_INTEGER", rs_int_type(sizeof(LUA_INTEGER))), -#if LUA_VERSION_NUM >= 502 - RS_TYPE("LUA_UNSIGNED", rs_uint_type(sizeof(LUA_UNSIGNED))), -#else - RS_TYPE("LUA_UNSIGNED", rs_uint_type(sizeof(size_t))), -#endif - - // == lua.h ============================================================== - - RS_COMMENT("lua.h"), - RS_INT("LUA_VERSION_NUM", LUA_VERSION_NUM), - 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), -#endif - - // == lualib.h =========================================================== - - RS_COMMENT("lualib.h"), - RS_STR("LUA_COLIBNAME", LUA_COLIBNAME), - RS_STR("LUA_TABLIBNAME", LUA_TABLIBNAME), - RS_STR("LUA_IOLIBNAME", LUA_IOLIBNAME), - RS_STR("LUA_OSLIBNAME", LUA_OSLIBNAME), - RS_STR("LUA_STRLIBNAME", LUA_STRLIBNAME), -#ifdef LUA_UTF8LIBNAME - RS_STR("LUA_UTF8LIBNAME", LUA_UTF8LIBNAME), -#endif -#ifdef LUA_BITLIBNAME - 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), -#ifdef LUA_JITLIBNAME - RS_STR("LUA_JITLIBNAME", LUA_JITLIBNAME), -#endif -#ifdef LUA_FFILIBNAME - RS_STR("LUA_FFILIBNAME", LUA_FFILIBNAME), -#endif - }; - - if (!write_items(f, glue_entries)) { - printf("%s: error generating %s; aborting\n", argv[0], filename); - return EXIT_FAILURE; - } - - fclose(f); - - return EXIT_SUCCESS; -} diff --git a/src/ffi/lauxlib.rs b/src/ffi/lauxlib.rs index b3c0a81..2371edb 100644 --- a/src/ffi/lauxlib.rs +++ b/src/ffi/lauxlib.rs @@ -1,306 +1,29 @@ -// The MIT License (MIT) -// -// Copyright (c) 2019-2021 A. Orlenko -// Copyright (c) 2014 J.C. Moyer -// -// 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. - //! Contains definitions from `lauxlib.h`. -use std::os::raw::{c_char, c_int, c_long, c_void}; -use std::ptr; +use std::os::raw::c_int; -use super::lua::{self, lua_CFunction, lua_Integer, lua_Number, lua_State}; +#[cfg(feature = "lua54")] +pub use super::lua54::lauxlib::*; -#[cfg(any(feature = "lua54", feature = "lua53"))] -pub use super::glue::LUAL_NUMSIZES; +#[cfg(feature = "lua53")] +pub use super::lua53::lauxlib::*; -#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))] +#[cfg(feature = "lua52")] +pub use super::lua52::lauxlib::*; + +#[cfg(any(feature = "lua51", feature = "luajit"))] +pub use super::lua51::lauxlib::*; + +#[cfg(feature = "lua52")] pub use super::compat53::{luaL_getmetafield, luaL_newmetatable, luaL_requiref, luaL_tolstring}; #[cfg(any(feature = "lua51", feature = "luajit"))] pub use super::compat53::{ - luaL_checkstack, luaL_checkversion, luaL_getsubtable, luaL_len, luaL_loadbufferx, - luaL_setfuncs, luaL_setmetatable, luaL_testudata, luaL_traceback, + luaL_checkstack, 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; - -#[repr(C)] -pub struct luaL_Reg { - pub name: *const c_char, - pub func: lua_CFunction, -} - -#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] -#[inline(always)] -pub unsafe fn luaL_checkversion(L: *mut lua_State) { - #[cfg(any(feature = "lua54", feature = "lua53"))] - luaL_checkversion_( - L, - lua::LUA_VERSION_NUM as lua_Number, - LUAL_NUMSIZES as usize, - ); - #[cfg(feature = "lua52")] - luaL_checkversion_(L, lua::LUA_VERSION_NUM as lua_Number); -} - -extern "C" { - #[cfg(any(feature = "lua54", feature = "lua53"))] - pub fn luaL_checkversion_(L: *mut lua_State, ver: lua_Number, sz: usize); - #[cfg(feature = "lua52")] - pub fn luaL_checkversion_(L: *mut lua_State, ver: lua_Number); - - #[cfg(any(feature = "lua54", feature = "lua53"))] - pub fn luaL_getmetafield(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int; - #[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))] - #[link_name = "luaL_getmetafield"] - pub fn luaL_getmetafield_old(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(any(feature = "lua54", 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; - 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; - - #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] - 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); - - #[cfg(any(feature = "lua54", feature = "lua53"))] - pub fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_int; - #[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))] - #[link_name = "luaL_newmetatable"] - pub fn luaL_newmetatable_old(L: *mut lua_State, tname: *const c_char) -> c_int; - - #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] - pub fn luaL_setmetatable(L: *mut lua_State, tname: *const c_char); - #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] - 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, ...) -> !; - - // TODO: test this - pub fn luaL_checkoption( - L: *mut lua_State, - arg: c_int, - def: *const c_char, - lst: *const *const c_char, - ) -> c_int; - - #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] - pub fn luaL_fileresult(L: *mut lua_State, stat: c_int, fname: *const c_char) -> c_int; - #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] - pub fn luaL_execresult(L: *mut lua_State, stat: c_int) -> c_int; -} - -// pre-defined references -pub const LUA_NOREF: c_int = -2; -pub const LUA_REFNIL: c_int = -1; - -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(any(feature = "lua54", feature = "lua53", feature = "lua52"))] - pub fn luaL_loadfilex(L: *mut lua_State, filename: *const c_char, mode: *const c_char) - -> c_int; - #[cfg(any(feature = "lua51", feature = "luajit"))] - pub fn luaL_loadfile(L: *mut lua_State, filename: *const c_char) -> c_int; -} - -#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] -#[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(any(feature = "lua54", feature = "lua53", feature = "lua52"))] - pub fn luaL_loadbufferx( - L: *mut lua_State, - buff: *const c_char, - sz: usize, - name: *const c_char, - mode: *const c_char, - ) -> c_int; - #[cfg(any(feature = "lua51", feature = "luajit"))] - 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(any(feature = "lua54", feature = "lua53", feature = "lua52"))] - pub fn luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer; - - // TODO (lua54): 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; - - #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] - pub fn luaL_setfuncs(L: *mut lua_State, l: *const luaL_Reg, nup: c_int); - - #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] - pub fn luaL_getsubtable(L: *mut lua_State, idx: c_int, fname: *const c_char) -> c_int; - - #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] - pub fn luaL_traceback(L: *mut lua_State, L1: *mut lua_State, msg: *const c_char, level: c_int); - - // Skip Lua 5.2 implementation in favor of the compat53 one - #[cfg(any(feature = "lua54", feature = "lua53"))] - pub fn luaL_requiref( - L: *mut lua_State, - modname: *const c_char, - openf: lua_CFunction, - glb: c_int, - ); -} - -#[inline(always)] -#[allow(unused_variables)] -pub unsafe fn luaL_newlibtable(L: *mut lua_State, l: *const luaL_Reg) { - // TODO: figure out how to pass an appropriate hint for the second param - // this involves correcting the second parameter's type; in C this is - // sizeof(l)/sizeof(l[0]) - lua::lua_createtable(L, 0, 0) -} - -#[inline(always)] -pub unsafe fn luaL_newlib(L: *mut lua_State, l: *const luaL_Reg) { - luaL_checkversion(L); - luaL_newlibtable(L, l); - luaL_setfuncs(L, l, 0) -} - -#[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()) -} - -// From 5.3 user manual: -// Macros to project non-default integer types (luaL_checkint, luaL_optint, -// luaL_checklong, luaL_optlong) were deprecated. Use their equivalent over -// lua_Integer with a type cast (or, when possible, use lua_Integer in your -// code). -#[inline(always)] -//#[deprecated] -pub unsafe fn luaL_checkint(L: *mut lua_State, n: c_int) -> c_int { - luaL_checkinteger(L, n) as c_int -} - -#[inline(always)] -//#[deprecated] -pub unsafe fn luaL_optint(L: *mut lua_State, n: c_int, d: c_int) -> c_int { - luaL_optinteger(L, n, d as lua_Integer) as c_int -} - -#[inline(always)] -//#[deprecated] -pub unsafe fn luaL_checklong(L: *mut lua_State, n: c_int) -> c_long { - luaL_checkinteger(L, n) as c_long -} - -#[inline(always)] -//#[deprecated] -pub unsafe fn luaL_optlong(L: *mut lua_State, n: c_int, d: c_long) -> c_long { - luaL_optinteger(L, n, d as lua_Integer) as c_long -} - -#[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 - -#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] -#[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()) -} - -// TODO: Add buffer API - -// omitted: old module system compatibility (removed in 5.4) +// I believe `luaL_traceback` < 5.4 requires this much free stack to not error. +// 5.4 uses `luaL_Buffer` +pub const LUA_TRACEBACK_STACK: c_int = 11; diff --git a/src/ffi/lua.rs b/src/ffi/lua.rs index f96b989..53af3a2 100644 --- a/src/ffi/lua.rs +++ b/src/ffi/lua.rs @@ -1,559 +1,48 @@ -// The MIT License (MIT) -// -// Copyright (c) 2019-2021 A. Orlenko -// Copyright (c) 2014 J.C. Moyer -// -// 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. - //! Contains definitions from `lua.h`. -use std::marker::{PhantomData, PhantomPinned}; -#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] -use std::os::raw::c_uchar; -use std::os::raw::{c_char, c_int, c_void}; +use std::os::raw::c_int; + #[cfg(feature = "lua54")] -use std::os::raw::{c_uint, c_ushort}; -use std::ptr; +pub use super::lua54::lua::*; -use super::luaconf; - -#[cfg(any(feature = "lua51", feature = "luajit"))] -pub use super::glue::{LUA_ENVIRONINDEX, LUA_GLOBALSINDEX}; -pub use super::glue::{LUA_REGISTRYINDEX, LUA_VERSION_NUM}; - -#[cfg(not(feature = "luajit"))] -pub const LUA_SIGNATURE: &[u8] = b"\x1bLua"; -#[cfg(feature = "luajit")] -pub const LUA_SIGNATURE: &[u8] = b"\x1bLJ"; - -// option for multiple returns in 'lua_pcall' and 'lua_call' -pub const LUA_MULTRET: c_int = -1; - -#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))] -pub use super::compat53::{ - lua_dump, lua_getextraspace, lua_getfield, lua_geti, lua_gettable, lua_getuservalue, - lua_isinteger, lua_pushlstring, lua_rawget, lua_rawgeti, lua_rawgetp, lua_rotate, lua_seti, - lua_stringtonumber, lua_tointegerx, -}; - -#[cfg(any(feature = "lua51", feature = "luajit"))] -pub use super::compat53::{ - lua_absindex, lua_arith, lua_compare, lua_copy, lua_len, lua_pushglobaltable, lua_pushstring, - lua_rawlen, lua_rawsetp, lua_resume as lua_resume_53, lua_setuservalue, lua_tonumberx, - lua_upvalueindex, -}; +#[cfg(feature = "lua53")] +pub use super::lua53::lua::*; #[cfg(feature = "lua52")] -pub use super::compat53::lua_getglobal; +pub use super::lua52::lua::*; -#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] -#[inline(always)] -pub const fn lua_upvalueindex(i: c_int) -> c_int { - LUA_REGISTRYINDEX - i -} +#[cfg(any(feature = "lua51", feature = "luajit"))] +pub use super::lua51::lua::*; -// 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; -#[cfg(any(feature = "lua53", feature = "lua52"))] -pub const LUA_ERRGCMM: c_int = 5; -#[cfg(any(feature = "lua54", feature = "lua51", feature = "luajit"))] -pub const LUA_ERRERR: c_int = 5; -#[cfg(any(feature = "lua53", feature = "lua52"))] -pub const LUA_ERRERR: c_int = 6; +#[cfg(feature = "lua52")] +pub use super::compat53::{ + lua_dump, lua_getextraspace, lua_getfield, lua_getglobal, lua_geti, lua_gettable, + lua_getuservalue, lua_isinteger, lua_pushlstring, lua_rawget, lua_rawgeti, lua_rawgetp, + lua_rawseti, lua_rotate, lua_seti, lua_stringtonumber, lua_tointeger, lua_tointegerx, + LUA_EXTRASPACE, +}; -/// A raw Lua state associated with a thread. -#[repr(C)] -pub struct lua_State { - _data: [u8; 0], - _marker: PhantomData<(*mut u8, PhantomPinned)>, -} +#[cfg(any(feature = "lua51", feature = "luajit"))] +pub use super::compat53::{ + lua_absindex, lua_arith, lua_compare, lua_copy, lua_dump, lua_getextraspace, lua_getfield, + lua_getglobal, lua_geti, lua_gettable, lua_getuservalue, lua_isinteger, lua_len, + lua_pushglobaltable, lua_pushlstring, lua_pushstring, lua_rawget, lua_rawgeti, lua_rawgetp, + lua_rawlen, lua_rawseti, lua_rawsetp, lua_rotate, lua_seti, lua_setuservalue, + lua_stringtonumber, lua_tointeger, lua_tointegerx, lua_tonumberx, +}; -// basic types -pub const LUA_TNONE: c_int = -1; +#[cfg(any(feature = "lua52", feature = "lua53", feature = "lua54",))] +pub const LUA_MAX_UPVALUES: c_int = 255; -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; +#[cfg(any(feature = "lua51", all(feature = "luajit", not(feature = "vendored"))))] +pub const LUA_MAX_UPVALUES: c_int = 60; -// Type produced by LuaJIT FFI module -#[cfg(feature = "luajit")] -pub const LUA_TCDATA: c_int = 10; +#[cfg(all(feature = "luajit", feature = "vendored"))] +pub const LUA_MAX_UPVALUES: c_int = 120; -#[cfg(feature = "lua54")] -pub const LUA_NUMTYPES: c_int = 9; -#[cfg(any(feature = "lua53", feature = "lua52"))] -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(any(feature = "lua54", feature = "lua53", feature = "lua52"))] -pub const LUA_RIDX_MAINTHREAD: lua_Integer = 1; -#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] -pub const LUA_RIDX_GLOBALS: lua_Integer = 2; -#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] -pub const LUA_RIDX_LAST: lua_Integer = LUA_RIDX_GLOBALS; - -// I believe `luaL_traceback` < 5.4 requires this much free stack to not error. -// 5.4 uses `luaL_Buffer` -pub const LUA_TRACEBACK_STACK: c_int = 11; - -/// A Lua number, usually equivalent to `f64`. -pub type lua_Number = luaconf::LUA_NUMBER; - -/// A Lua integer, usually equivalent to `i64`. -pub type lua_Integer = luaconf::LUA_INTEGER; - -/// A Lua unsigned integer, usually equivalent to `u64`. -pub type lua_Unsigned = luaconf::LUA_UNSIGNED; - -// type for continuation-function contexts -#[cfg(any(feature = "lua54", feature = "lua53"))] -pub type lua_KContext = luaconf::LUA_KCONTEXT; - -/// Type for native C 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(any(feature = "lua54", feature = "lua53"))] -pub type lua_KFunction = - unsafe extern "C" 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 -pub type lua_Reader = - unsafe extern "C" fn(L: *mut lua_State, ud: *mut c_void, sz: *mut usize) -> *const c_char; -pub type lua_Writer = - unsafe extern "C" fn(L: *mut lua_State, p: *const c_void, sz: usize, ud: *mut c_void) -> c_int; - -// Type for memory-allocation functions. -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 -#[cfg(feature = "lua54")] -pub type lua_WarnFunction = - unsafe extern "C" fn(ud: *mut c_void, msg: *const c_char, tocont: c_int); - -extern "C" { - // state manipulation - pub fn lua_newstate(f: lua_Alloc, ud: *mut c_void) -> *mut lua_State; - pub fn lua_close(L: *mut lua_State); - pub fn lua_newthread(L: *mut lua_State) -> *mut lua_State; - - #[cfg(feature = "lua54")] - #[link_name = "lua_resetthread"] - pub fn lua_resetthread_54(L: *mut lua_State) -> c_int; - #[cfg(all(feature = "luajit", feature = "vendored"))] - #[link_name = "lua_resetthread"] - pub fn lua_resetthread_jit(L: *mut lua_State, th: *mut lua_State); - - pub fn lua_atpanic(L: *mut lua_State, panicf: lua_CFunction) -> lua_CFunction; - - #[cfg(feature = "lua54")] - pub fn lua_version(L: *mut lua_State) -> lua_Number; - #[cfg(feature = "lua53")] - pub fn lua_version(L: *mut lua_State) -> *const lua_Number; - - // basic stack manipulation - #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] - 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(any(feature = "lua52", feature = "lua51", feature = "luajit"))] - pub fn lua_remove(L: *mut lua_State, idx: c_int); - #[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))] - pub fn lua_insert(L: *mut lua_State, idx: c_int); - #[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))] - pub fn lua_replace(L: *mut lua_State, idx: c_int); - #[cfg(any(feature = "lua54", feature = "lua53"))] - pub fn lua_rotate(L: *mut lua_State, idx: c_int, n: c_int); - #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] - 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; - #[cfg(any(feature = "lua54", 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(any(feature = "lua51", feature = "luajit"))] - pub fn lua_tonumber(L: *mut lua_State, idx: c_int) -> lua_Number; - #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] - pub fn lua_tonumberx(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Number; - #[cfg(any(feature = "lua51", feature = "luajit"))] - pub fn lua_tointeger(L: *mut lua_State, idx: c_int) -> lua_Integer; - #[cfg(any(feature = "lua54", 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(any(feature = "lua51", feature = "luajit"))] - pub fn lua_objlen(L: *mut lua_State, idx: c_int) -> usize; - #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] - 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; - 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; -} - -#[cfg(any(feature = "lua54", all(feature = "luajit", feature = "vendored")))] -pub unsafe fn lua_resetthread(_L: *mut lua_State, th: *mut lua_State) -> c_int { - #[cfg(all(feature = "luajit", feature = "vendored"))] - { - lua_resetthread_jit(_L, th); - LUA_OK - } - #[cfg(feature = "lua54")] - lua_resetthread_54(th) -} - -// 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; - -#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))] -pub const LUA_OPDIV: c_int = 3; -#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))] -pub const LUA_OPMOD: c_int = 4; -#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))] -pub const LUA_OPPOW: c_int = 5; -#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))] -pub const LUA_OPUNM: c_int = 6; - -#[cfg(any(feature = "lua54", feature = "lua53"))] -pub const LUA_OPMOD: c_int = 3; -#[cfg(any(feature = "lua54", feature = "lua53"))] -pub const LUA_OPPOW: c_int = 4; -#[cfg(any(feature = "lua54", feature = "lua53"))] -pub const LUA_OPDIV: c_int = 5; -#[cfg(any(feature = "lua54", feature = "lua53"))] -pub const LUA_OPIDIV: c_int = 6; -#[cfg(any(feature = "lua54", feature = "lua53"))] -pub const LUA_OPBAND: c_int = 7; -#[cfg(any(feature = "lua54", feature = "lua53"))] -pub const LUA_OPBOR: c_int = 8; -#[cfg(any(feature = "lua54", feature = "lua53"))] -pub const LUA_OPBXOR: c_int = 9; -#[cfg(any(feature = "lua54", feature = "lua53"))] -pub const LUA_OPSHL: c_int = 10; -#[cfg(any(feature = "lua54", feature = "lua53"))] -pub const LUA_OPSHR: c_int = 11; -#[cfg(any(feature = "lua54", feature = "lua53"))] -pub const LUA_OPUNM: c_int = 12; -#[cfg(any(feature = "lua54", feature = "lua53"))] -pub const LUA_OPBNOT: c_int = 13; - -extern "C" { - #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] - pub fn lua_arith(L: *mut lua_State, op: c_int); -} - -pub const LUA_OPEQ: c_int = 0; -pub const LUA_OPLT: c_int = 1; -pub const LUA_OPLE: c_int = 2; - -extern "C" { - #[cfg(any(feature = "lua51", feature = "luajit"))] - 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(any(feature = "lua51", feature = "luajit"))] - pub fn lua_lessthan(L: *mut lua_State, idx1: c_int, idx2: c_int) -> c_int; - #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] - pub fn lua_compare(L: *mut lua_State, idx1: c_int, idx2: c_int, op: c_int) -> c_int; -} - -// push functions (C -> stack) -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(any(feature = "lua54", feature = "lua53"))] - pub fn lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char; - #[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))] - #[link_name = "lua_pushlstring"] - pub fn lua_pushlstring_old(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char; - - #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] - pub fn lua_pushstring(L: *mut lua_State, s: *const c_char) -> *const c_char; - #[cfg(any(feature = "lua51", feature = "luajit"))] - #[link_name = "lua_pushstring"] - pub fn lua_pushstring_old(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; - 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) -extern "C" { - #[cfg(any(feature = "lua54", feature = "lua53"))] - pub fn lua_getglobal(L: *mut lua_State, var: *const c_char) -> c_int; - #[cfg(feature = "lua52")] - #[link_name = "lua_getglobal"] - pub fn lua_getglobal_old(L: *mut lua_State, var: *const c_char); - - #[cfg(any(feature = "lua54", feature = "lua53"))] - pub fn lua_gettable(L: *mut lua_State, idx: c_int) -> c_int; - #[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))] - #[link_name = "lua_gettable"] - pub fn lua_gettable_old(L: *mut lua_State, idx: c_int); - - #[cfg(any(feature = "lua54", feature = "lua53"))] - pub fn lua_getfield(L: *mut lua_State, idx: c_int, k: *const c_char) -> c_int; - #[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))] - #[link_name = "lua_getfield"] - pub fn lua_getfield_old(L: *mut lua_State, idx: c_int, k: *const c_char); - - #[cfg(any(feature = "lua54", feature = "lua53"))] - pub fn lua_geti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int; - - #[cfg(any(feature = "lua54", feature = "lua53"))] - pub fn lua_rawget(L: *mut lua_State, idx: c_int) -> c_int; - #[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))] - #[link_name = "lua_rawget"] - pub fn lua_rawget_old(L: *mut lua_State, idx: c_int); - - #[cfg(any(feature = "lua54", feature = "lua53"))] - pub fn lua_rawgeti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int; - #[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))] - #[link_name = "lua_rawgeti"] - pub fn lua_rawgeti_old(L: *mut lua_State, idx: c_int, n: lua_Integer); - - #[cfg(any(feature = "lua54", feature = "lua53"))] - pub fn lua_rawgetp(L: *mut lua_State, idx: c_int, p: *const c_void) -> c_int; - #[cfg(feature = "lua52")] - #[link_name = "lua_rawgetp"] - pub fn lua_rawgetp_old(L: *mut lua_State, idx: c_int, p: *const c_void); - - pub fn lua_createtable(L: *mut lua_State, narr: c_int, nrec: c_int); - #[cfg(feature = "lua54")] - pub fn lua_newuserdatauv(L: *mut lua_State, sz: usize, nuvalue: c_int) -> *mut c_void; - #[cfg(any( - feature = "lua53", - feature = "lua52", - feature = "lua51", - feature = "luajit" - ))] - 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 = "lua54")] - pub fn lua_getiuservalue(L: *mut lua_State, idx: c_int, n: c_int) -> c_int; - #[cfg(feature = "lua53")] - pub fn lua_getuservalue(L: *mut lua_State, idx: c_int) -> c_int; - #[cfg(feature = "lua52")] - #[link_name = "lua_getuservalue"] - pub fn lua_getuservalue_old(L: *mut lua_State, idx: c_int); - #[cfg(any(feature = "lua51", feature = "luajit"))] - pub fn lua_getfenv(L: *mut lua_State, idx: c_int); -} - -#[cfg(feature = "lua54")] -#[inline(always)] -pub unsafe fn lua_newuserdata(L: *mut lua_State, sz: usize) -> *mut c_void { - lua_newuserdatauv(L, sz, 1) -} - -#[cfg(feature = "lua54")] -#[inline(always)] -pub unsafe fn lua_getuservalue(L: *mut lua_State, idx: c_int) -> c_int { - lua_getiuservalue(L, idx, 1) -} - -// set functions (stack -> Lua) -extern "C" { - #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] - 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(any(feature = "lua54", 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(any(feature = "lua54", feature = "lua53", feature = "lua52"))] - 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 = "lua54")] - pub fn lua_setiuservalue(L: *mut lua_State, idx: c_int, n: c_int) -> c_int; - #[cfg(any(feature = "lua53", feature = "lua52"))] - pub fn lua_setuservalue(L: *mut lua_State, idx: c_int); - #[cfg(any(feature = "lua51", feature = "luajit"))] - pub fn lua_setfenv(L: *mut lua_State, idx: c_int) -> c_int; -} - -#[cfg(feature = "lua54")] -#[inline(always)] -pub unsafe fn lua_setuservalue(L: *mut lua_State, idx: c_int) { - lua_setiuservalue(L, idx, 1); -} - -// 'load' and 'call' functions (load and run Lua code) -extern "C" { - #[cfg(any(feature = "lua54", feature = "lua53"))] - pub fn lua_callk( - L: *mut lua_State, - nargs: c_int, - nresults: c_int, - ctx: lua_KContext, - k: Option, - ); - #[cfg(feature = "lua52")] - pub fn lua_callk( - L: *mut lua_State, - nargs: c_int, - nresults: c_int, - ctx: c_int, - k: Option, - ); - - #[cfg(any(feature = "lua54", feature = "lua53"))] - pub fn lua_pcallk( - L: *mut lua_State, - nargs: c_int, - nresults: c_int, - errfunc: c_int, - ctx: lua_KContext, - k: Option, - ) -> c_int; - #[cfg(feature = "lua52")] - pub fn lua_pcallk( - L: *mut lua_State, - nargs: c_int, - nresults: c_int, - errfunc: c_int, - ctx: c_int, - k: Option, - ) -> c_int; - - #[cfg(feature = "lua52")] - pub fn lua_getctx(L: *mut lua_State, ctx: *mut c_int) -> c_int; - - #[cfg(any(feature = "lua51", feature = "luajit"))] - pub fn lua_call(L: *mut lua_State, nargs: c_int, nresults: c_int); - #[cfg(any(feature = "lua51", feature = "luajit"))] - pub fn lua_pcall(L: *mut lua_State, nargs: c_int, nresults: c_int, errfunc: c_int) -> c_int; - - // TODO - pub fn lua_load( - L: *mut lua_State, - reader: lua_Reader, - dt: *mut c_void, - chunkname: *const c_char, - mode: *const c_char, - ) -> c_int; - - #[cfg(any(feature = "lua54", feature = "lua53"))] - pub fn lua_dump( - L: *mut lua_State, - writer: lua_Writer, - data: *mut c_void, - strip: c_int, - ) -> c_int; - #[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))] - #[link_name = "lua_dump"] - pub fn lua_dump_old(L: *mut lua_State, writer: lua_Writer, data: *mut c_void) -> c_int; -} - -#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] -#[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(any(feature = "lua54", feature = "lua53", feature = "lua52"))] -#[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) -} - -// coroutine functions -extern "C" { - #[cfg(any(feature = "lua54", feature = "lua53"))] - pub fn lua_yieldk( - L: *mut lua_State, - nresults: c_int, - ctx: lua_KContext, - k: Option, - ) -> c_int; - #[cfg(feature = "lua52")] - pub fn lua_yieldk( - L: *mut lua_State, - nresults: c_int, - ctx: c_int, - k: Option, - ) -> c_int; - #[cfg(any(feature = "lua51", feature = "luajit"))] - pub fn lua_yield(L: *mut lua_State, nresults: c_int) -> c_int; - - #[cfg(feature = "lua54")] - pub fn lua_resume( - L: *mut lua_State, - from: *mut lua_State, - narg: c_int, - nres: *mut c_int, - ) -> c_int; - #[cfg(any(feature = "lua53", feature = "lua52"))] - #[link_name = "lua_resume"] - pub fn lua_resume_53(L: *mut lua_State, from: *mut lua_State, narg: c_int) -> c_int; - #[cfg(any(feature = "lua51", feature = "luajit"))] - #[link_name = "lua_resume"] - pub fn lua_resume_old(L: *mut lua_State, narg: c_int) -> c_int; - - pub fn lua_status(L: *mut lua_State) -> c_int; - #[cfg(any(feature = "lua54", feature = "lua53"))] - pub fn lua_isyieldable(L: *mut lua_State) -> c_int; -} - -#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] -#[inline(always)] -pub unsafe fn lua_yield(L: *mut lua_State, n: c_int) -> c_int { - lua_yieldk(L, n, 0, None) -} +// +// Lua 5.4 compatibility layer +// #[cfg(any( feature = "lua53", @@ -568,272 +57,30 @@ pub unsafe fn lua_resume( narg: c_int, nres: *mut c_int, ) -> c_int { - let ret = lua_resume_53(L, from, narg); + #[cfg(any(feature = "lua51", feature = "luajit"))] + let _ = from; + #[cfg(any(feature = "lua51", feature = "luajit"))] + let ret = lua_resume_(L, narg); + + #[cfg(any(feature = "lua53", feature = "lua52"))] + let ret = lua_resume_(L, from, narg); + if ret == LUA_OK || ret == LUA_YIELD { *nres = lua_gettop(L); } ret } -// warning-related functions -#[cfg(feature = "lua54")] -extern "C" { - 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 function and 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_GCSETPAUSE: c_int = 6; -pub const LUA_GCSETSTEPMUL: c_int = 7; -#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] -pub const LUA_GCISRUNNING: c_int = 9; -#[cfg(feature = "lua54")] -pub const LUA_GCGEN: c_int = 10; -#[cfg(feature = "lua54")] -pub const LUA_GCINC: c_int = 11; - -extern "C" { +#[cfg(any(feature = "lua54", all(feature = "luajit", feature = "vendored")))] +pub unsafe fn lua_resetthreadx(L: *mut lua_State, th: *mut lua_State) -> c_int { + #[cfg(all(feature = "luajit", feature = "vendored"))] + { + lua_resetthread(L, th); + LUA_OK + } #[cfg(feature = "lua54")] - pub fn lua_gc(L: *mut lua_State, what: c_int, ...) -> c_int; - #[cfg(any( - feature = "lua53", - feature = "lua52", - feature = "lua51", - feature = "luajit" - ))] - pub fn lua_gc(L: *mut lua_State, what: c_int, data: c_int) -> c_int; -} - -// miscellaneous functions -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(any(feature = "lua54", feature = "lua53", feature = "lua52"))] - pub fn lua_len(L: *mut lua_State, idx: c_int); - #[cfg(any(feature = "lua54", 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); - #[cfg(feature = "lua54")] - pub fn lua_toclose(L: *mut lua_State, idx: c_int); -} - -// some useful macros -// here, implemented as Rust functions -#[cfg(any(feature = "lua54", feature = "lua53"))] -#[inline(always)] -pub unsafe fn lua_getextraspace(L: *mut lua_State) -> *mut c_void { - (L as *mut c_char).offset(-super::glue::LUA_EXTRASPACE as isize) as *mut c_void -} - -#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] -#[inline(always)] -pub unsafe fn lua_tonumber(L: *mut lua_State, i: c_int) -> lua_Number { - lua_tonumberx(L, i, ptr::null_mut()) -} - -#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] -#[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 str) -> *const c_char { - use std::ffi::CString; - let c_str = CString::new(s).unwrap(); - lua_pushlstring(L, c_str.as_ptr(), c_str.as_bytes().len()) -} - -#[cfg(any(feature = "lua51", feature = "luajit"))] -#[inline(always)] -pub unsafe fn lua_setglobal(L: *mut lua_State, var: *const c_char) { - lua_setfield(L, LUA_GLOBALSINDEX, var) -} - -#[cfg(any(feature = "lua51", feature = "luajit"))] -#[inline(always)] -pub unsafe fn lua_getglobal(L: *mut lua_State, var: *const c_char) -> c_int { - lua_getfield(L, LUA_GLOBALSINDEX, var) -} - -#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] -#[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_tostring(L: *mut lua_State, i: c_int) -> *const c_char { - lua_tolstring(L, i, ptr::null_mut()) -} - -#[cfg(any(feature = "lua54", feature = "lua53"))] -#[inline(always)] -pub unsafe fn lua_insert(L: *mut lua_State, idx: c_int) { - lua_rotate(L, idx, 1) -} - -#[cfg(any(feature = "lua54", 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(any(feature = "lua54", feature = "lua53"))] -#[inline(always)] -pub unsafe fn lua_replace(L: *mut lua_State, idx: c_int) { - lua_copy(L, -1, idx); - lua_pop(L, 1) -} - -// Debug API -// 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" 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; - 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; - - #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] - pub fn lua_upvalueid(L: *mut lua_State, fidx: c_int, n: c_int) -> *mut c_void; - #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] - 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; - - #[cfg(feature = "lua54")] - pub fn lua_setcstacklimit(L: *mut lua_State, limit: c_uint) -> c_int; -} - -#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] -#[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, - #[cfg(feature = "lua54")] - pub srclen: usize, - pub currentline: c_int, - pub linedefined: c_int, - pub lastlinedefined: c_int, - pub nups: c_uchar, - pub nparams: c_uchar, - pub isvararg: c_char, - pub istailcall: c_char, - #[cfg(feature = "lua54")] - pub ftransfer: c_ushort, - #[cfg(feature = "lua54")] - pub ntransfer: c_ushort, - pub short_src: [c_char; luaconf::LUA_IDSIZE as usize], - // lua.h mentions this is for private use - i_ci: *mut c_void, -} - -#[cfg(any(feature = "lua51", feature = "luajit"))] -#[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, + { + let _ = L; + lua_resetthread(th) + } } diff --git a/src/ffi/lua51/lauxlib.rs b/src/ffi/lua51/lauxlib.rs new file mode 100644 index 0000000..cdce05e --- /dev/null +++ b/src/ffi/lua51/lauxlib.rs @@ -0,0 +1,145 @@ +//! Contains definitions from `lauxlib.h`. + +use std::os::raw::{c_char, c_int, c_void}; +use std::ptr; + +use super::lua::{self, lua_CFunction, lua_Integer, lua_Number, lua_State}; + +// Extra error code for 'luaL_load' +pub const LUA_ERRFILE: c_int = lua::LUA_ERRERR + 1; + +#[repr(C)] +pub struct luaL_Reg { + pub name: *const c_char, + pub func: lua_CFunction, +} + +extern "C" { + pub fn luaL_register(L: *mut lua_State, libname: *const c_char, l: *const luaL_Reg); + #[link_name = "luaL_getmetafield"] + pub fn luaL_getmetafield_(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int; + pub fn luaL_callmeta(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int; + pub fn luaL_typerror(L: *mut lua_State, narg: c_int, tname: *const c_char) -> c_int; + pub fn luaL_argerror(L: *mut lua_State, narg: c_int, extramsg: *const c_char) -> c_int; + pub fn luaL_checklstring(L: *mut lua_State, narg: c_int, l: *mut usize) -> *const c_char; + pub fn luaL_optlstring( + L: *mut lua_State, + narg: c_int, + def: *const c_char, + l: *mut usize, + ) -> *const c_char; + pub fn luaL_checknumber(L: *mut lua_State, narg: c_int) -> lua_Number; + pub fn luaL_optnumber(L: *mut lua_State, narg: c_int, def: lua_Number) -> lua_Number; + pub fn luaL_checkinteger(L: *mut lua_State, narg: c_int) -> lua_Integer; + pub fn luaL_optinteger(L: *mut lua_State, narg: c_int, def: lua_Integer) -> lua_Integer; + #[link_name = "luaL_checkstack"] + pub fn luaL_checkstack_(L: *mut lua_State, sz: c_int, msg: *const c_char); + pub fn luaL_checktype(L: *mut lua_State, narg: c_int, t: c_int); + pub fn luaL_checkany(L: *mut lua_State, narg: c_int); + + #[link_name = "luaL_newmetatable"] + pub fn luaL_newmetatable_(L: *mut lua_State, tname: *const c_char) -> c_int; + pub fn luaL_checkudata(L: *mut lua_State, ud: c_int, tname: *const c_char) -> *mut c_void; + + pub fn luaL_where(L: *mut lua_State, lvl: c_int); + pub fn luaL_error(L: *mut lua_State, fmt: *const c_char, ...) -> !; + + pub fn luaL_checkoption( + L: *mut lua_State, + narg: c_int, + def: *const c_char, + lst: *const *const c_char, + ) -> c_int; +} + +// Pre-defined references +pub const LUA_NOREF: c_int = -2; +pub const LUA_REFNIL: c_int = -1; + +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#ref: c_int); + + pub fn luaL_loadfile(L: *mut lua_State, filename: *const c_char) -> c_int; + 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; + + 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_findtable( + L: *mut lua_State, + idx: c_int, + fname: *const c_char, + szhint: c_int, + ) -> *const c_char; +} + +// +// Some useful macros (implemented as Rust functions) +// + +#[inline(always)] +pub unsafe fn luaL_argcheck(L: *mut lua_State, cond: c_int, narg: c_int, extramsg: *const c_char) { + if cond == 0 { + luaL_argerror(L, narg, 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()) +} + +// Deprecated from 5.3: luaL_checkint, luaL_optint, luaL_checklong, luaL_optlong + +#[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)) +} + +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); +} + +// TODO: luaL_opt + +// +// TODO: Generic Buffer Manipulation +// diff --git a/src/ffi/lua51/lua.rs b/src/ffi/lua51/lua.rs new file mode 100644 index 0000000..3ad2db5 --- /dev/null +++ b/src/ffi/lua51/lua.rs @@ -0,0 +1,380 @@ +//! Contains definitions from `lua.h`. + +use std::marker::{PhantomData, PhantomPinned}; +use std::os::raw::{c_char, c_double, c_int, c_void}; +use std::ptr; + +// Mark for precompiled code (`Lua`) +#[cfg(not(feature = "luajit"))] +pub const LUA_SIGNATURE: &[u8] = b"\x1bLua"; +#[cfg(feature = "luajit")] +pub const LUA_SIGNATURE: &[u8] = b"\x1bLJ"; + +// Option for multiple returns in 'lua_pcall' and 'lua_call' +pub const LUA_MULTRET: c_int = -1; + +// +// Pseudo-indices +// +pub const LUA_REGISTRYINDEX: c_int = -10000; +pub const LUA_ENVIRONINDEX: c_int = -10001; +pub const LUA_GLOBALSINDEX: c_int = -10002; + +pub const fn lua_upvalueindex(i: c_int) -> c_int { + LUA_GLOBALSINDEX - 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; + +/// Type produced by LuaJIT FFI module +#[cfg(feature = "luajit")] +pub const LUA_TCDATA: c_int = 10; + +/// Minimum Lua stack available to a C function +pub const LUA_MINSTACK: c_int = 20; + +/// A Lua number, usually equivalent to `f64` +pub type lua_Number = c_double; + +/// A Lua integer, usually equivalent to `i64` +pub type lua_Integer = isize; + +/// Type for native C functions that can be passed to Lua. +pub type lua_CFunction = unsafe extern "C" fn(L: *mut lua_State) -> c_int; + +// Type for functions that read/write blocks when loading/dumping Lua chunks +pub type lua_Reader = + unsafe extern "C" fn(L: *mut lua_State, ud: *mut c_void, sz: *mut usize) -> *const c_char; +pub type lua_Writer = + unsafe extern "C" fn(L: *mut lua_State, p: *const c_void, sz: usize, ud: *mut c_void) -> c_int; + +/// Type for memory-allocation functions +pub type lua_Alloc = unsafe extern "C" fn( + ud: *mut c_void, + ptr: *mut c_void, + osize: usize, + nsize: usize, +) -> *mut c_void; + +extern "C" { + // + // State manipulation + // + pub fn lua_newstate(f: lua_Alloc, ud: *mut c_void) -> *mut lua_State; + pub fn lua_close(L: *mut lua_State); + pub fn lua_newthread(L: *mut lua_State) -> *mut lua_State; + + #[cfg(all(feature = "luajit", feature = "vendored"))] + pub fn lua_resetthread(L: *mut lua_State, th: *mut lua_State); + + pub fn lua_atpanic(L: *mut lua_State, panicf: lua_CFunction) -> lua_CFunction; + + // + // Basic stack manipulation + // + 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_remove(L: *mut lua_State, idx: c_int); + pub fn lua_insert(L: *mut lua_State, idx: c_int); + pub fn lua_replace(L: *mut lua_State, idx: 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_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_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; + pub fn lua_lessthan(L: *mut lua_State, idx1: c_int, idx2: c_int) -> c_int; + + pub fn lua_tonumber(L: *mut lua_State, idx: c_int) -> lua_Number; + #[link_name = "lua_tointeger"] + pub fn lua_tointeger_(L: *mut lua_State, idx: 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; + pub fn lua_objlen(L: *mut lua_State, idx: c_int) -> usize; + 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; + + // + // 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); + #[link_name = "lua_pushlstring"] + pub fn lua_pushlstring_(L: *mut lua_State, s: *const c_char, l: usize); + #[link_name = "lua_pushstring"] + pub fn lua_pushstring_(L: *mut lua_State, s: *const c_char); + // lua_pushvfstring + 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) + // + #[link_name = "lua_gettable"] + pub fn lua_gettable_(L: *mut lua_State, idx: c_int); + #[link_name = "lua_getfield"] + pub fn lua_getfield_(L: *mut lua_State, idx: c_int, k: *const c_char); + #[link_name = "lua_rawget"] + pub fn lua_rawget_(L: *mut lua_State, idx: c_int); + #[link_name = "lua_rawgeti"] + pub fn lua_rawgeti_(L: *mut lua_State, idx: c_int, n: c_int); + pub fn lua_createtable(L: *mut lua_State, narr: c_int, nrec: c_int); + pub fn lua_newuserdata(L: *mut lua_State, sz: usize) -> *mut c_void; + pub fn lua_getmetatable(L: *mut lua_State, objindex: c_int) -> c_int; + pub fn lua_getfenv(L: *mut lua_State, idx: c_int); + + // + // Set functions (stack -> Lua) + // + pub fn lua_settable(L: *mut lua_State, idx: c_int); + pub fn lua_setfield(L: *mut lua_State, idx: c_int, k: *const c_char); + pub fn lua_rawset(L: *mut lua_State, idx: c_int); + #[link_name = "lua_rawseti"] + pub fn lua_rawseti_(L: *mut lua_State, idx: c_int, n: c_int); + pub fn lua_setmetatable(L: *mut lua_State, objindex: c_int) -> c_int; + pub fn lua_setfenv(L: *mut lua_State, idx: c_int) -> c_int; + + // + // 'load' and 'call' functions (load and run Lua code) + // + pub fn lua_call(L: *mut lua_State, nargs: c_int, nresults: c_int); + pub fn lua_pcall(L: *mut lua_State, nargs: c_int, nresults: c_int, errfunc: c_int) -> c_int; + pub fn lua_cpcall(L: *mut lua_State, f: lua_CFunction, ud: *mut c_void) -> c_int; + pub fn lua_load( + L: *mut lua_State, + reader: lua_Reader, + data: *mut c_void, + chunkname: *const c_char, + ) -> c_int; + + #[link_name = "lua_dump"] + pub fn lua_dump_(L: *mut lua_State, writer: lua_Writer, data: *mut c_void) -> c_int; + + // + // Coroutine functions + // + pub fn lua_yield(L: *mut lua_State, nresults: c_int) -> c_int; + #[link_name = "lua_resume"] + pub fn lua_resume_(L: *mut lua_State, narg: c_int) -> c_int; + pub fn lua_status(L: *mut lua_State) -> c_int; +} + +// +// Garbage-collection function and 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_GCSETPAUSE: c_int = 6; +pub const LUA_GCSETSTEPMUL: c_int = 7; + +extern "C" { + pub fn lua_gc(L: *mut lua_State, what: c_int, data: c_int) -> c_int; +} + +// +// Miscellaneous functions +// +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); + 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); +} + +// +// Some useful macros (implemented as Rust functions) +// +#[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) +} + +// TODO: lua_strlen + +#[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) <= LUA_TNIL) as c_int +} + +#[inline(always)] +pub unsafe fn lua_pushliteral(L: *mut lua_State, s: &'static str) { + use std::ffi::CString; + let c_str = CString::new(s).unwrap(); + lua_pushlstring_(L, c_str.as_ptr(), c_str.as_bytes().len()) +} + +#[inline(always)] +pub unsafe fn lua_setglobal(L: *mut lua_State, var: *const c_char) { + lua_setfield(L, LUA_GLOBALSINDEX, var) +} + +#[inline(always)] +pub unsafe fn lua_getglobal_(L: *mut lua_State, var: *const c_char) { + lua_getfield_(L, LUA_GLOBALSINDEX, var) +} + +#[inline(always)] +pub unsafe fn lua_tostring(L: *mut lua_State, i: c_int) -> *const c_char { + lua_tolstring(L, i, ptr::null_mut()) +} + +// +// 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" 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; + 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_sethook( + L: *mut lua_State, + func: Option, + mask: c_int, + count: c_int, + ) -> 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, + 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; LUA_IDSIZE], + // lua.h mentions this is for private use + i_ci: c_int, +} diff --git a/src/ffi/lua51/lualib.rs b/src/ffi/lua51/lualib.rs new file mode 100644 index 0000000..2165221 --- /dev/null +++ b/src/ffi/lua51/lualib.rs @@ -0,0 +1,42 @@ +//! Contains definitions from `lualib.h`. + +use std::os::raw::c_int; + +use super::lua::lua_State; + +pub const LUA_COLIBNAME: &str = "coroutine"; +pub const LUA_TABLIBNAME: &str = "table"; +pub const LUA_IOLIBNAME: &str = "io"; +pub const LUA_OSLIBNAME: &str = "os"; +pub const LUA_STRLIBNAME: &str = "string"; +pub const LUA_MATHLIBNAME: &str = "math"; +pub const LUA_DBLIBNAME: &str = "debug"; +pub const LUA_LOADLIBNAME: &str = "package"; + +#[cfg(feature = "luajit")] +pub const LUA_BITLIBNAME: &str = "bit"; +#[cfg(feature = "luajit")] +pub const LUA_JITLIBNAME: &str = "jit"; +#[cfg(feature = "luajit")] +pub const LUA_FFILIBNAME: &str = "ffi"; + +extern "C" { + pub fn luaopen_base(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; + pub fn luaopen_math(L: *mut lua_State) -> c_int; + pub fn luaopen_debug(L: *mut lua_State) -> c_int; + pub fn luaopen_package(L: *mut lua_State) -> c_int; + + #[cfg(feature = "luajit")] + pub fn luaopen_bit(L: *mut lua_State) -> c_int; + #[cfg(feature = "luajit")] + pub fn luaopen_jit(L: *mut lua_State) -> c_int; + #[cfg(feature = "luajit")] + pub fn luaopen_ffi(L: *mut lua_State) -> c_int; + + // open all builtin libraries + pub fn luaL_openlibs(L: *mut lua_State); +} diff --git a/src/ffi/lua51/mod.rs b/src/ffi/lua51/mod.rs new file mode 100644 index 0000000..c84fe4a --- /dev/null +++ b/src/ffi/lua51/mod.rs @@ -0,0 +1,9 @@ +//! Low level bindings to Lua 5.1. + +pub use self::lauxlib::*; +pub use self::lua::*; +pub use self::lualib::*; + +pub mod lauxlib; +pub mod lua; +pub mod lualib; diff --git a/src/ffi/lua52/lauxlib.rs b/src/ffi/lua52/lauxlib.rs new file mode 100644 index 0000000..6b16aeb --- /dev/null +++ b/src/ffi/lua52/lauxlib.rs @@ -0,0 +1,184 @@ +//! Contains definitions from `lauxlib.h`. + +use std::os::raw::{c_char, c_int, c_void}; +use std::ptr; + +use super::lua::{self, lua_CFunction, lua_Integer, lua_Number, lua_State, lua_Unsigned}; + +// Extra error code for 'luaL_load' +pub const LUA_ERRFILE: c_int = lua::LUA_ERRERR + 1; + +#[repr(C)] +pub struct luaL_Reg { + pub name: *const c_char, + pub func: lua_CFunction, +} + +extern "C" { + pub fn luaL_checkversion_(L: *mut lua_State, ver: lua_Number); + + #[link_name = "luaL_getmetafield"] + pub fn luaL_getmetafield_(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int; + pub fn luaL_callmeta(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int; + #[link_name = "luaL_tolstring"] + 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_checkunsigned(L: *mut lua_State, arg: c_int) -> lua_Unsigned; + pub fn luaL_optunsigned(L: *mut lua_State, arg: c_int, def: lua_Unsigned) -> lua_Unsigned; + + 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); + + #[link_name = "luaL_newmetatable"] + 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, ...) -> !; + + 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; +} + +// Pre-defined references +pub const LUA_NOREF: c_int = -2; +pub const LUA_REFNIL: c_int = -1; + +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#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()) +} + +extern "C" { + 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; + + pub fn luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer; + + 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); + + #[link_name = "luaL_requiref"] + 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()) +} + +// +// TODO: Generic Buffer Manipulation +// diff --git a/src/ffi/lua52/lua.rs b/src/ffi/lua52/lua.rs new file mode 100644 index 0000000..44097da --- /dev/null +++ b/src/ffi/lua52/lua.rs @@ -0,0 +1,467 @@ +//! Contains definitions from `lua.h`. + +use std::marker::{PhantomData, PhantomPinned}; +use std::os::raw::{c_char, c_double, c_int, c_uchar, c_uint, c_void}; +use std::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 +pub const LUAI_MAXSTACK: c_int = 1000000; + +// +// Pseudo-indices +// +pub const LUA_REGISTRYINDEX: c_int = -LUAI_MAXSTACK - 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_ERRGCMM: c_int = 5; +pub const LUA_ERRERR: c_int = 6; + +/// 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_NUMTAGS: c_int = 9; + +/// Minimum Lua stack available to a C function +pub const LUA_MINSTACK: c_int = 20; + +// Predefined values in the registry +pub const LUA_RIDX_MAINTHREAD: lua_Integer = 1; +pub const LUA_RIDX_GLOBALS: lua_Integer = 2; +pub const LUA_RIDX_LAST: lua_Integer = LUA_RIDX_GLOBALS; + +/// A Lua number, usually equivalent to `f64` +pub type lua_Number = c_double; + +/// A Lua integer, usually equivalent to `i64` +pub type lua_Integer = isize; + +/// A Lua unsigned integer, equivalent to `u32` in Lua 5.2 +pub type lua_Unsigned = c_uint; + +/// Type for native C functions that can be passed to Lua +pub type lua_CFunction = unsafe extern "C" fn(L: *mut lua_State) -> c_int; + +// Type for functions that read/write blocks when loading/dumping Lua chunks +pub type lua_Reader = + unsafe extern "C" fn(L: *mut lua_State, ud: *mut c_void, sz: *mut usize) -> *const c_char; +pub type lua_Writer = + unsafe extern "C" fn(L: *mut lua_State, p: *const c_void, sz: usize, ud: *mut c_void) -> c_int; + +/// Type for memory-allocation functions +pub type lua_Alloc = unsafe extern "C" fn( + ud: *mut c_void, + ptr: *mut c_void, + osize: usize, + nsize: usize, +) -> *mut c_void; + +extern "C" { + // + // State manipulation + // + pub fn lua_newstate(f: lua_Alloc, ud: *mut c_void) -> *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_atpanic(L: *mut lua_State, panicf: lua_CFunction) -> lua_CFunction; + + pub fn lua_version(L: *mut lua_State) -> *const 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_remove(L: *mut lua_State, idx: c_int); + pub fn lua_insert(L: *mut lua_State, idx: c_int); + pub fn lua_replace(L: *mut lua_State, idx: 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_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; + #[link_name = "lua_tointegerx"] + pub fn lua_tointegerx_(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Integer; + pub fn lua_tounsignedx(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Unsigned; + pub fn lua_toboolean(L: *mut lua_State, idx: c_int) -> c_int; + pub fn lua_tolstring(L: *mut lua_State, idx: c_int, len: *mut usize) -> *const c_char; + pub fn lua_rawlen(L: *mut lua_State, idx: c_int) -> usize; + 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; +} + +// +// 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_OPDIV: c_int = 3; +pub const LUA_OPMOD: c_int = 4; +pub const LUA_OPPOW: c_int = 5; +pub const LUA_OPUNM: c_int = 6; + +extern "C" { + pub fn lua_arith(L: *mut lua_State, op: c_int); +} + +pub const LUA_OPEQ: c_int = 0; +pub const LUA_OPLT: c_int = 1; +pub const LUA_OPLE: c_int = 2; + +extern "C" { + 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; +} + +extern "C" { + // + // 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_pushunsigned(L: *mut lua_State, n: lua_Unsigned); + #[link_name = "lua_pushlstring"] + pub fn lua_pushlstring_(L: *mut lua_State, s: *const c_char, l: usize) -> *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) + // + #[link_name = "lua_getglobal"] + pub fn lua_getglobal_(L: *mut lua_State, name: *const c_char); + #[link_name = "lua_gettable"] + pub fn lua_gettable_(L: *mut lua_State, idx: c_int); + #[link_name = "lua_getfield"] + pub fn lua_getfield_(L: *mut lua_State, idx: c_int, k: *const c_char); + #[link_name = "lua_rawget"] + pub fn lua_rawget_(L: *mut lua_State, idx: c_int); + #[link_name = "lua_rawgeti"] + pub fn lua_rawgeti_(L: *mut lua_State, idx: c_int, n: c_int); + #[link_name = "lua_rawgetp"] + pub fn lua_rawgetp_(L: *mut lua_State, idx: c_int, p: *const c_void); + 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; + #[link_name = "lua_getuservalue"] + pub fn lua_getuservalue_(L: *mut lua_State, idx: c_int); + + // + // Set functions (stack -> Lua) + // + 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); + pub fn lua_rawset(L: *mut lua_State, idx: c_int); + #[link_name = "lua_rawseti"] + pub fn lua_rawseti_(L: *mut lua_State, idx: c_int, n: c_int); + 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_setuservalue(L: *mut lua_State, idx: 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: c_int, + k: Option, + ); + pub fn lua_pcallk( + L: *mut lua_State, + nargs: c_int, + nresults: c_int, + errfunc: c_int, + ctx: c_int, + k: Option, + ) -> c_int; + + pub fn lua_getctx(L: *mut lua_State, ctx: *mut c_int) -> 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; + #[link_name = "lua_dump"] + pub fn lua_dump_(L: *mut lua_State, writer: lua_Writer, data: *mut c_void) -> 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) +} + +extern "C" { + // + // Coroutine functions + // + pub fn lua_yieldk( + L: *mut lua_State, + nresults: c_int, + ctx: c_int, + k: Option, + ) -> c_int; + #[link_name = "lua_resume"] + pub fn lua_resume_(L: *mut lua_State, from: *mut lua_State, narg: c_int) -> c_int; + pub fn lua_status(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) +} + +// +// Garbage-collection function and 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_GCSETPAUSE: c_int = 6; +pub const LUA_GCSETSTEPMUL: c_int = 7; +pub const LUA_GCSETMAJORINC: c_int = 8; +pub const LUA_GCISRUNNING: c_int = 9; +pub const LUA_GCGEN: c_int = 10; +pub const LUA_GCINC: c_int = 11; + +extern "C" { + pub fn lua_gc(L: *mut lua_State, what: c_int, data: c_int) -> c_int; +} + +extern "C" { + // + // Miscellaneous functions + // + 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); + pub fn lua_len(L: *mut lua_State, idx: c_int); + 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); +} + +// +// Some useful macros (implemented as Rust functions) +// +#[inline(always)] +pub unsafe fn lua_tonumber(L: *mut lua_State, i: c_int) -> lua_Number { + lua_tonumberx(L, i, ptr::null_mut()) +} + +#[inline(always)] +pub unsafe fn lua_tointeger_(L: *mut lua_State, i: c_int) -> lua_Integer { + lua_tointegerx_(L, i, ptr::null_mut()) +} + +#[inline(always)] +pub unsafe fn lua_tounsigned(L: *mut lua_State, i: c_int) -> lua_Unsigned { + lua_tounsignedx(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 str) -> *const c_char { + use std::ffi::CString; + let c_str = CString::new(s).unwrap(); + lua_pushlstring_(L, c_str.as_ptr(), c_str.as_bytes().len()) +} + +#[inline(always)] +pub unsafe fn lua_pushglobaltable(L: *mut lua_State) { + lua_rawgeti_(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS as _) +} + +#[inline(always)] +pub unsafe fn lua_tostring(L: *mut lua_State, i: c_int) -> *const c_char { + lua_tolstring(L, i, ptr::null_mut()) +} + +// +// 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" 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; + 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, + pub namewhat: *const c_char, + pub what: *const c_char, + pub source: *const c_char, + pub currentline: c_int, + pub linedefined: c_int, + pub lastlinedefined: c_int, + pub nups: c_uchar, + pub nparams: c_uchar, + pub isvararg: c_char, + pub istailcall: c_char, + pub short_src: [c_char; LUA_IDSIZE], + // lua.h mentions this is for private use + i_ci: *mut c_void, +} diff --git a/src/ffi/lua52/lualib.rs b/src/ffi/lua52/lualib.rs new file mode 100644 index 0000000..9ffba45 --- /dev/null +++ b/src/ffi/lua52/lualib.rs @@ -0,0 +1,31 @@ +//! Contains definitions from `lualib.h`. + +use std::os::raw::c_int; + +use super::lua::lua_State; + +pub const LUA_COLIBNAME: &str = "coroutine"; +pub const LUA_TABLIBNAME: &str = "table"; +pub const LUA_IOLIBNAME: &str = "io"; +pub const LUA_OSLIBNAME: &str = "os"; +pub const LUA_STRLIBNAME: &str = "string"; +pub const LUA_BITLIBNAME: &str = "bit32"; +pub const LUA_MATHLIBNAME: &str = "math"; +pub const LUA_DBLIBNAME: &str = "debug"; +pub const LUA_LOADLIBNAME: &str = "package"; + +extern "C" { + pub fn luaopen_base(L: *mut lua_State) -> c_int; + 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; + 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; + pub fn luaopen_package(L: *mut lua_State) -> c_int; + + // open all builtin libraries + pub fn luaL_openlibs(L: *mut lua_State); +} diff --git a/src/ffi/lua52/mod.rs b/src/ffi/lua52/mod.rs new file mode 100644 index 0000000..a50765d --- /dev/null +++ b/src/ffi/lua52/mod.rs @@ -0,0 +1,9 @@ +//! Low level bindings to Lua 5.2. + +pub use self::lauxlib::*; +pub use self::lua::*; +pub use self::lualib::*; + +pub mod lauxlib; +pub mod lua; +pub mod lualib; diff --git a/src/ffi/lua53/lauxlib.rs b/src/ffi/lua53/lauxlib.rs new file mode 100644 index 0000000..cc83c61 --- /dev/null +++ b/src/ffi/lua53/lauxlib.rs @@ -0,0 +1,184 @@ +//! Contains definitions from `lauxlib.h`. + +use std::os::raw::{c_char, c_int, 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: &str = "_LOADED"; + +// Key, in the registry, for table of preloaded loaders +pub const LUA_PRELOAD_TABLE: &str = "_PRELOAD"; + +#[repr(C)] +pub struct luaL_Reg { + pub name: *const c_char, + pub func: lua_CFunction, +} + +extern "C" { + 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, ...) -> !; + + 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; +} + +// Pre-defined references +pub const LUA_NOREF: c_int = -2; +pub const LUA_REFNIL: c_int = -1; + +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#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()) +} + +extern "C" { + 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; + + pub fn luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer; + + 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()) +} + +// +// TODO: Generic Buffer Manipulation +// diff --git a/src/ffi/lua53/lua.rs b/src/ffi/lua53/lua.rs new file mode 100644 index 0000000..753408c --- /dev/null +++ b/src/ffi/lua53/lua.rs @@ -0,0 +1,494 @@ +//! Contains definitions from `lua.h`. + +use std::marker::{PhantomData, PhantomPinned}; +use std::mem; +use std::os::raw::{c_char, c_double, c_int, c_uchar, c_void}; +use std::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 +pub const LUAI_MAXSTACK: c_int = 1000000; + +// 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 = -LUAI_MAXSTACK - 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_ERRGCMM: c_int = 5; +pub const LUA_ERRERR: c_int = 6; + +/// 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_NUMTAGS: c_int = 9; + +/// Minimum Lua stack available to a C function +pub const LUA_MINSTACK: c_int = 20; + +// Predefined values in the registry +pub const LUA_RIDX_MAINTHREAD: lua_Integer = 1; +pub const LUA_RIDX_GLOBALS: lua_Integer = 2; +pub const LUA_RIDX_LAST: lua_Integer = LUA_RIDX_GLOBALS; + +/// 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" fn(L: *mut lua_State) -> c_int; + +/// Type for continuation functions +pub type lua_KFunction = + unsafe extern "C" 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 +pub type lua_Reader = + unsafe extern "C" fn(L: *mut lua_State, ud: *mut c_void, sz: *mut usize) -> *const c_char; +pub type lua_Writer = + unsafe extern "C" fn(L: *mut lua_State, p: *const c_void, sz: usize, ud: *mut c_void) -> c_int; + +/// Type for memory-allocation functions +pub type lua_Alloc = unsafe extern "C" fn( + ud: *mut c_void, + ptr: *mut c_void, + osize: usize, + nsize: usize, +) -> *mut c_void; + +extern "C" { + // + // State manipulation + // + pub fn lua_newstate(f: lua_Alloc, ud: *mut c_void) -> *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_atpanic(L: *mut lua_State, panicf: lua_CFunction) -> lua_CFunction; + + pub fn lua_version(L: *mut lua_State) -> *const 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; + pub fn lua_rawlen(L: *mut lua_State, idx: c_int) -> usize; + 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; +} + +// +// 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; + +extern "C" { + pub fn lua_arith(L: *mut lua_State, op: c_int); +} + +pub const LUA_OPEQ: c_int = 0; +pub const LUA_OPLT: c_int = 1; +pub const LUA_OPLE: c_int = 2; + +extern "C" { + 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; +} + +extern "C" { + // + // 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_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_newuserdata(L: *mut lua_State, sz: usize) -> *mut c_void; + pub fn lua_getmetatable(L: *mut lua_State, objindex: c_int) -> c_int; + pub fn lua_getuservalue(L: *mut lua_State, idx: 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_setuservalue(L: *mut lua_State, idx: 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) +} + +extern "C" { + // + // Coroutine functions + // + pub fn lua_yieldk( + L: *mut lua_State, + nresults: c_int, + ctx: lua_KContext, + k: Option, + ) -> c_int; + #[link_name = "lua_resume"] + pub fn lua_resume_(L: *mut lua_State, from: *mut lua_State, narg: c_int) -> c_int; + pub fn lua_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) +} + +// +// Garbage-collection function and 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_GCSETPAUSE: c_int = 6; +pub const LUA_GCSETSTEPMUL: c_int = 7; +pub const LUA_GCISRUNNING: c_int = 9; + +extern "C" { + pub fn lua_gc(L: *mut lua_State, what: c_int, data: c_int) -> c_int; +} + +extern "C" { + // + // Miscellaneous functions + // + 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); + pub fn lua_len(L: *mut lua_State, idx: c_int); + 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); +} + +// +// 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 str) -> *const c_char { + use std::ffi::CString; + let c_str = CString::new(s).unwrap(); + lua_pushlstring(L, c_str.as_ptr(), c_str.as_bytes().len()) +} + +#[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_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) +} + +// +// 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" 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; + 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, + pub namewhat: *const c_char, + pub what: *const c_char, + pub source: *const c_char, + pub currentline: c_int, + pub linedefined: c_int, + pub lastlinedefined: c_int, + pub nups: c_uchar, + pub nparams: c_uchar, + pub isvararg: c_char, + pub istailcall: c_char, + pub short_src: [c_char; LUA_IDSIZE], + // lua.h mentions this is for private use + i_ci: *mut c_void, +} diff --git a/src/ffi/lua53/lualib.rs b/src/ffi/lua53/lualib.rs new file mode 100644 index 0000000..1cedf75 --- /dev/null +++ b/src/ffi/lua53/lualib.rs @@ -0,0 +1,33 @@ +//! Contains definitions from `lualib.h`. + +use std::os::raw::c_int; + +use super::lua::lua_State; + +pub const LUA_COLIBNAME: &str = "coroutine"; +pub const LUA_TABLIBNAME: &str = "table"; +pub const LUA_IOLIBNAME: &str = "io"; +pub const LUA_OSLIBNAME: &str = "os"; +pub const LUA_STRLIBNAME: &str = "string"; +pub const LUA_UTF8LIBNAME: &str = "utf8"; +pub const LUA_BITLIBNAME: &str = "bit32"; +pub const LUA_MATHLIBNAME: &str = "math"; +pub const LUA_DBLIBNAME: &str = "debug"; +pub const LUA_LOADLIBNAME: &str = "package"; + +extern "C" { + pub fn luaopen_base(L: *mut lua_State) -> c_int; + 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; + pub fn luaopen_utf8(L: *mut lua_State) -> c_int; + 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; + pub fn luaopen_package(L: *mut lua_State) -> c_int; + + // open all builtin libraries + pub fn luaL_openlibs(L: *mut lua_State); +} diff --git a/src/ffi/lua53/mod.rs b/src/ffi/lua53/mod.rs new file mode 100644 index 0000000..c5e07f2 --- /dev/null +++ b/src/ffi/lua53/mod.rs @@ -0,0 +1,9 @@ +//! Low level bindings to Lua 5.3. + +pub use self::lauxlib::*; +pub use self::lua::*; +pub use self::lualib::*; + +pub mod lauxlib; +pub mod lua; +pub mod lualib; diff --git a/src/ffi/lua54/lauxlib.rs b/src/ffi/lua54/lauxlib.rs new file mode 100644 index 0000000..5a6c173 --- /dev/null +++ b/src/ffi/lua54/lauxlib.rs @@ -0,0 +1,186 @@ +//! Contains definitions from `lauxlib.h`. + +use std::os::raw::{c_char, c_int, 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: &str = "_LOADED"; + +// Key, in the registry, for table of preloaded loaders +pub const LUA_PRELOAD_TABLE: &str = "_PRELOAD"; + +#[repr(C)] +pub struct luaL_Reg { + pub name: *const c_char, + pub func: lua_CFunction, +} + +extern "C" { + 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, ...) -> !; + + 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; +} + +// Pre-defined references +pub const LUA_NOREF: c_int = -2; +pub const LUA_REFNIL: c_int = -1; + +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#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()) +} + +extern "C" { + 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; + + 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()) +} + +// +// TODO: Generic Buffer Manipulation +// diff --git a/src/ffi/lua54/lua.rs b/src/ffi/lua54/lua.rs new file mode 100644 index 0000000..113f324 --- /dev/null +++ b/src/ffi/lua54/lua.rs @@ -0,0 +1,533 @@ +//! Contains definitions from `lua.h`. + +use std::marker::{PhantomData, PhantomPinned}; +use std::mem; +use std::os::raw::{c_char, c_double, c_int, c_uchar, c_ushort, c_void}; +use std::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 +pub const LUAI_MAXSTACK: c_int = 1000000; + +// 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 = -LUAI_MAXSTACK - 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 +pub const LUA_RIDX_MAINTHREAD: lua_Integer = 1; +pub const LUA_RIDX_GLOBALS: lua_Integer = 2; +pub const LUA_RIDX_LAST: lua_Integer = LUA_RIDX_GLOBALS; + +/// 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" fn(L: *mut lua_State) -> c_int; + +/// Type for continuation functions +pub type lua_KFunction = + unsafe extern "C" 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 +pub type lua_Reader = + unsafe extern "C" fn(L: *mut lua_State, ud: *mut c_void, sz: *mut usize) -> *const c_char; +pub type lua_Writer = + unsafe extern "C" fn(L: *mut lua_State, p: *const c_void, sz: usize, ud: *mut c_void) -> c_int; + +/// Type for memory-allocation functions +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" fn(ud: *mut c_void, msg: *const c_char, tocont: c_int); + +extern "C" { + // + // State manipulation + // + pub fn lua_newstate(f: lua_Alloc, ud: *mut c_void) -> *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_resetthread(L: *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; + pub fn lua_rawlen(L: *mut lua_State, idx: c_int) -> usize; + 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; +} + +// +// 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; + +extern "C" { + pub fn lua_arith(L: *mut lua_State, op: c_int); +} + +pub const LUA_OPEQ: c_int = 0; +pub const LUA_OPLT: c_int = 1; +pub const LUA_OPLE: c_int = 2; + +extern "C" { + 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; +} + +extern "C" { + // + // 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_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) +} + +extern "C" { + // + // 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 +// +extern "C" { + 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 function and 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_GCSETPAUSE: c_int = 6; +pub const LUA_GCSETSTEPMUL: c_int = 7; +pub const LUA_GCISRUNNING: c_int = 9; +pub const LUA_GCGEN: c_int = 10; +pub const LUA_GCINC: c_int = 11; + +extern "C" { + pub fn lua_gc(L: *mut lua_State, what: c_int, ...) -> c_int; +} + +extern "C" { + // + // Miscellaneous functions + // + 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); + pub fn lua_len(L: *mut lua_State, idx: c_int); + 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); +} + +// +// 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 str) -> *const c_char { + use std::ffi::CString; + let c_str = CString::new(s).unwrap(); + lua_pushlstring(L, c_str.as_ptr(), c_str.as_bytes().len()) +} + +#[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_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_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" 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; + 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, + pub namewhat: *const c_char, + pub what: *const c_char, + pub source: *const c_char, + pub srclen: usize, + pub currentline: c_int, + pub linedefined: c_int, + pub lastlinedefined: c_int, + pub nups: c_uchar, + pub nparams: c_uchar, + pub isvararg: c_char, + pub istailcall: c_char, + pub ftransfer: c_ushort, + pub ntransfer: c_ushort, + pub short_src: [c_char; LUA_IDSIZE], + // lua.h mentions this is for private use + i_ci: *mut c_void, +} diff --git a/src/ffi/lua54/lualib.rs b/src/ffi/lua54/lualib.rs new file mode 100644 index 0000000..3626004 --- /dev/null +++ b/src/ffi/lua54/lualib.rs @@ -0,0 +1,31 @@ +//! Contains definitions from `lualib.h`. + +use std::os::raw::c_int; + +use super::lua::lua_State; + +pub const LUA_COLIBNAME: &str = "coroutine"; +pub const LUA_TABLIBNAME: &str = "table"; +pub const LUA_IOLIBNAME: &str = "io"; +pub const LUA_OSLIBNAME: &str = "os"; +pub const LUA_STRLIBNAME: &str = "string"; +pub const LUA_UTF8LIBNAME: &str = "utf8"; +pub const LUA_MATHLIBNAME: &str = "math"; +pub const LUA_DBLIBNAME: &str = "debug"; +pub const LUA_LOADLIBNAME: &str = "package"; + +extern "C" { + pub fn luaopen_base(L: *mut lua_State) -> c_int; + 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; + pub fn luaopen_utf8(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; + pub fn luaopen_package(L: *mut lua_State) -> c_int; + + // open all builtin libraries + pub fn luaL_openlibs(L: *mut lua_State); +} diff --git a/src/ffi/lua54/mod.rs b/src/ffi/lua54/mod.rs new file mode 100644 index 0000000..96d61e6 --- /dev/null +++ b/src/ffi/lua54/mod.rs @@ -0,0 +1,9 @@ +//! Low level bindings to Lua 5.4. + +pub use self::lauxlib::*; +pub use self::lua::*; +pub use self::lualib::*; + +pub mod lauxlib; +pub mod lua; +pub mod lualib; diff --git a/src/ffi/luaconf.rs b/src/ffi/luaconf.rs deleted file mode 100644 index be67a75..0000000 --- a/src/ffi/luaconf.rs +++ /dev/null @@ -1,36 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2019-2021 A. Orlenko -// Copyright (c) 2014 J.C. Moyer -// -// 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. - -//! Contains definitions from `luaconf.h`. - -pub use super::glue::LUA_INTEGER; -pub use super::glue::LUA_NUMBER; -pub use super::glue::LUA_UNSIGNED; - -pub use super::glue::LUA_IDSIZE; - -#[cfg(any(feature = "lua54", feature = "lua53"))] -pub use super::glue::LUAL_NUMSIZES; - -#[cfg(any(feature = "lua54", feature = "lua53"))] -pub type LUA_KCONTEXT = isize; // intptr_t diff --git a/src/ffi/lualib.rs b/src/ffi/lualib.rs index 806fa03..9861460 100644 --- a/src/ffi/lualib.rs +++ b/src/ffi/lualib.rs @@ -1,67 +1,13 @@ -// The MIT License (MIT) -// -// Copyright (c) 2019-2021 A. Orlenko -// Copyright (c) 2014 J.C. Moyer -// -// 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. - //! Contains definitions from `lualib.h`. -use std::os::raw::c_int; +#[cfg(feature = "lua54")] +pub use super::lua54::lualib::*; -use super::lua::lua_State; +#[cfg(feature = "lua53")] +pub use super::lua53::lualib::*; -pub use super::glue::{ - LUA_COLIBNAME, LUA_DBLIBNAME, LUA_IOLIBNAME, LUA_LOADLIBNAME, LUA_MATHLIBNAME, LUA_OSLIBNAME, - LUA_STRLIBNAME, LUA_TABLIBNAME, -}; +#[cfg(feature = "lua52")] +pub use super::lua52::lualib::*; -#[cfg(any(feature = "lua54", feature = "lua53"))] -pub use super::glue::LUA_UTF8LIBNAME; - -#[cfg(any(feature = "lua52", feature = "luajit"))] -pub use super::glue::LUA_BITLIBNAME; - -#[cfg(feature = "luajit")] -pub use super::glue::{LUA_FFILIBNAME, LUA_JITLIBNAME}; - -extern "C" { - pub fn luaopen_base(L: *mut lua_State) -> c_int; - #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] - 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(any(feature = "lua54", feature = "lua53"))] - pub fn luaopen_utf8(L: *mut lua_State) -> c_int; - #[cfg(feature = "lua52")] - 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; - pub fn luaopen_package(L: *mut lua_State) -> c_int; - #[cfg(feature = "luajit")] - pub fn luaopen_bit(L: *mut lua_State) -> c_int; - #[cfg(feature = "luajit")] - pub fn luaopen_jit(L: *mut lua_State) -> c_int; - #[cfg(feature = "luajit")] - pub fn luaopen_ffi(L: *mut lua_State) -> c_int; - - pub fn luaL_openlibs(L: *mut lua_State); -} +#[cfg(any(feature = "lua51", feature = "luajit"))] +pub use super::lua51::lualib::*; diff --git a/src/ffi/luau/lua.rs b/src/ffi/luau/lua.rs new file mode 100644 index 0000000..f7d37e4 --- /dev/null +++ b/src/ffi/luau/lua.rs @@ -0,0 +1,421 @@ +//! Contains definitions from `lua.h`. + +use std::marker::{PhantomData, PhantomPinned}; +use std::os::raw::{c_char, c_double, c_float, c_int, c_uint, c_void}; +use std::ptr; + +// Option for multiple returns in 'lua_pcall' and 'lua_call' +pub const LUA_MULTRET: c_int = -1; + +// +// Pseudo-indices +// +pub const LUA_REGISTRYINDEX: c_int = -10000; +pub const LUA_ENVIRONINDEX: c_int = -10001; +pub const LUA_GLOBALSINDEX: c_int = -10002; + +pub const fn lua_upvalueindex(i: c_int) -> c_int { + LUA_GLOBALSINDEX - 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_TVECTOR: c_int = 4; + +pub const LUA_TSTRING: c_int = 5; +pub const LUA_TTABLE: c_int = 6; +pub const LUA_TFUNCTION: c_int = 7; +pub const LUA_TUSERDATA: c_int = 8; +pub const LUA_TTHREAD: c_int = 9; + +/// Guaranteed number of Lua stack slots available to a C function. +pub const LUA_MINSTACK: c_int = 20; + +/// A Lua number, usually equivalent to `f64`. +pub type lua_Number = c_double; + +/// A Lua integer, equivalent to `i32`. +pub type lua_Integer = c_int; + +/// A Lua unsigned integer, equivalent to `u32`. +pub type lua_Unsigned = c_uint; + +/// Type for native C functions that can be passed to Lua. +pub type lua_CFunction = unsafe extern "C" fn(L: *mut lua_State) -> c_int; +pub type lua_Continuation = unsafe extern "C" fn(L: *mut lua_State, status: c_int) -> c_int; + +/// Type for memory-allocation functions. +pub type lua_Alloc = unsafe extern "C" fn( + L: *mut lua_State, + ud: *mut c_void, + ptr: *mut c_void, + osize: usize, + nsize: usize, +) -> *mut c_void; + +extern "C" { + // + // State manipulation + // + pub fn lua_newstate(f: lua_Alloc, ud: *mut c_void) -> *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_mainthread(L: *mut lua_State) -> *mut lua_State; + pub fn lua_resetthread(L: *mut lua_State); + pub fn lua_isthreadreset(L: *mut lua_State) -> c_int; + + // + // 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_remove(L: *mut lua_State, idx: c_int); + pub fn lua_insert(L: *mut lua_State, idx: c_int); + pub fn lua_replace(L: *mut lua_State, idx: c_int); + pub fn lua_checkstack(L: *mut lua_State, sz: c_int) -> c_int; + pub fn lua_rawcheckstack(L: *mut lua_State, sz: c_int); + + pub fn lua_xmove(from: *mut lua_State, to: *mut lua_State, n: c_int); + pub fn lua_xpush(from: *mut lua_State, to: *mut lua_State, idx: 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_isLfunction(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_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; + pub fn lua_lessthan(L: *mut lua_State, idx1: c_int, idx2: c_int) -> c_int; + + pub fn lua_tonumberx(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Number; + pub fn lua_tointegerx(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Integer; + pub fn lua_tounsignedx(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Unsigned; + pub fn lua_tovector(L: *mut lua_State, idx: c_int) -> *const c_float; + pub fn lua_toboolean(L: *mut lua_State, idx: c_int) -> c_int; + pub fn lua_tolstring(L: *mut lua_State, idx: c_int, len: *mut usize) -> *const c_char; + pub fn lua_tostringatom(L: *mut lua_State, idx: c_int, atom: *mut c_int) -> *const c_char; + pub fn lua_namecallatom(L: *mut lua_State, atom: *mut c_int) -> *const c_char; + pub fn lua_objlen(L: *mut lua_State, idx: c_int) -> c_int; + pub fn lua_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_touserdatatagged(L: *mut lua_State, idx: c_int, tag: c_int) -> *mut c_void; + pub fn lua_userdatatag(L: *mut lua_State, idx: c_int) -> c_int; + 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; + + // + // 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_pushunsigned(L: *mut lua_State, n: lua_Unsigned); + pub fn lua_pushvector(L: *mut lua_State, x: c_float, y: c_float, z: c_float); + pub fn lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize); + pub fn lua_pushstring(L: *mut lua_State, s: *const c_char); + // lua_pushvfstring + #[link_name = "lua_pushfstringL"] + pub fn lua_pushfstring(L: *mut lua_State, fmt: *const c_char, ...) -> *const c_char; + pub fn lua_pushcclosurek( + L: *mut lua_State, + f: lua_CFunction, + debugname: *const c_char, + nup: c_int, + cont: Option, + ); + 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_gettable(L: *mut lua_State, idx: c_int); + pub fn lua_getfield(L: *mut lua_State, idx: c_int, k: *const c_char); + pub fn lua_rawgetfield(L: *mut lua_State, idx: c_int, k: *const c_char); + pub fn lua_rawget(L: *mut lua_State, idx: c_int); + pub fn lua_rawgeti(L: *mut lua_State, idx: c_int, n: c_int); + pub fn lua_createtable(L: *mut lua_State, narr: c_int, nrec: c_int); + + pub fn lua_setreadonly(L: *mut lua_State, idx: c_int, enabled: c_int); + pub fn lua_getreadonly(L: *mut lua_State, idx: c_int) -> c_int; + pub fn lua_setsafeenv(L: *mut lua_State, idx: c_int, enabled: c_int); + + pub fn lua_newuserdatatagged(L: *mut lua_State, sz: usize, tag: c_int) -> *mut c_void; + pub fn lua_newuserdatadtor(L: *mut lua_State, sz: usize, dtor: fn(*mut c_void)); + pub fn lua_getmetatable(L: *mut lua_State, objindex: c_int) -> c_int; + pub fn lua_getfenv(L: *mut lua_State, idx: c_int); + + // + // Set functions (stack -> Lua) + // + pub fn lua_settable(L: *mut lua_State, idx: c_int); + pub fn lua_setfield(L: *mut lua_State, idx: c_int, k: *const c_char); + pub fn lua_rawset(L: *mut lua_State, idx: c_int); + pub fn lua_rawseti(L: *mut lua_State, idx: c_int, n: c_int); + pub fn lua_setmetatable(L: *mut lua_State, objindex: c_int) -> c_int; + pub fn lua_setfenv(L: *mut lua_State, idx: c_int) -> c_int; + + // + // `load' and `call' functions (load and run Luau bytecode) + // + pub fn luau_load( + L: *mut lua_State, + chunkname: *const c_char, + data: *const c_char, + size: usize, + env: c_int, + ) -> c_int; + pub fn lua_call(L: *mut lua_State, nargs: c_int, nresults: c_int); + pub fn lua_pcall(L: *mut lua_State, nargs: c_int, nresults: c_int, errfunc: c_int) -> c_int; + + // + // Coroutine functions + // + pub fn lua_yield(L: *mut lua_State, nresults: c_int) -> c_int; + pub fn lua_break(L: *mut lua_State) -> c_int; + pub fn lua_resume(L: *mut lua_State, from: *mut lua_State, narg: c_int) -> c_int; + pub fn lua_resumeerror(L: *mut lua_State, from: *mut lua_State) -> c_int; + pub fn lua_status(L: *mut lua_State) -> c_int; + pub fn lua_isyieldable(L: *mut lua_State) -> c_int; + pub fn lua_getthreaddata(L: *mut lua_State) -> *mut c_void; + pub fn lua_setthreaddata(L: *mut lua_State, data: *mut c_void); +} + +// +// Garbage-collection function and 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_GCISRUNNING: c_int = 5; +pub const LUA_GCSTEP: c_int = 6; +pub const LUA_GCSETGOAL: c_int = 7; +pub const LUA_GCSETSTEPMUL: c_int = 8; +pub const LUA_GCSETSTEPSIZE: c_int = 9; + +extern "C" { + pub fn lua_gc(L: *mut lua_State, what: c_int, data: c_int) -> c_int; +} + +// +// Miscellaneous functions +// +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); + // TODO: lua_encodepointer, lua_clock + pub fn lua_setuserdatadtor(L: *mut lua_State, tag: c_int, dtor: fn(*mut c_void)); +} + +// +// Reference system, can be used to pin objects +// +pub const LUA_NOREF: c_int = -1; +pub const LUA_REFNIL: c_int = 0; + +extern "C" { + pub fn lua_ref(L: *mut lua_State, idx: c_int) -> c_int; + pub fn lua_unref(L: *mut lua_State, r#ref: c_int); +} + +// +// Some useful macros (implemented as Rust functions) +// +#[inline(always)] +pub unsafe fn lua_tonumber(L: *mut lua_State, i: c_int) -> lua_Number { + lua_tonumberx(L, i, ptr::null_mut()) +} + +#[inline(always)] +pub unsafe fn lua_tointeger(L: *mut lua_State, i: c_int) -> lua_Integer { + lua_tointegerx(L, i, ptr::null_mut()) +} + +#[inline(always)] +pub unsafe fn lua_tounsigned(L: *mut lua_State, i: c_int) -> lua_Unsigned { + lua_tounsignedx(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_newuserdata(L: *mut lua_State, sz: usize) -> *mut c_void { + lua_newuserdatatagged(L, sz, 0) +} + +// TODO: lua_strlen + +#[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_isvector(L: *mut lua_State, n: c_int) -> c_int { + (lua_type(L, n) == LUA_TVECTOR) 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) <= LUA_TNIL) as c_int +} + +#[inline(always)] +pub unsafe fn lua_pushliteral(L: *mut lua_State, s: &'static str) { + use std::ffi::CString; + let c_str = CString::new(s).unwrap(); + lua_pushlstring(L, c_str.as_ptr(), c_str.as_bytes().len()) +} + +pub unsafe fn lua_pushcfunction(L: *mut lua_State, f: lua_CFunction, debugname: *const c_char) { + lua_pushcclosurek(L, f, debugname, 0, None) +} + +pub unsafe fn lua_pushcclosure( + L: *mut lua_State, + f: lua_CFunction, + debugname: *const c_char, + nup: c_int, +) { + lua_pushcclosurek(L, f, debugname, nup, None) +} + +#[inline(always)] +pub unsafe fn lua_setglobal(L: *mut lua_State, var: *const c_char) { + lua_setfield(L, LUA_GLOBALSINDEX, var) +} + +#[inline(always)] +pub unsafe fn lua_getglobal(L: *mut lua_State, var: *const c_char) { + lua_getfield(L, LUA_GLOBALSINDEX, var) +} + +#[inline(always)] +pub unsafe fn lua_tostring(L: *mut lua_State, i: c_int) -> *const c_char { + lua_tolstring(L, i, ptr::null_mut()) +} + +// +// Debug API +// + +// Maximum size for the description of the source of a function in debug information. +const LUA_IDSIZE: usize = 256; + +/// Type for functions to be called on debug events. +pub type lua_Hook = unsafe extern "C" fn(L: *mut lua_State, ar: *mut lua_Debug); + +extern "C" { + pub fn lua_getinfo( + L: *mut lua_State, + level: c_int, + what: *const c_char, + ar: *mut lua_Debug, + ) -> c_int; + pub fn lua_getargument(L: *mut lua_State, level: c_int, n: c_int) -> c_int; + pub fn lua_getlocal(L: *mut lua_State, level: c_int, n: c_int) -> *const c_char; + pub fn lua_setlocal(L: *mut lua_State, level: c_int, 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_singlestep(L: *mut lua_State, enabled: c_int); + pub fn lua_breakpoint(L: *mut lua_State, funcindex: c_int, line: c_int, enabled: c_int); + + // TODO: lua_Coverage, lua_getcoverage +} + +#[repr(C)] +pub struct lua_Debug { + pub name: *const c_char, + pub what: *const c_char, + pub source: *const c_char, + pub linedefined: c_int, + pub currentline: c_int, + pub nupvals: u8, + pub nparams: u8, + pub isvararg: c_char, + pub short_src: [c_char; LUA_IDSIZE], + pub userdata: *mut c_void, +} + +// +// Callbacks that can be used to reconfigure behavior of the VM dynamically. +// These are shared between all coroutines. +// + +// TODO: lua_Callbacks, lua_callbacks diff --git a/src/ffi/luau/lualib.rs b/src/ffi/luau/lualib.rs new file mode 100644 index 0000000..bde8a29 --- /dev/null +++ b/src/ffi/luau/lualib.rs @@ -0,0 +1,113 @@ +//! Contains definitions from `lualib.h`. + +use std::os::raw::{c_char, c_float, c_int, c_void}; + +use super::lua::{ + lua_CFunction, lua_Integer, lua_Number, lua_State, lua_Unsigned, lua_getfield, + LUA_REGISTRYINDEX, +}; + +#[repr(C)] +pub struct luaL_Reg { + pub name: *const c_char, + pub func: lua_CFunction, +} + +extern "C" { + pub fn luaL_register(L: *mut lua_State, libname: *const c_char, l: *const luaL_Reg); + pub fn luaL_getmetafield(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int; + pub fn luaL_callmeta(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int; + // TODO: luaL_typeerrorL, luaL_argerrorL + pub fn luaL_checklstring(L: *mut lua_State, narg: c_int, l: *mut usize) -> *const c_char; + pub fn luaL_optlstring( + L: *mut lua_State, + narg: c_int, + def: *const c_char, + l: *mut usize, + ) -> *const c_char; + pub fn luaL_checknumber(L: *mut lua_State, narg: c_int) -> lua_Number; + pub fn luaL_optnumber(L: *mut lua_State, narg: c_int, def: lua_Number) -> lua_Number; + + pub fn luaL_checkboolean(L: *mut lua_State, narg: c_int) -> c_int; + pub fn luaL_optboolean(L: *mut lua_State, narg: c_int, def: c_int) -> c_int; + + pub fn luaL_checkinteger(L: *mut lua_State, narg: c_int) -> lua_Integer; + pub fn luaL_optinteger(L: *mut lua_State, narg: c_int, def: lua_Integer) -> lua_Integer; + pub fn luaL_checkunsigned(L: *mut lua_State, narg: c_int) -> lua_Unsigned; + pub fn luaL_optunsigned(L: *mut lua_State, narg: c_int, def: lua_Unsigned) -> lua_Unsigned; + + pub fn luaL_checkvector(L: *mut lua_State, narg: c_int) -> *const c_float; + pub fn luaL_optvector(L: *mut lua_State, narg: c_int, def: *const c_float) -> *const c_float; + + pub fn luaL_checkstack(L: *mut lua_State, sz: c_int, msg: *const c_char); + pub fn luaL_checktype(L: *mut lua_State, narg: c_int, t: c_int); + pub fn luaL_checkany(L: *mut lua_State, narg: c_int); + + pub fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_int; + pub fn luaL_checkudata(L: *mut lua_State, ud: c_int, tname: *const c_char) -> *mut c_void; + + pub fn luaL_where(L: *mut lua_State, lvl: c_int); + + #[link_name = "luaL_errorL"] + pub fn luaL_error(L: *mut lua_State, fmt: *const c_char, ...) -> !; + + pub fn luaL_checkoption( + L: *mut lua_State, + narg: c_int, + def: *const c_char, + lst: *const *const c_char, + ) -> c_int; + + pub fn luaL_tolstring(L: *mut lua_State, idx: c_int, len: *mut usize) -> *const c_char; + + pub fn luaL_newstate() -> *mut lua_State; + + // TODO: luaL_findtable +} + +// +// Some useful macros (implemented as Rust functions) +// + +// TODO: luaL_argcheck, luaL_argexpected, luaL_checkstring, luaL_optstring, luaL_typename, luaL_opt + +#[inline(always)] +pub unsafe fn luaL_getmetatable(L: *mut lua_State, n: *const c_char) { + lua_getfield(L, LUA_REGISTRYINDEX, n); +} + +// +// TODO: Generic Buffer Manipulation +// + +// +// Builtin libraries +// + +pub const LUA_COLIBNAME: &str = "coroutine"; +pub const LUA_TABLIBNAME: &str = "table"; +pub const LUA_OSLIBNAME: &str = "os"; +pub const LUA_STRLIBNAME: &str = "string"; +pub const LUA_BITLIBNAME: &str = "bit32"; +pub const LUA_UTF8LIBNAME: &str = "utf8"; +pub const LUA_MATHLIBNAME: &str = "math"; +pub const LUA_DBLIBNAME: &str = "debug"; + +extern "C" { + pub fn luaopen_base(L: *mut lua_State) -> c_int; + pub fn luaopen_coroutine(L: *mut lua_State) -> c_int; + pub fn luaopen_table(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_bit32(L: *mut lua_State) -> c_int; + pub fn luaopen_utf8(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; + + // open all builtin libraries + pub fn luaL_openlibs(L: *mut lua_State); + + // sandbox libraries and globals + pub fn luaL_sandbox(L: *mut lua_State); + pub fn luaL_sandboxthread(L: *mut lua_State); +} diff --git a/src/ffi/luau/mod.rs b/src/ffi/luau/mod.rs new file mode 100644 index 0000000..bbdb276 --- /dev/null +++ b/src/ffi/luau/mod.rs @@ -0,0 +1,7 @@ +//! Low level bindings to Luau. + +pub use self::lua::*; +pub use self::lualib::*; + +pub mod lua; +pub mod lualib; diff --git a/src/ffi/mod.rs b/src/ffi/mod.rs index 0f49697..9f88188 100644 --- a/src/ffi/mod.rs +++ b/src/ffi/mod.rs @@ -1,265 +1,13 @@ -// The MIT License (MIT) -// -// Copyright (c) 2019-2021 A. Orlenko -// Copyright (c) 2014 J.C. Moyer -// -// 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. - -//! Low level bindings to Lua. +//! Low level bindings to Lua 5.4/5.3/5.2/5.1 including LuaJIT. #![allow(non_camel_case_types, non_snake_case, dead_code)] -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. - -// C API types -pub use self::lua::{ - lua_Alloc, lua_CFunction, lua_Debug, lua_Hook, lua_Integer, lua_Number, lua_Reader, lua_State, - lua_Unsigned, lua_Writer, -}; - -#[cfg(feature = "lua54")] -pub use self::lua::lua_WarnFunction; - -#[cfg(any(feature = "lua54", feature = "lua53"))] -pub use self::lua::{lua_KContext, lua_KFunction}; - -#[cfg(any(feature = "lua51", feature = "luajit"))] -pub use self::lua::{lua_getfenv, lua_setfenv}; - -// C API functions -pub use self::lua::{ - lua_absindex, - lua_arith, - lua_atpanic, - lua_call, - lua_checkstack, - lua_close, - lua_compare, - lua_concat, - lua_copy, - lua_createtable, - lua_dump, - lua_error, - lua_gc, - lua_getallocf, - lua_getextraspace, - lua_getfield, - lua_getglobal, - lua_gethook, - lua_gethookcount, - lua_gethookmask, - lua_geti, - lua_getinfo, - lua_getlocal, - lua_getmetatable, - lua_getstack, - lua_gettable, - lua_gettop, - lua_getupvalue, - lua_getuservalue, - lua_insert, - lua_isboolean, - lua_iscfunction, - lua_isfunction, - lua_isinteger, - lua_islightuserdata, - lua_isnil, - lua_isnone, - lua_isnoneornil, - lua_isnumber, - lua_isstring, - lua_istable, - lua_isthread, - lua_isuserdata, - lua_len, - lua_load, - lua_newstate, - lua_newtable, - lua_newthread, - lua_newuserdata, - lua_next, - lua_pcall, - lua_pop, - lua_pushboolean, - lua_pushcclosure, - lua_pushcfunction, - lua_pushfstring, - lua_pushglobaltable, - lua_pushinteger, - lua_pushlightuserdata, - lua_pushliteral, - lua_pushlstring, - lua_pushnil, - lua_pushnumber, - lua_pushstring, - lua_pushthread, - lua_pushvalue, - // omitted: lua_pushvfstring - lua_rawequal, - lua_rawget, - lua_rawgeti, - lua_rawgetp, - lua_rawlen, - lua_rawset, - lua_rawseti, - lua_rawsetp, - lua_register, - lua_remove, - lua_replace, - lua_resume, - lua_rotate, - lua_setallocf, - lua_setfield, - lua_setglobal, - lua_sethook, - lua_seti, - lua_setlocal, - lua_setmetatable, - lua_settable, - lua_settop, - lua_setupvalue, - lua_setuservalue, - lua_status, - lua_stringtonumber, - lua_toboolean, - lua_tocfunction, - lua_tointeger, - lua_tointegerx, - lua_tolstring, - lua_tonumber, - lua_tonumberx, - lua_topointer, - lua_tostring, - lua_tothread, - lua_touserdata, - lua_type, - lua_typename, - lua_upvalueindex, - lua_xmove, - lua_yield, -}; - -#[cfg(feature = "lua54")] -pub use self::lua::{ - lua_getiuservalue, lua_newuserdatauv, lua_setcstacklimit, lua_setiuservalue, lua_setwarnf, - lua_toclose, lua_warning, -}; - -#[cfg(any(feature = "lua54", feature = "lua53"))] -pub use self::lua::{lua_isyieldable, lua_version}; - -#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] -pub use self::lua::{lua_callk, lua_pcallk, lua_upvalueid, lua_upvaluejoin, lua_yieldk}; - -#[cfg(any(feature = "lua54", all(feature = "luajit", feature = "vendored")))] -pub use self::lua::lua_resetthread; - -// auxiliary library types -pub use self::lauxlib::luaL_Reg; - -// auxiliary library functions -pub use self::lauxlib::{ - 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_checkversion, 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_ref, luaL_requiref, luaL_setfuncs, - luaL_setmetatable, luaL_testudata, luaL_tolstring, luaL_traceback, luaL_typename, luaL_unref, - luaL_where, -}; - -#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] -pub use self::lauxlib::{luaL_execresult, luaL_fileresult, luaL_loadfilex}; - -// lualib.h functions -pub use self::lualib::{ - luaL_openlibs, luaopen_base, luaopen_debug, luaopen_io, luaopen_math, luaopen_os, - luaopen_package, luaopen_string, luaopen_table, -}; - -#[cfg(any(feature = "lua54", feature = "lua53"))] -pub use self::lualib::{luaopen_coroutine, luaopen_utf8}; - -#[cfg(feature = "lua52")] -pub use self::lualib::{luaopen_bit32, luaopen_coroutine}; - -#[cfg(feature = "luajit")] -pub use self::lualib::{luaopen_bit, luaopen_ffi, luaopen_jit}; - -// constants from lua.h -pub use self::lua::{ - 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_OPADD, LUA_OPDIV, LUA_OPEQ, - LUA_OPLE, LUA_OPLT, LUA_OPMOD, LUA_OPMUL, LUA_OPPOW, LUA_OPSUB, LUA_OPUNM, LUA_REGISTRYINDEX, - LUA_SIGNATURE, LUA_TBOOLEAN, LUA_TFUNCTION, LUA_TLIGHTUSERDATA, LUA_TNIL, LUA_TNONE, - LUA_TNUMBER, LUA_TRACEBACK_STACK, LUA_TSTRING, LUA_TTABLE, LUA_TTHREAD, LUA_TUSERDATA, - LUA_YIELD, -}; - -#[cfg(any(feature = "lua54", feature = "lua53"))] -pub use self::lua::{ - LUA_OPBAND, LUA_OPBNOT, LUA_OPBOR, LUA_OPBXOR, LUA_OPIDIV, LUA_OPSHL, LUA_OPSHR, -}; - -#[cfg(feature = "lua54")] -pub use self::lua::{LUA_GCGEN, LUA_GCINC}; - -#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] -pub use self::lua::{LUA_GCISRUNNING, LUA_RIDX_GLOBALS, LUA_RIDX_MAINTHREAD}; - -#[cfg(any(feature = "lua53", feature = "lua52"))] -pub use self::lua::LUA_ERRGCMM; - -#[cfg(any(feature = "lua51", feature = "luajit"))] -pub use self::lua::{LUA_ENVIRONINDEX, LUA_GLOBALSINDEX}; - -#[cfg(feature = "luajit")] -pub use self::lua::LUA_TCDATA; - -// constants from lauxlib.h -pub use self::lauxlib::{LUA_ERRFILE, LUA_NOREF, LUA_REFNIL}; - -// constants from lualib.h -pub use self::lualib::{ - LUA_COLIBNAME, LUA_DBLIBNAME, LUA_IOLIBNAME, LUA_LOADLIBNAME, LUA_MATHLIBNAME, LUA_OSLIBNAME, - LUA_STRLIBNAME, LUA_TABLIBNAME, -}; - -#[cfg(any(feature = "lua54", feature = "lua53"))] -pub use self::lualib::LUA_UTF8LIBNAME; - -#[cfg(any(feature = "lua52", feature = "luajit"))] -pub use self::lualib::LUA_BITLIBNAME; - -#[cfg(feature = "luajit")] -pub use self::lualib::{LUA_FFILIBNAME, LUA_JITLIBNAME}; - -// Not actually defined in lua.h / luaconf.h -pub const LUA_MAX_UPVALUES: c_int = 255; +pub use lauxlib::*; +pub use lua::*; +pub use lualib::*; +// The minimum alignment guaranteed by the architecture. This value is used to +// add fast paths for low alignment values. // Copied from https://github.com/rust-lang/rust/blob/master/library/std/src/sys/common/alloc.rs #[cfg(all(any( target_arch = "x86", @@ -271,7 +19,8 @@ pub const LUA_MAX_UPVALUES: c_int = 255; target_arch = "asmjs", target_arch = "wasm32", target_arch = "hexagon", - target_arch = "riscv32" + all(target_arch = "riscv32", not(target_os = "espidf")), + all(target_arch = "xtensa", not(target_os = "espidf")), )))] pub const SYS_MIN_ALIGN: usize = 8; #[cfg(all(any( @@ -280,9 +29,16 @@ pub const SYS_MIN_ALIGN: usize = 8; target_arch = "mips64", target_arch = "s390x", target_arch = "sparc64", - target_arch = "riscv64" + target_arch = "riscv64", + target_arch = "wasm64", )))] pub const SYS_MIN_ALIGN: usize = 16; +// The allocator on the esp-idf platform guarentees 4 byte alignment. +#[cfg(all(any( + all(target_arch = "riscv32", target_os = "espidf"), + all(target_arch = "xtensa", target_os = "espidf"), +)))] +pub const SYS_MIN_ALIGN: usize = 4; // Hack to avoid stripping a few unused Lua symbols that could be imported // by C modules in unsafe mode @@ -293,26 +49,24 @@ pub(crate) fn keep_lua_symbols() { symbols.push(lua_tocfunction as _); symbols.push(luaL_loadstring as _); symbols.push(luaL_openlibs as _); - if cfg!(any(any( - feature = "lua54", - feature = "lua53", - feature = "lua52" - ))) { + if cfg!(any(feature = "lua54", feature = "lua53", feature = "lua52")) { symbols.push(lua_getglobal as _); symbols.push(lua_setglobal as _); } } -#[allow(unused_imports, dead_code, non_camel_case_types)] -#[allow(clippy::unreadable_literal)] -mod glue { - include!(concat!(env!("OUT_DIR"), "/glue.rs")); -} +mod lauxlib; +mod lua; +mod lualib; #[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))] mod compat53; -mod lauxlib; -mod lua; -mod luaconf; -mod lualib; +#[cfg(any(feature = "lua51", feature = "luajit"))] +pub mod lua51; +#[cfg(feature = "lua52")] +pub mod lua52; +#[cfg(feature = "lua53")] +pub mod lua53; +#[cfg(feature = "lua54")] +pub mod lua54; diff --git a/src/lua.rs b/src/lua.rs index e8d0204..c4a539c 100644 --- a/src/lua.rs +++ b/src/lua.rs @@ -1453,7 +1453,7 @@ impl Lua { let extra = &mut *self.extra.get(); let thread_state = ffi::lua_tothread(extra.ref_thread, thread.0.index); if extra.recycled_thread_cache.len() < extra.recycled_thread_cache.capacity() - && ffi::lua_resetthread(self.state, thread_state) == ffi::LUA_OK + && ffi::lua_resetthreadx(self.state, thread_state) == ffi::LUA_OK { extra.recycled_thread_cache.push(thread.0.index); thread.0.index = 0; diff --git a/src/serde/de.rs b/src/serde/de.rs index 437de1d..be6e114 100644 --- a/src/serde/de.rs +++ b/src/serde/de.rs @@ -1,4 +1,5 @@ use std::cell::RefCell; +use std::convert::TryInto; use std::os::raw::c_void; use std::rc::Rc; use std::string::String as StdString; @@ -117,7 +118,9 @@ impl<'lua, 'de> serde::Deserializer<'de> for Deserializer<'lua> { Value::Nil => visitor.visit_unit(), Value::Boolean(b) => visitor.visit_bool(b), #[allow(clippy::useless_conversion)] - Value::Integer(i) => visitor.visit_i64(i.into()), + Value::Integer(i) => { + visitor.visit_i64(i.try_into().expect("cannot convert lua_Integer to i64")) + } #[allow(clippy::useless_conversion)] Value::Number(n) => visitor.visit_f64(n.into()), Value::String(s) => match s.to_str() { diff --git a/src/thread.rs b/src/thread.rs index e805562..f4445a0 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -192,7 +192,7 @@ impl<'lua> Thread<'lua> { lua.push_ref(&self.0); let thread_state = ffi::lua_tothread(lua.state, -1); - let ret = ffi::lua_resetthread(lua.state, thread_state); + let ret = ffi::lua_resetthreadx(lua.state, thread_state); if ret != ffi::LUA_OK { return Err(pop_error(thread_state, ret)); } diff --git a/src/value.rs b/src/value.rs index eefbf8a..290cd4e 100644 --- a/src/value.rs +++ b/src/value.rs @@ -4,6 +4,7 @@ use std::{slice, str, vec}; #[cfg(feature = "serialize")] use { serde::ser::{self, Serialize, Serializer}, + std::convert::TryInto, std::result::Result as StdResult, }; @@ -125,9 +126,10 @@ impl<'lua> Serialize for Value<'lua> { Value::Nil => serializer.serialize_unit(), Value::Boolean(b) => serializer.serialize_bool(*b), #[allow(clippy::useless_conversion)] - Value::Integer(i) => serializer.serialize_i64((*i).into()), + Value::Integer(i) => serializer + .serialize_i64((*i).try_into().expect("cannot convert lua_Integer to i64")), #[allow(clippy::useless_conversion)] - Value::Number(n) => serializer.serialize_f64((*n).into()), + Value::Number(n) => serializer.serialize_f64(*n), Value::String(s) => s.serialize(serializer), Value::Table(t) => t.serialize(serializer), Value::UserData(ud) => ud.serialize(serializer), diff --git a/tests/async.rs b/tests/async.rs index 77bc576..dead884 100644 --- a/tests/async.rs +++ b/tests/async.rs @@ -13,8 +13,8 @@ use futures_timer::Delay; use futures_util::stream::TryStreamExt; use mlua::{ - Error, ExternalError, Function, Lua, LuaOptions, MetaMethod, Result, StdLib, Table, TableExt, - Thread, ToLua, UserData, UserDataMethods, Value, + Error, ExternalError, Function, Lua, LuaOptions, Result, StdLib, Table, TableExt, Thread, + ToLua, UserData, UserDataMethods, Value, }; #[tokio::test] @@ -300,7 +300,7 @@ async fn test_async_userdata() -> Result<()> { }); #[cfg(not(feature = "lua51"))] - methods.add_async_meta_method(MetaMethod::Call, |_, data, ()| async move { + methods.add_async_meta_method(mlua::MetaMethod::Call, |_, data, ()| async move { let n = data.0.load(Ordering::Relaxed); Delay::new(Duration::from_millis(n)).await; Ok(format!("elapsed:{}ms", n))