#![allow(clippy::too_many_arguments)]
extern crate libc;
extern crate td_clua;
use std::borrow::Borrow;
use std::ffi::{CStr, CString};
use std::fs::File;
use std::io::prelude::*;
macro_rules! unwrap_or {
($expr:expr, $or:expr) => {
match $expr {
Some(x) => x,
None => $or,
}
};
}
pub mod functions;
mod hotfix;
pub mod lua_tables;
pub mod rust_tables;
pub mod tuples;
pub mod userdata;
pub mod values;
pub use functions::{
function0, function1, function10, function2, function3, function4, function5, function6,
function7, function8, function9, Function,
};
pub use lua_tables::LuaTable;
pub use td_clua::*;
pub use userdata::{push_lightuserdata, push_userdata, read_userdata, LuaStruct, NewStruct};
pub struct Lua {
lua: *mut lua_State,
own: bool,
}
pub struct LuaGuard {
pub lua: *mut lua_State,
pub size: i32,
}
impl LuaGuard {
pub fn forget(mut self) -> i32 {
let size = self.size;
self.size = 0;
size
}
pub fn empty(&self) -> LuaGuard {
LuaGuard {
lua: self.lua,
size: 0,
}
}
pub fn new_empty(lua: *mut lua_State) -> LuaGuard {
LuaGuard { lua: lua, size: 0 }
}
pub fn new(lua: *mut lua_State, size: i32) -> LuaGuard {
LuaGuard {
lua: lua,
size: size,
}
}
}
macro_rules! impl_exec_func {
($name:ident, $($p:ident),*) => (
#[allow(non_snake_case, unused_mut)]
pub fn $name<Z, $($p),*>(&mut self, func_name : Z, $($p : $p, )*) -> i32 where Z: Borrow<str>, $($p : LuaPush),* {
let func_name = CString::new(func_name.borrow()).unwrap();
unsafe {
let state = self.state();
let error = CString::new("error_handle").unwrap();
lua_getglobal(state, error.as_ptr());
td_clua::lua_getglobal(state, func_name.as_ptr());
let mut index = 0;
$(
index += $p.push_to_lua(self.state());
)*
let success = td_clua::lua_pcall(state, index, 0, -index - 2);
if success != 0 {
td_clua::lua_pop(state, 1);
}
td_clua::lua_pop(state, 1);
success
}
}
)
}
impl Default for Lua {
fn default() -> Self {
Self::new()
}
}
impl Lua {
pub fn new() -> Lua {
let lua = unsafe { td_clua::luaL_newstate() };
if lua.is_null() {
panic!("lua_newstate failed");
}
extern "C" fn panic(lua: *mut td_clua::lua_State) -> libc::c_int {
let err = unsafe { td_clua::lua_tostring(lua, -1) };
let err = unsafe { CStr::from_ptr(err) };
let err = String::from_utf8(err.to_bytes().to_vec()).unwrap();
panic!("PANIC: unprotected error in call to Lua API ({})\n", err);
}
extern "C" fn error_handle(lua: *mut td_clua::lua_State) -> libc::c_int {
let err = unsafe { td_clua::lua_tostring(lua, -1) };
let err = unsafe { CStr::from_ptr(err) };
let err = String::from_utf8(err.to_bytes().to_vec()).unwrap();
println!("error:{}", err);
0
}
unsafe { td_clua::lua_atpanic(lua, panic) };
let mut lua = Lua {
lua: lua,
own: true,
};
lua.register("error_handle", error_handle);
lua
}
pub fn state(&mut self) -> *mut lua_State {
self.lua
}
pub fn clone(&mut self) -> Lua {
Lua {
lua: self.lua,
own: false,
}
}
pub fn set_own(&mut self, own: bool) {
self.own = own;
}
pub fn from_existing_state(lua: *mut lua_State, close_at_the_end: bool) -> Lua {
Lua {
lua: lua,
own: close_at_the_end,
}
}
pub fn register<I>(
&mut self,
index: I,
func: extern "C" fn(*mut td_clua::lua_State) -> libc::c_int,
) -> i32
where
I: Borrow<str>,
{
let index = CString::new(index.borrow()).unwrap();
unsafe { td_clua::lua_register(self.state(), index.as_ptr(), func) };
0
}
pub fn openlibs(&mut self) {
unsafe { td_clua::luaL_openlibs(self.lua) }
}
pub fn query<V, I>(&mut self, index: I) -> Option<V>
where
I: Borrow<str>,
V: LuaRead,
{
let index = CString::new(index.borrow()).unwrap();
unsafe {
td_clua::lua_getglobal(self.lua, index.as_ptr());
}
let _guard = LuaGuard::new(self.lua, 1);
LuaRead::lua_read_with_pop(self.state(), -1, 1)
}
pub fn set<I, V>(&mut self, index: I, value: V)
where
I: Borrow<str>,
for<'a> V: LuaPush,
{
let index = CString::new(index.borrow()).unwrap();
value.push_to_lua(self.state());
unsafe {
td_clua::lua_setglobal(self.lua, index.as_ptr());
}
}
pub fn exec_string<I, R>(&mut self, index: I) -> Option<R>
where
I: Borrow<str>,
R: LuaRead,
{
let index = CString::new(index.borrow()).unwrap();
unsafe {
let state = self.state();
let error = CString::new("error_handle").unwrap();
td_clua::lua_getglobal(state, error.as_ptr());
td_clua::luaL_loadstring(state, index.as_ptr());
let success = td_clua::lua_pcall(state, 0, 1, -2);
if success != 0 {
td_clua::lua_pop(state, 1);
return None;
}
LuaRead::lua_read(state)
}
}
pub fn exec_func<I, R>(&mut self, index: I) -> Option<R>
where
I: Borrow<str>,
R: LuaRead,
{
let index = CString::new(index.borrow()).unwrap();
unsafe {
let state = self.state();
let error = CString::new("error_handle").unwrap();
let top = td_clua::lua_gettop(state);
td_clua::lua_getglobal(state, index.as_ptr());
td_clua::lua_insert(state, -top - 1);
td_clua::lua_getglobal(state, error.as_ptr());
td_clua::lua_insert(state, -top - 2);
let success = td_clua::lua_pcall(state, top, 1, -top - 2);
if success != 0 {
td_clua::lua_pop(state, 1);
return None;
}
LuaRead::lua_read(state)
}
}
pub fn empty_table<I>(&mut self, index: I) -> LuaTable
where
I: Borrow<str>,
{
let index2 = CString::new(index.borrow()).unwrap();
unsafe {
td_clua::lua_newtable(self.state());
td_clua::lua_setglobal(self.state(), index2.as_ptr());
}
self.query(index).unwrap()
}
pub fn add_lualoader(
&mut self,
func: extern "C" fn(*mut td_clua::lua_State) -> libc::c_int,
) -> i32 {
let state = self.state();
unsafe {
let package = CString::new("package").unwrap();
let searchers = CString::new("searchers").unwrap();
td_clua::lua_getglobal(state, package.as_ptr());
td_clua::lua_getfield(state, -1, searchers.as_ptr());
td_clua::lua_pushcfunction(state, func);
let mut i = (td_clua::lua_rawlen(state, -2) + 1) as i32;
while i > 2 {
td_clua::lua_rawgeti(state, -2, i - 1);
td_clua::lua_rawseti(state, -3, i);
i -= 1;
}
td_clua::lua_rawseti(state, -2, 2);
td_clua::lua_setfield(state, -2, searchers.as_ptr());
td_clua::lua_pop(state, 1);
}
0
}
pub fn load_file(&mut self, file_name: &str) -> i32 {
let mut f = unwrap_or!(File::open(file_name).ok(), return 0);
let mut buffer = Vec::new();
let _ = unwrap_or!(f.read_to_end(&mut buffer).ok(), return 0);
let mut name = file_name.to_string();
let mut short_name = name.clone();
let len = name.len();
if len > 30 {
short_name = name.drain((len - 30)..).collect();
}
let short_name = CString::new(short_name).unwrap();
let ret = unsafe {
td_clua::luaL_loadbuffer(
self.state(),
buffer.as_ptr() as *const libc::c_char,
buffer.len(),
short_name.as_ptr(),
)
};
if ret != 0 {
let err_msg: String = unwrap_or!(LuaRead::lua_read(self.state()), return 0);
let err_detail = CString::new(format!(
"error loading from file {} :\n\t{}",
file_name, err_msg
))
.unwrap();
unsafe {
td_clua::luaL_error(self.state(), err_detail.as_ptr());
}
}
1
}
pub fn enable_hotfix(&mut self) {
hotfix::load_hot_fix(self);
}
pub fn exec_gc(&mut self) -> i32 {
unsafe { td_clua::lua_gc(self.state(), td_clua::LUA_GCCOLLECT, 0) as i32 }
}
impl_exec_func!(exec_func0,);
impl_exec_func!(exec_func1, A);
impl_exec_func!(exec_func2, A, B);
impl_exec_func!(exec_func3, A, B, C);
impl_exec_func!(exec_func4, A, B, C, D);
impl_exec_func!(exec_func5, A, B, C, D, E);
impl_exec_func!(exec_func6, A, B, C, D, E, F);
impl_exec_func!(exec_func7, A, B, C, D, E, F, G);
impl_exec_func!(exec_func8, A, B, C, D, E, F, G, H);
impl_exec_func!(exec_func9, A, B, C, D, E, F, G, H, I);
impl_exec_func!(exec_func10, A, B, C, D, E, F, G, H, I, J);
}
pub trait LuaPush {
fn push_to_lua(self, lua: *mut lua_State) -> i32;
}
pub trait LuaRead: Sized {
fn lua_read(lua: *mut lua_State) -> Option<Self> {
LuaRead::lua_read_at_position(lua, -1)
}
fn lua_read_at_position(lua: *mut lua_State, index: i32) -> Option<Self> {
LuaRead::lua_read_with_pop(lua, index, 0)
}
fn lua_read_with_pop(lua: *mut lua_State, index: i32, pop: i32) -> Option<Self>;
}
impl Drop for Lua {
fn drop(&mut self) {
if self.own {
unsafe { td_clua::lua_close(self.lua) }
}
}
}
impl Drop for LuaGuard {
fn drop(&mut self) {
if self.size != 0 {
unsafe { td_clua::lua_pop(self.lua, self.size) }
}
}
}