diff --git a/.gitignore b/.gitignore index 4308d82..5c21d7d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ target/ **/*.rs.bk Cargo.lock + +.vscode/ +.DS_Store diff --git a/Cargo.toml b/Cargo.toml index e07eed1..8f380b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,8 @@ num-traits = { version = "0.2.6" } compiletest_rs = { version = "0.3", optional = true } [build-dependencies] -pkg-config = "0.3" +cc = "1.0" +pkg-config = "0.3.11" [dev-dependencies] rustyline = "2.0.0" diff --git a/build.rs b/build.rs index eac2634..6093ea0 100644 --- a/build.rs +++ b/build.rs @@ -1,8 +1,56 @@ -extern crate pkg_config; +use std::io; +use std::env; +use std::path::PathBuf; +use std::process::Command; + +trait CommandExt { + fn execute(&mut self) -> io::Result<()>; +} + +impl CommandExt for Command { + /// Execute the command and return an error if it exited with a failure status. + fn execute(&mut self) -> io::Result<()> { + self.status() + .map(|_| ()) + .map_err(|_| { + io::Error::new(io::ErrorKind::Other, format!("The command\n\ + \t{:?}\n\ + did not run successfully.", self)) + }) + } +} fn main() { - pkg_config::Config::new() - .atleast_version("5.3") + let lua = pkg_config::Config::new() + .atleast_version("5.1") .probe("lua") .unwrap(); + + let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + + // Ensure the presence of glue.rs + if !build_dir.join("glue.rs").exists() { + let mut config = cc::Build::new(); + + for path in lua.include_paths { + config.include(path); + } + for (k, v) in lua.defines { + config.define(&k, v.as_ref().map(|x| x.as_str())); + } + + // 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(); + } } diff --git a/src/ffi.rs b/src/ffi.rs deleted file mode 100644 index dd435c4..0000000 --- a/src/ffi.rs +++ /dev/null @@ -1,328 +0,0 @@ -#![allow(non_camel_case_types)] -#![allow(non_snake_case)] -#![allow(unused)] - -use std::mem; -use std::os::raw::{c_char, c_double, c_int, c_longlong, c_uchar, c_void}; -use std::ptr; - -pub type lua_Integer = c_longlong; -pub type lua_Number = c_double; - -pub enum lua_State {} -pub type lua_Alloc = - unsafe extern "C" fn(ud: *mut c_void, ptr: *mut c_void, osize: usize, nsize: usize) - -> *mut c_void; -pub type lua_KContext = *mut c_void; -pub type lua_KFunction = - unsafe extern "C" fn(state: *mut lua_State, status: c_int, ctx: lua_KContext) -> c_int; -pub type lua_CFunction = unsafe extern "C" fn(state: *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 as usize], - i_ci: *mut c_void, -} - -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; - -pub const LUA_NOREF: c_int = -2; -pub const LUA_REFNIL: c_int = -1; - -pub const LUA_MULTRET: c_int = -1; -pub const LUAI_MAXSTACK: c_int = 1_000_000; -pub const LUA_REGISTRYINDEX: c_int = -LUAI_MAXSTACK - 1000; -pub const LUA_RIDX_MAINTHREAD: lua_Integer = 1; -pub const LUA_RIDX_GLOBALS: lua_Integer = 2; -pub const LUA_IDSIZE: c_int = 60; -pub const LUA_MINSTACK: c_int = 20; -// Not actually defined in lua.h / luaconf.h -pub const LUA_MAX_UPVALUES: c_int = 255; - -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_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_newstate(alloc: lua_Alloc, ud: *mut c_void) -> *mut lua_State; - pub fn lua_close(state: *mut lua_State); - - pub fn lua_callk( - state: *mut lua_State, - nargs: c_int, - nresults: c_int, - ctx: lua_KContext, - k: Option, - ); - pub fn lua_pcallk( - state: *mut lua_State, - nargs: c_int, - nresults: c_int, - msgh: c_int, - ctx: lua_KContext, - k: Option, - ) -> c_int; - pub fn lua_resume(state: *mut lua_State, from: *mut lua_State, nargs: c_int) -> c_int; - pub fn lua_status(state: *mut lua_State) -> c_int; - - pub fn lua_pushnil(state: *mut lua_State); - pub fn lua_pushvalue(state: *mut lua_State, index: c_int); - pub fn lua_pushboolean(state: *mut lua_State, b: c_int); - pub fn lua_pushinteger(state: *mut lua_State, n: lua_Integer); - pub fn lua_pushnumber(state: *mut lua_State, n: lua_Number); - pub fn lua_pushlstring(state: *mut lua_State, s: *const c_char, len: usize) -> *const c_char; - pub fn lua_pushstring(state: *mut lua_State, s: *const c_char) -> *const c_char; - pub fn lua_pushlightuserdata(state: *mut lua_State, data: *mut c_void); - pub fn lua_pushcclosure(state: *mut lua_State, function: lua_CFunction, n: c_int); - - pub fn lua_tointegerx(state: *mut lua_State, index: c_int, isnum: *mut c_int) -> lua_Integer; - pub fn lua_tolstring(state: *mut lua_State, index: c_int, len: *mut usize) -> *const c_char; - pub fn lua_toboolean(state: *mut lua_State, index: c_int) -> c_int; - pub fn lua_tonumberx(state: *mut lua_State, index: c_int, isnum: *mut c_int) -> lua_Number; - pub fn lua_touserdata(state: *mut lua_State, index: c_int) -> *mut c_void; - pub fn lua_tothread(state: *mut lua_State, index: c_int) -> *mut lua_State; - - pub fn lua_gettop(state: *const lua_State) -> c_int; - pub fn lua_settop(state: *mut lua_State, n: c_int); - pub fn lua_checkstack(state: *mut lua_State, n: c_int) -> c_int; - pub fn lua_rotate(state: *mut lua_State, index: c_int, n: c_int); - pub fn lua_copy(state: *mut lua_State, from: c_int, to: c_int); - pub fn lua_absindex(state: *mut lua_State, index: c_int) -> c_int; - pub fn lua_xmove(from: *mut lua_State, to: *mut lua_State, n: c_int); - - pub fn lua_isinteger(state: *mut lua_State, index: c_int) -> c_int; - pub fn lua_isnumber(state: *mut lua_State, index: c_int) -> c_int; - pub fn lua_isstring(state: *mut lua_State, index: c_int) -> c_int; - pub fn lua_iscfunction(state: *mut lua_State, index: c_int) -> c_int; - pub fn lua_isuserdata(state: *mut lua_State, index: c_int) -> c_int; - pub fn lua_type(state: *mut lua_State, index: c_int) -> c_int; - - pub fn lua_gettable(state: *mut lua_State, index: c_int) -> c_int; - pub fn lua_geti(state: *mut lua_State, index: c_int, i: lua_Integer) -> c_int; - pub fn lua_rawget(state: *mut lua_State, index: c_int) -> c_int; - pub fn lua_rawgeti(state: *mut lua_State, index: c_int, n: lua_Integer) -> c_int; - pub fn lua_rawseti(state: *mut lua_State, index: c_int, n: lua_Integer); - pub fn lua_getmetatable(state: *mut lua_State, index: c_int) -> c_int; - - pub fn lua_createtable(state: *mut lua_State, narr: c_int, nrec: c_int); - pub fn lua_newuserdata(state: *mut lua_State, size: usize) -> *mut c_void; - pub fn lua_newthread(state: *mut lua_State) -> *mut lua_State; - - pub fn lua_setuservalue(state: *mut lua_State, index: c_int); - pub fn lua_getuservalue(state: *mut lua_State, index: c_int) -> c_int; - - pub fn lua_getupvalue(state: *mut lua_State, funcindex: c_int, n: c_int) -> *const c_char; - pub fn lua_setupvalue(state: *mut lua_State, funcindex: c_int, n: c_int) -> *const c_char; - - pub fn lua_settable(state: *mut lua_State, index: c_int); - pub fn lua_rawset(state: *mut lua_State, index: c_int); - pub fn lua_setmetatable(state: *mut lua_State, index: c_int); - - pub fn lua_len(state: *mut lua_State, index: c_int); - pub fn lua_rawlen(state: *mut lua_State, index: c_int) -> usize; - pub fn lua_next(state: *mut lua_State, index: c_int) -> c_int; - pub fn lua_rawequal(state: *mut lua_State, index1: c_int, index2: c_int) -> c_int; - - pub fn lua_error(state: *mut lua_State) -> !; - pub fn lua_atpanic(state: *mut lua_State, panic: lua_CFunction) -> lua_CFunction; - pub fn lua_gc(state: *mut lua_State, what: c_int, data: c_int) -> c_int; - pub fn lua_getinfo(state: *mut lua_State, what: *const c_char, ar: *mut lua_Debug) -> c_int; - - pub fn luaopen_base(state: *mut lua_State) -> c_int; - pub fn luaopen_coroutine(state: *mut lua_State) -> c_int; - pub fn luaopen_table(state: *mut lua_State) -> c_int; - pub fn luaopen_io(state: *mut lua_State) -> c_int; - pub fn luaopen_os(state: *mut lua_State) -> c_int; - pub fn luaopen_string(state: *mut lua_State) -> c_int; - pub fn luaopen_utf8(state: *mut lua_State) -> c_int; - pub fn luaopen_math(state: *mut lua_State) -> c_int; - pub fn luaopen_debug(state: *mut lua_State) -> c_int; - pub fn luaopen_package(state: *mut lua_State) -> c_int; - - pub fn luaL_openlibs(state: *mut lua_State); - pub fn luaL_requiref( - state: *mut lua_State, - modname: *const c_char, - openf: lua_CFunction, - glb: c_int, - ); - - pub fn luaL_loadbufferx( - state: *mut lua_State, - buf: *const c_char, - size: usize, - name: *const c_char, - mode: *const c_char, - ) -> c_int; - pub fn luaL_ref(state: *mut lua_State, table: c_int) -> c_int; - pub fn luaL_unref(state: *mut lua_State, table: c_int, lref: c_int); - pub fn luaL_checkstack(state: *mut lua_State, size: c_int, msg: *const c_char); - pub fn luaL_traceback( - push_state: *mut lua_State, - state: *mut lua_State, - msg: *const c_char, - level: c_int, - ); - pub fn luaL_len(push_state: *mut lua_State, index: c_int) -> lua_Integer; -} - -// The following are re-implementations of what are macros in the Lua C API - -pub unsafe fn lua_getextraspace(state: *mut lua_State) -> *mut c_void { - (state as *mut c_void).offset(-(mem::size_of::<*mut c_void>() as isize)) -} - -pub unsafe fn lua_pop(state: *mut lua_State, n: c_int) { - lua_settop(state, -n - 1); -} - -pub unsafe fn lua_newtable(state: *mut lua_State) { - lua_createtable(state, 0, 0); -} - -pub fn lua_upvalueindex(i: c_int) -> c_int { - LUA_REGISTRYINDEX - i -} - -pub unsafe fn lua_pushcfunction(state: *mut lua_State, function: lua_CFunction) { - lua_pushcclosure(state, function, 0); -} - -pub unsafe fn lua_tonumber(state: *mut lua_State, index: c_int) -> lua_Number { - lua_tonumberx(state, index, ptr::null_mut()) -} - -pub unsafe fn lua_tointeger(state: *mut lua_State, index: c_int) -> lua_Integer { - lua_tointegerx(state, index, ptr::null_mut()) -} - -pub unsafe fn lua_tostring(state: *mut lua_State, index: c_int) -> *const c_char { - lua_tolstring(state, index, ptr::null_mut()) -} - -pub unsafe fn lua_isfunction(state: *mut lua_State, index: c_int) -> c_int { - if lua_type(state, index) == LUA_TFUNCTION { - 1 - } else { - 0 - } -} - -pub unsafe fn lua_istable(state: *mut lua_State, index: c_int) -> c_int { - if lua_type(state, index) == LUA_TTABLE { - 1 - } else { - 0 - } -} - -pub unsafe fn lua_islightuserdata(state: *mut lua_State, index: c_int) -> c_int { - if lua_type(state, index) == LUA_TLIGHTUSERDATA { - 1 - } else { - 0 - } -} - -pub unsafe fn lua_isnil(state: *mut lua_State, index: c_int) -> c_int { - if lua_type(state, index) == LUA_TNIL { - 1 - } else { - 0 - } -} - -pub unsafe fn lua_isboolean(state: *mut lua_State, index: c_int) -> c_int { - if lua_type(state, index) == LUA_TBOOLEAN { - 1 - } else { - 0 - } -} - -pub unsafe fn lua_isthread(state: *mut lua_State, index: c_int) -> c_int { - if lua_type(state, index) == LUA_TTHREAD { - 1 - } else { - 0 - } -} - -pub unsafe fn lua_isnone(state: *mut lua_State, index: c_int) -> c_int { - if lua_type(state, index) == LUA_TNONE { - 1 - } else { - 0 - } -} - -pub unsafe fn lua_insert(state: *mut lua_State, index: c_int) { - lua_rotate(state, index, 1); -} - -pub unsafe fn lua_remove(state: *mut lua_State, index: c_int) { - lua_rotate(state, index, -1); - lua_pop(state, 1); -} - -pub unsafe fn lua_call(state: *mut lua_State, nargs: c_int, nresults: c_int) { - lua_callk(state, nargs, nresults, ptr::null_mut(), None) -} - -pub unsafe fn lua_pcall( - state: *mut lua_State, - nargs: c_int, - nresults: c_int, - msgh: c_int, -) -> c_int { - lua_pcallk(state, nargs, nresults, msgh, ptr::null_mut(), None) -} - -pub unsafe fn lua_replace(state: *mut lua_State, index: c_int) { - lua_copy(state, -1, index); - lua_pop(state, 1); -} - -pub unsafe fn luaL_loadbuffer( - state: *mut lua_State, - buf: *const c_char, - size: usize, - name: *const c_char, -) -> c_int { - luaL_loadbufferx(state, buf, size, name, ptr::null()) -} diff --git a/src/ffi/glue/glue.c b/src/ffi/glue/glue.c new file mode 100644 index 0000000..7cc5c4a --- /dev/null +++ b/src/ffi/glue/glue.c @@ -0,0 +1,247 @@ +// The MIT License (MIT) +// +// 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 + +// 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 TY_LUAINT 1 +#define TY_STR 2 +#define TY_TYPE 3 +#define TY_COMMENT 4 +#define TY_RAW 5 + +#define RS_INT(name, val) {TY_INT, name, .int_val=val} +#define RS_LUAINT(name, val) {TY_LUAINT, name, .lua_int_val=val} +#define RS_STR(name, val) {TY_STR, name, .str_val=val} +#define RS_TYPE(name, val) {TY_TYPE, name, .str_val=val} +#define RS_COMMENT(val) {TY_COMMENT, NULL, .str_val=val} +#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"; + } +} + +const char* rs_uint_type(int width) { + switch (width) { + default: + case 2: return "u16"; + case 4: return "u32"; + case 8: return "u64"; + } +} + +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); +} + +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); +} + +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: &'static 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); + case TY_LUAINT: return write_lua_int_item(f, c->name, c->lua_int_val); + 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 libc::*;\n"), + + // == luaconf.h =========================================================== + + RS_COMMENT("luaconf.h"), + RS_STR("LUA_VDIR", LUA_VDIR), + RS_STR("LUA_PATH_DEFAULT", LUA_PATH_DEFAULT), + RS_STR("LUA_CPATH_DEFAULT", LUA_CPATH_DEFAULT), + RS_STR("LUA_DIRSEP", LUA_DIRSEP), + RS_INT("LUA_EXTRASPACE", LUA_EXTRASPACE), + RS_INT("LUA_IDSIZE", LUA_IDSIZE), + // RS_INT("LUAI_MAXSHORTLEN", LUAI_MAXSHORTLEN), + RS_TYPE("LUA_KCONTEXT", xstr(LUA_KCONTEXT)), + RS_INT("LUAI_BITSINT", LUAI_BITSINT), + // LUA_INT32? LUAI_UMEM? LUAI_MEM? + RS_INT("LUAI_MAXSTACK", LUAI_MAXSTACK), + RS_INT("LUAL_BUFFERSIZE", LUAL_BUFFERSIZE), + RS_TYPE("LUA_NUMBER", + sizeof(LUA_NUMBER) > sizeof(float) ? "c_double" : "c_float"), + RS_TYPE("LUA_UNSIGNED", rs_uint_type(sizeof(LUA_UNSIGNED))), + RS_TYPE("LUA_INTEGER", rs_int_type(sizeof(LUA_INTEGER))), + RS_LUAINT("LUA_MAXINTEGER", LUA_MAXINTEGER), + RS_LUAINT("LUA_MININTEGER", LUA_MININTEGER), + + // == lua.h =============================================================== + + RS_COMMENT("lua.h"), + RS_STR("LUA_VERSION_MAJOR", LUA_VERSION_MAJOR), + RS_STR("LUA_VERSION_MINOR", LUA_VERSION_MINOR), + RS_INT("LUA_VERSION_NUM", LUA_VERSION_NUM), + RS_STR("LUA_VERSION_RELEASE", LUA_VERSION_RELEASE), + RS_STR("LUA_VERSION", LUA_VERSION), + RS_STR("LUA_RELEASE", LUA_RELEASE), + RS_STR("LUA_COPYRIGHT", LUA_COPYRIGHT), + RS_STR("LUA_AUTHORS", LUA_AUTHORS), + RS_INT("LUA_REGISTRYINDEX", LUA_REGISTRYINDEX), + + // == lauxlib.h =========================================================== + + RS_COMMENT("lauxlib.h"), + RS_INT("LUAL_NUMSIZES", LUAL_NUMSIZES), + RS_STR("LUA_FILEHANDLE", LUA_FILEHANDLE), + + // == 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), + RS_STR("LUA_UTF8LIBNAME", LUA_UTF8LIBNAME), + RS_STR("LUA_BITLIBNAME", LUA_BITLIBNAME), + RS_STR("LUA_MATHLIBNAME", LUA_MATHLIBNAME), + RS_STR("LUA_DBLIBNAME", LUA_DBLIBNAME), + RS_STR("LUA_LOADLIBNAME", LUA_LOADLIBNAME), + }; + + 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 new file mode 100644 index 0000000..83ac690 --- /dev/null +++ b/src/ffi/lauxlib.rs @@ -0,0 +1,264 @@ +// The MIT License (MIT) +// +// 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 libc::{c_int, c_long, c_char, c_void, size_t}; +use ffi::lua; +use ffi::lua::{lua_State, lua_CFunction, lua_Integer, lua_Number}; +use ffi::luaconf::LUAL_BUFFERSIZE; +use std::ptr; + +pub use super::glue::LUAL_NUMSIZES; +pub use super::glue::LUA_FILEHANDLE; + +// 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, +} + + +#[inline(always)] +pub unsafe fn luaL_checkversion(L: *mut lua_State) { + luaL_checkversion_(L, lua::LUA_VERSION_NUM as lua_Number, LUAL_NUMSIZES as size_t) +} + +extern { + pub fn luaL_checkversion_(L: *mut lua_State, ver: lua_Number, sz: size_t); + + 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 size_t) -> *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 size_t) -> *const c_char; + pub fn luaL_optlstring(L: *mut lua_State, arg: c_int, def: *const c_char, l: *mut size_t) -> *const c_char; + pub fn luaL_checknumber(L: *mut lua_State, arg: c_int) -> lua_Number; + pub fn luaL_optnumber(L: *mut lua_State, arg: c_int, def: lua_Number) -> lua_Number; + pub fn luaL_checkinteger(L: *mut lua_State, arg: c_int) -> lua_Integer; + pub fn luaL_optinteger(L: *mut lua_State, arg: c_int, def: lua_Integer) -> lua_Integer; + + pub fn luaL_checkstack(L: *mut lua_State, sz: c_int, msg: *const c_char); + pub fn luaL_checktype(L: *mut lua_State, arg: c_int, t: c_int); + pub fn luaL_checkany(L: *mut lua_State, arg: c_int); + + pub fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_int; + pub fn luaL_setmetatable(L: *mut lua_State, tname: *const c_char); + pub fn luaL_testudata(L: *mut lua_State, ud: c_int, tname: *const c_char) -> *mut c_void; + pub fn luaL_checkudata(L: *mut lua_State, ud: c_int, tname: *const c_char) -> *mut c_void; + + pub fn luaL_where(L: *mut lua_State, lvl: c_int); + pub fn luaL_error(L: *mut lua_State, fmt: *const c_char, ...) -> c_int; + + // 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; + + 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 { + 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); + + 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 { + pub fn luaL_loadbufferx(L: *mut lua_State, buff: *const c_char, sz: size_t, 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); +} + +#[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 + +#[inline(always)] +pub unsafe fn luaL_loadbuffer(L: *mut lua_State, s: *const c_char, sz: size_t, n: *const c_char) -> c_int { + luaL_loadbufferx(L, s, sz, n, ptr::null()) +} + +#[repr(C)] +pub struct luaL_Buffer { + pub b: *mut c_char, + pub size: size_t, + pub n: size_t, + pub L: *mut lua_State, + pub initb: [c_char; LUAL_BUFFERSIZE as usize] +} + +// TODO: Test this thoroughly +#[inline(always)] +pub unsafe fn luaL_addchar(B: *mut luaL_Buffer, c: c_char) { + // (B)->n < (B) -> size || luaL_prepbuffsize((B), 1) + if (*B).n < (*B).size { + luaL_prepbuffsize(B, 1); + } + // (B)->b[(B)->n++] = (c) + let offset = (*B).b.offset((*B).n as isize); + ptr::write(offset, c); + (*B).n += 1; +} + +#[inline(always)] +pub unsafe fn luaL_addsize(B: *mut luaL_Buffer, s: size_t) { + (*B).n += s; +} + +extern { + pub fn luaL_buffinit(L: *mut lua_State, B: *mut luaL_Buffer); + pub fn luaL_prepbuffsize(B: *mut luaL_Buffer, sz: size_t) -> *mut c_char; + pub fn luaL_addlstring(B: *mut luaL_Buffer, s: *const c_char, l: size_t); + pub fn luaL_addstring(B: *mut luaL_Buffer, s: *const c_char); + pub fn luaL_addvalue(B: *mut luaL_Buffer); + pub fn luaL_pushresult(B: *mut luaL_Buffer); + pub fn luaL_pushresultsize(B: *mut luaL_Buffer, sz: size_t); + pub fn luaL_buffinitsize(L: *mut lua_State, B: *mut luaL_Buffer, sz: size_t) -> *mut c_char; +} + +pub unsafe fn luaL_prepbuffer(B: *mut luaL_Buffer) -> *mut c_char { + luaL_prepbuffsize(B, LUAL_BUFFERSIZE as size_t) +} + +#[repr(C)] +pub struct luaL_Stream { + pub f: *mut ::libc::FILE, + pub closef: lua_CFunction +} + +// omitted: old module system compatibility diff --git a/src/ffi/lua.rs b/src/ffi/lua.rs new file mode 100644 index 0000000..141402c --- /dev/null +++ b/src/ffi/lua.rs @@ -0,0 +1,439 @@ +// The MIT License (MIT) +// +// 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 libc::{c_void, c_int, c_char, c_uchar, size_t}; +use ffi::luaconf; +use std::ptr; + +pub use super::glue::{LUA_VERSION_MAJOR, LUA_VERSION_MINOR, LUA_VERSION_NUM, LUA_VERSION_RELEASE}; +pub use super::glue::{LUA_VERSION, LUA_RELEASE, LUA_COPYRIGHT, LUA_AUTHORS}; +pub use super::glue::{LUA_REGISTRYINDEX}; + +pub const LUA_SIGNATURE: &'static [u8] = b"\x1bLua"; + +// option for multiple returns in 'lua_pcall' and 'lua_call' +pub const LUA_MULTRET: c_int = -1; + +#[inline(always)] +pub 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; + +pub type lua_State = c_void; + +// 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 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 = luaconf::LUA_NUMBER; + +/// A Lua integer, usually equivalent to `i64`. +pub type lua_Integer = luaconf::LUA_INTEGER; + +// unsigned integer type +pub type lua_Unsigned = luaconf::LUA_UNSIGNED; + +// type for continuation-function contexts +pub type lua_KContext = luaconf::LUA_KCONTEXT; + +/// Type for native functions that can be passed to Lua. +pub type lua_CFunction = unsafe extern "C" fn(L: *mut lua_State) -> c_int; + +// Type for continuation functions +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 size_t) -> *const c_char; +pub type lua_Writer = unsafe extern "C" fn(L: *mut lua_State, p: *const c_void, sz: size_t, 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: size_t, nsize: size_t) -> *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 size_t) -> *const c_char; + pub fn lua_rawlen(L: *mut lua_State, idx: c_int) -> size_t; + 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; +} + +// 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; +} + +// 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); + pub fn lua_pushlstring(L: *mut lua_State, s: *const c_char, l: size_t) -> *const c_char; + pub fn lua_pushstring(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" { + pub fn lua_getglobal(L: *mut lua_State, var: *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: size_t) -> *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) +extern "C" { + 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_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) +extern "C" { + 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, dt: *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) +} + +// coroutine functions +extern "C" { + 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) -> 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 { + pub fn lua_gc(L: *mut lua_State, what: c_int, data: c_int) -> c_int; +} + +// miscellaneous functions +extern { + 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) -> size_t; + 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 +// here, implemented as Rust functions +#[inline(always)] +pub unsafe fn lua_getextraspace(L: *mut lua_State) -> *mut c_void { + L.offset(-super::glue::LUA_EXTRASPACE as isize) as *mut c_void +} + +#[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 +} + +// TODO: Test +#[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() as size_t) +} + +#[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 +// 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 = Option; + +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: lua_Hook, mask: c_int, count: c_int); + pub fn lua_gethook(L: *mut lua_State) -> lua_Hook; + 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; luaconf::LUA_IDSIZE as usize], + // lua.h mentions this is for private use + i_ci: *mut c_void, +} + diff --git a/src/ffi/luaconf.rs b/src/ffi/luaconf.rs new file mode 100644 index 0000000..05de95d --- /dev/null +++ b/src/ffi/luaconf.rs @@ -0,0 +1,49 @@ +// The MIT License (MIT) +// +// 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::LUAL_BUFFERSIZE; +pub use super::glue::LUA_NUMBER; +pub use super::glue::LUA_INTEGER; +pub use super::glue::LUA_UNSIGNED; + +pub use super::glue::{LUA_IDSIZE}; +pub use super::glue::{LUA_MININTEGER, LUA_MAXINTEGER}; + +pub use super::glue::LUAI_MAXSTACK; +pub use super::glue::LUAL_NUMSIZES; + +pub use super::glue::LUA_KCONTEXT; + +use libc::c_int; + +#[inline(always)] +pub unsafe fn lua_numtointeger(n: LUA_NUMBER, p: *mut LUA_INTEGER) -> c_int { + if n >= (LUA_MININTEGER as LUA_NUMBER) && n < -(LUA_MININTEGER as LUA_NUMBER) { + *p = n as LUA_INTEGER; + 1 + } else { + 0 + } +} + diff --git a/src/ffi/lualib.rs b/src/ffi/lualib.rs new file mode 100644 index 0000000..a0bd5dc --- /dev/null +++ b/src/ffi/lualib.rs @@ -0,0 +1,47 @@ +// The MIT License (MIT) +// +// 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 ffi::lua::lua_State; +use libc::c_int; + +pub use super::glue::{ + LUA_COLIBNAME, LUA_TABLIBNAME, LUA_IOLIBNAME, LUA_OSLIBNAME, LUA_STRLIBNAME, + LUA_UTF8LIBNAME, LUA_BITLIBNAME, LUA_MATHLIBNAME, LUA_DBLIBNAME, LUA_LOADLIBNAME +}; + +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; + + pub fn luaL_openlibs(L: *mut lua_State); +} diff --git a/src/ffi/mod.rs b/src/ffi/mod.rs new file mode 100644 index 0000000..fbe9416 --- /dev/null +++ b/src/ffi/mod.rs @@ -0,0 +1,310 @@ +// The MIT License (MIT) +// +// 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. + +#![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. + +// luaconf.h functions +pub use self::luaconf::lua_numtointeger; + +// C API types +pub use self::lua::{ + lua_Alloc, + lua_CFunction, + lua_KContext, + lua_Debug, + lua_Hook, + lua_Integer, + lua_KFunction, + lua_Number, + lua_Reader, + lua_State, + lua_Unsigned, + lua_Writer +}; + +// C API functions +pub use self::lua::{ + lua_absindex, + lua_arith, + lua_atpanic, + lua_call, + lua_callk, + 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_isyieldable, + lua_len, + lua_load, + lua_newstate, + lua_newtable, + lua_newthread, + lua_newuserdata, + lua_next, + lua_pcall, + lua_pcallk, + 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_upvalueid, + lua_upvalueindex, + lua_upvaluejoin, + lua_version, + lua_xmove, + lua_yield, + lua_yieldk +}; + +// auxiliary library types +pub use self::lauxlib::{ + luaL_Buffer, + luaL_Reg, + luaL_Stream +}; + +// auxiliary library functions +pub use self::lauxlib::{ + luaL_addchar, + luaL_addlstring, + luaL_addsize, + luaL_addstring, + luaL_addvalue, + luaL_argcheck, + luaL_argerror, + luaL_buffinit, + luaL_buffinitsize, + luaL_callmeta, + luaL_checkany, + luaL_checkint, + luaL_checkinteger, + luaL_checklong, + luaL_checklstring, + luaL_checknumber, + luaL_checkoption, + luaL_checkstack, + luaL_checkstring, + luaL_checktype, + luaL_checkudata, + luaL_checkversion, + luaL_dofile, + luaL_dostring, + luaL_error, + luaL_execresult, + luaL_fileresult, + luaL_getmetafield, + luaL_getmetatable, + luaL_getsubtable, + luaL_gsub, + luaL_len, + luaL_loadbuffer, + luaL_loadbufferx, + luaL_loadfile, + luaL_loadfilex, + luaL_loadstring, + luaL_newlib, + luaL_newlibtable, + luaL_newmetatable, + luaL_newstate, + luaL_optint, + luaL_optinteger, + luaL_optlong, + luaL_optlstring, + luaL_optnumber, + luaL_optstring, + luaL_prepbuffer, + luaL_prepbuffsize, + luaL_pushresult, + luaL_pushresultsize, + luaL_ref, + luaL_requiref, + luaL_setfuncs, + luaL_setmetatable, + luaL_testudata, + luaL_tolstring, + luaL_traceback, + luaL_typename, + luaL_unref, + luaL_where +}; + +// lualib.h functions +pub use self::lualib::{ + luaopen_base, + luaopen_coroutine, + luaopen_table, + luaopen_io, + luaopen_os, + luaopen_string, + luaopen_utf8, + luaopen_bit32, + luaopen_math, + luaopen_debug, + luaopen_package, + + luaL_openlibs +}; + +// constants from lua.h +pub use self::lua::{ + LUA_MULTRET, + LUA_REGISTRYINDEX, + + LUA_RIDX_MAINTHREAD, LUA_RIDX_GLOBALS, + + LUA_OPADD, LUA_OPSUB, LUA_OPMUL, LUA_OPDIV, LUA_OPIDIV, + LUA_OPMOD, LUA_OPPOW, LUA_OPUNM, + LUA_OPBNOT, LUA_OPBAND, LUA_OPBOR, LUA_OPBXOR, LUA_OPSHL, LUA_OPSHR, + LUA_OPEQ, LUA_OPLT, LUA_OPLE, + + LUA_OK, LUA_YIELD, LUA_ERRRUN, LUA_ERRSYNTAX, LUA_ERRMEM, LUA_ERRGCMM, LUA_ERRERR, + + LUA_TNONE, LUA_TNIL, LUA_TNUMBER, LUA_TBOOLEAN, LUA_TSTRING, LUA_TTABLE, + LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD, LUA_TLIGHTUSERDATA, + + LUA_HOOKCALL, LUA_HOOKRET, LUA_HOOKTAILCALL, LUA_HOOKLINE, LUA_HOOKCOUNT, + LUA_MASKCALL, LUA_MASKRET, LUA_MASKLINE, LUA_MASKCOUNT, + + LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, LUA_GCCOUNT, LUA_GCCOUNTB, + LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL, LUA_GCISRUNNING, + + LUA_MINSTACK +}; + +// constants from lauxlib.h +pub use self::lauxlib::{ + LUA_REFNIL, LUA_NOREF, + LUA_ERRFILE, + LUA_FILEHANDLE +}; + +// constants from lualib.h +pub use self::lualib::{ + LUA_COLIBNAME, LUA_TABLIBNAME, LUA_IOLIBNAME, LUA_OSLIBNAME, LUA_STRLIBNAME, + LUA_UTF8LIBNAME, LUA_BITLIBNAME, LUA_MATHLIBNAME, LUA_DBLIBNAME, LUA_LOADLIBNAME +}; + +// Not actually defined in lua.h / luaconf.h +pub const LUA_MAX_UPVALUES: c_int = 255; + +#[allow(unused_imports, dead_code, non_camel_case_types)] +mod glue { + include!(concat!(env!("OUT_DIR"), "/glue.rs")); +} + +mod luaconf; +mod lua; +mod lauxlib; +mod lualib;