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