1use std::error::Error;
2use std::ffi::{c_int, CStr};
3use std::mem;
4use std::ptr;
5
6use crate::ffi::{self, lua_State};
7use crate::{utils, Poppable, Pushable};
8
9pub fn store<F, A, R, E>(fun: F) -> c_int
11where
12 F: Fn(A) -> Result<R, E> + 'static,
13 A: Poppable,
14 R: Pushable,
15 E: Error + 'static,
16{
17 type Callback =
18 Box<dyn Fn(*mut lua_State) -> Result<c_int, crate::Error> + 'static>;
19
20 unsafe extern "C" fn c_fun(lstate: *mut lua_State) -> c_int {
21 let fun = {
22 let idx = ffi::lua_upvalueindex(1);
23 let upv = ffi::lua_touserdata(lstate, idx) as *mut Callback;
24 &**upv
25 };
26
27 fun(lstate).unwrap_or_else(|err| utils::handle_error(lstate, &err))
28 }
29
30 unsafe {
31 crate::with_state(move |lstate| {
32 let fun = move |lstate| {
33 let args = A::pop(lstate)?;
34 let ret = fun(args)
35 .map_err(crate::Error::push_error_from_err::<R, _>)?;
36 ret.push(lstate)
37 };
38
39 let ud = ffi::lua_newuserdata(lstate, mem::size_of::<Callback>());
40 ptr::write(ud as *mut Callback, Box::new(fun));
41
42 ffi::lua_pushcclosure(lstate, c_fun, 1);
43 ffi::luaL_ref(lstate, ffi::LUA_REGISTRYINDEX)
44 })
45 }
46}
47
48pub fn call<A, R>(lua_ref: c_int, args: A) -> Result<R, crate::Error>
50where
51 A: Pushable,
52 R: Poppable,
53{
54 unsafe {
55 crate::with_state(move |lstate| {
56 ffi::lua_rawgeti(lstate, ffi::LUA_REGISTRYINDEX, lua_ref);
57 let nargs = args.push(lstate)?;
58
59 match ffi::lua_pcall(lstate, nargs, -1, 0 ) {
60 ffi::LUA_OK => R::pop(lstate),
61
62 err_code => {
63 let msg = CStr::from_ptr(ffi::lua_tostring(lstate, -1))
64 .to_string_lossy()
65 .to_string();
66
67 ffi::lua_pop(lstate, 1);
68
69 match err_code {
70 ffi::LUA_ERRRUN => {
71 Err(crate::Error::RuntimeError(msg))
72 },
73
74 ffi::LUA_ERRMEM => Err(crate::Error::MemoryError(msg)),
75
76 ffi::LUA_ERRERR => {
77 unreachable!("errorfunc is 0, this never happens!")
78 },
79
80 _ => unreachable!(),
81 }
82 },
83 }
84 })
85 }
86}
87
88pub fn remove(lua_ref: c_int) {
90 unsafe {
91 crate::with_state(|lstate| {
92 ffi::luaL_unref(lstate, ffi::LUA_REGISTRYINDEX, lua_ref)
93 })
94 }
95}