1#![allow(clippy::too_many_arguments)]
2extern crate libc;
3extern crate td_clua;
4
5use std::borrow::Borrow;
6use std::ffi::{CStr, CString};
7use std::fs::File;
8use std::io::prelude::*;
9
10macro_rules! unwrap_or {
11 ($expr:expr, $or:expr) => {
12 match $expr {
13 Some(x) => x,
14 None => $or,
15 }
16 };
17}
18
19pub mod functions;
20mod hotfix;
21pub mod lua_tables;
22pub mod rust_tables;
23pub mod tuples;
24pub mod userdata;
25pub mod values;
26
27pub use functions::{
28 function0, function1, function10, function2, function3, function4, function5, function6,
29 function7, function8, function9, Function,
30};
31pub use lua_tables::LuaTable;
32pub use td_clua::*;
33pub use userdata::{push_lightuserdata, push_userdata, read_userdata, LuaStruct, NewStruct};
34pub struct Lua {
35 lua: *mut lua_State,
36 own: bool,
37}
38
39pub struct LuaGuard {
40 pub lua: *mut lua_State,
41 pub size: i32,
42}
43
44impl LuaGuard {
45 pub fn forget(mut self) -> i32 {
46 let size = self.size;
47 self.size = 0;
48 size
49 }
50
51 pub fn empty(&self) -> LuaGuard {
52 LuaGuard {
53 lua: self.lua,
54 size: 0,
55 }
56 }
57
58 pub fn new_empty(lua: *mut lua_State) -> LuaGuard {
59 LuaGuard { lua: lua, size: 0 }
60 }
61
62 pub fn new(lua: *mut lua_State, size: i32) -> LuaGuard {
63 LuaGuard {
64 lua: lua,
65 size: size,
66 }
67 }
68}
69
70macro_rules! impl_exec_func {
71 ($name:ident, $($p:ident),*) => (
72 #[allow(non_snake_case, unused_mut)]
73 pub fn $name<Z, $($p),*>(&mut self, func_name : Z, $($p : $p, )*) -> i32 where Z: Borrow<str>, $($p : LuaPush),* {
74 let func_name = CString::new(func_name.borrow()).unwrap();
75 unsafe {
76 let state = self.state();
77 let error = CString::new("error_handle").unwrap();
78 lua_getglobal(state, error.as_ptr());
79 td_clua::lua_getglobal(state, func_name.as_ptr());
80
81 let mut index = 0;
82 $(
83 index += $p.push_to_lua(self.state());
84 )*
85
86 let success = td_clua::lua_pcall(state, index, 0, -index - 2);
87 if success != 0 {
88 td_clua::lua_pop(state, 1);
89 }
90 td_clua::lua_pop(state, 1);
91 success
92 }
93 }
94 )
95}
96
97impl Default for Lua {
98 fn default() -> Self {
99 Self::new()
100 }
101}
102
103impl Lua {
104 pub fn new() -> Lua {
111 let lua = unsafe { td_clua::luaL_newstate() };
112 if lua.is_null() {
113 panic!("lua_newstate failed");
114 }
115
116 extern "C" fn panic(lua: *mut td_clua::lua_State) -> libc::c_int {
118 let err = unsafe { td_clua::lua_tostring(lua, -1) };
119 let err = unsafe { CStr::from_ptr(err) };
120 let err = String::from_utf8(err.to_bytes().to_vec()).unwrap();
121 panic!("PANIC: unprotected error in call to Lua API ({})\n", err);
122 }
123
124 extern "C" fn error_handle(lua: *mut td_clua::lua_State) -> libc::c_int {
125 let err = unsafe { td_clua::lua_tostring(lua, -1) };
126 let err = unsafe { CStr::from_ptr(err) };
127 let err = String::from_utf8(err.to_bytes().to_vec()).unwrap();
128 println!("error:{}", err);
129 0
130 }
131
132 unsafe { td_clua::lua_atpanic(lua, panic) };
133 let mut lua = Lua {
134 lua: lua,
135 own: true,
136 };
137 lua.register("error_handle", error_handle);
138 lua
139 }
140
141 pub fn state(&mut self) -> *mut lua_State {
142 self.lua
143 }
144
145 pub fn clone(&mut self) -> Lua {
146 Lua {
147 lua: self.lua,
148 own: false,
149 }
150 }
151
152 pub fn set_own(&mut self, own: bool) {
153 self.own = own;
154 }
155
156 pub fn from_existing_state(lua: *mut lua_State, close_at_the_end: bool) -> Lua {
162 Lua {
163 lua: lua,
164 own: close_at_the_end,
165 }
166 }
167
168 pub fn register<I>(
169 &mut self,
170 index: I,
171 func: extern "C" fn(*mut td_clua::lua_State) -> libc::c_int,
172 ) -> i32
173 where
174 I: Borrow<str>,
175 {
176 let index = CString::new(index.borrow()).unwrap();
177 unsafe { td_clua::lua_register(self.state(), index.as_ptr(), func) };
178 0
179 }
180
181 pub fn openlibs(&mut self) {
184 unsafe { td_clua::luaL_openlibs(self.lua) }
185 }
186
187 pub fn query<V, I>(&mut self, index: I) -> Option<V>
189 where
190 I: Borrow<str>,
191 V: LuaRead,
192 {
193 let index = CString::new(index.borrow()).unwrap();
194 unsafe {
195 td_clua::lua_getglobal(self.lua, index.as_ptr());
196 }
197 let _guard = LuaGuard::new(self.lua, 1);
198 LuaRead::lua_read_with_pop(self.state(), -1, 1)
199 }
200
201 pub fn set<I, V>(&mut self, index: I, value: V)
203 where
204 I: Borrow<str>,
205 for<'a> V: LuaPush,
206 {
207 let index = CString::new(index.borrow()).unwrap();
208 value.push_to_lua(self.state());
209 unsafe {
210 td_clua::lua_setglobal(self.lua, index.as_ptr());
211 }
212 }
213
214 pub fn exec_string<I, R>(&mut self, index: I) -> Option<R>
215 where
216 I: Borrow<str>,
217 R: LuaRead,
218 {
219 let index = CString::new(index.borrow()).unwrap();
220 unsafe {
221 let state = self.state();
222 let error = CString::new("error_handle").unwrap();
223 td_clua::lua_getglobal(state, error.as_ptr());
224 td_clua::luaL_loadstring(state, index.as_ptr());
225 let success = td_clua::lua_pcall(state, 0, 1, -2);
226 if success != 0 {
227 td_clua::lua_pop(state, 1);
228 return None;
229 }
230 LuaRead::lua_read(state)
231 }
232 }
233
234 pub fn exec_func<I, R>(&mut self, index: I) -> Option<R>
235 where
236 I: Borrow<str>,
237 R: LuaRead,
238 {
239 let index = CString::new(index.borrow()).unwrap();
240 unsafe {
241 let state = self.state();
242 let error = CString::new("error_handle").unwrap();
243 let top = td_clua::lua_gettop(state);
244 td_clua::lua_getglobal(state, index.as_ptr());
245 td_clua::lua_insert(state, -top - 1);
246 td_clua::lua_getglobal(state, error.as_ptr());
247 td_clua::lua_insert(state, -top - 2);
248 let success = td_clua::lua_pcall(state, top, 1, -top - 2);
249 if success != 0 {
250 td_clua::lua_pop(state, 1);
251 return None;
252 }
253 LuaRead::lua_read(state)
254 }
255 }
256
257 pub fn empty_table<I>(&mut self, index: I) -> LuaTable
259 where
260 I: Borrow<str>,
261 {
262 let index2 = CString::new(index.borrow()).unwrap();
263 unsafe {
264 td_clua::lua_newtable(self.state());
265 td_clua::lua_setglobal(self.state(), index2.as_ptr());
266 }
267 self.query(index).unwrap()
268 }
269
270 pub fn add_lualoader(
271 &mut self,
272 func: extern "C" fn(*mut td_clua::lua_State) -> libc::c_int,
273 ) -> i32 {
274 let state = self.state();
275 unsafe {
276 let package = CString::new("package").unwrap();
277 let searchers = CString::new("searchers").unwrap();
278 td_clua::lua_getglobal(state, package.as_ptr());
279 td_clua::lua_getfield(state, -1, searchers.as_ptr());
280 td_clua::lua_pushcfunction(state, func);
281 let mut i = (td_clua::lua_rawlen(state, -2) + 1) as i32;
282 while i > 2 {
283 td_clua::lua_rawgeti(state, -2, i - 1);
284 td_clua::lua_rawseti(state, -3, i);
285 i -= 1;
286 }
287 td_clua::lua_rawseti(state, -2, 2);
288 td_clua::lua_setfield(state, -2, searchers.as_ptr());
290 td_clua::lua_pop(state, 1);
291 }
292 0
293 }
294
295 pub fn load_file(&mut self, file_name: &str) -> i32 {
296 let mut f = unwrap_or!(File::open(file_name).ok(), return 0);
297 let mut buffer = Vec::new();
298 let _ = unwrap_or!(f.read_to_end(&mut buffer).ok(), return 0);
299 let mut name = file_name.to_string();
300 let mut short_name = name.clone();
301 let len = name.len();
302 if len > 30 {
303 short_name = name.drain((len - 30)..).collect();
304 }
305
306 let short_name = CString::new(short_name).unwrap();
307 let ret = unsafe {
308 td_clua::luaL_loadbuffer(
309 self.state(),
310 buffer.as_ptr() as *const libc::c_char,
311 buffer.len(),
312 short_name.as_ptr(),
313 )
314 };
315 if ret != 0 {
316 let err_msg: String = unwrap_or!(LuaRead::lua_read(self.state()), return 0);
317 let err_detail = CString::new(format!(
318 "error loading from file {} :\n\t{}",
319 file_name, err_msg
320 ))
321 .unwrap();
322 unsafe {
323 td_clua::luaL_error(self.state(), err_detail.as_ptr());
324 }
325 }
326 1
327 }
328
329 pub fn enable_hotfix(&mut self) {
331 hotfix::load_hot_fix(self);
332 }
333
334 pub fn exec_gc(&mut self) -> i32 {
335 unsafe { td_clua::lua_gc(self.state(), td_clua::LUA_GCCOLLECT, 0) as i32 }
336 }
337
338 impl_exec_func!(exec_func0,);
339 impl_exec_func!(exec_func1, A);
340 impl_exec_func!(exec_func2, A, B);
341 impl_exec_func!(exec_func3, A, B, C);
342 impl_exec_func!(exec_func4, A, B, C, D);
343 impl_exec_func!(exec_func5, A, B, C, D, E);
344 impl_exec_func!(exec_func6, A, B, C, D, E, F);
345 impl_exec_func!(exec_func7, A, B, C, D, E, F, G);
346 impl_exec_func!(exec_func8, A, B, C, D, E, F, G, H);
347 impl_exec_func!(exec_func9, A, B, C, D, E, F, G, H, I);
348 impl_exec_func!(exec_func10, A, B, C, D, E, F, G, H, I, J);
349}
350
351pub trait LuaPush {
354 fn push_to_lua(self, lua: *mut lua_State) -> i32;
362}
363
364pub trait LuaRead: Sized {
369 fn lua_read(lua: *mut lua_State) -> Option<Self> {
371 LuaRead::lua_read_at_position(lua, -1)
372 }
373
374 fn lua_read_at_position(lua: *mut lua_State, index: i32) -> Option<Self> {
376 LuaRead::lua_read_with_pop(lua, index, 0)
377 }
378
379 fn lua_read_with_pop(lua: *mut lua_State, index: i32, pop: i32) -> Option<Self>;
381}
382
383impl Drop for Lua {
384 fn drop(&mut self) {
385 if self.own {
386 unsafe { td_clua::lua_close(self.lua) }
387 }
388 }
389}
390
391impl Drop for LuaGuard {
392 fn drop(&mut self) {
393 if self.size != 0 {
394 unsafe { td_clua::lua_pop(self.lua, self.size) }
395 }
396 }
397}