pub unsafe fn callback_error<F, R>(state: *mut ffi::lua_State, f: F) -> R
where
    F: FnOnce(c_int) -> Result<R>,
{
    let nargs = ffi::lua_gettop(state);

    // We need 2 extra stack spaces to store preallocated memory and error/panic metatable
    let extra_stack = if nargs < 2 { 2 - nargs } else { 1 };
    ffi::luaL_checkstack(
        state,
        extra_stack,
        cstr!("not enough stack space for callback error handling"),
    );

    // We cannot shadow Rust errors with Lua ones, we pre-allocate enough memory
    // to store a wrapped error or panic *before* we proceed.
    let ud = ffi::lua_newuserdata(
        state,
        mem::size_of::<WrappedError>().max(mem::size_of::<WrappedPanic>()),
    );
    ffi::lua_rotate(state, 1, 1);

    match catch_unwind(AssertUnwindSafe(|| f(nargs))) {
        Ok(Ok(r)) => {
            ffi::lua_remove(state, 1);
            r
        }
        Ok(Err(err)) => {
            ffi::lua_settop(state, 1);

            let wrapped_error = ud as *mut WrappedError;
            ptr::write(wrapped_error, WrappedError(err));
            get_gc_metatable_for::<WrappedError>(state);
            ffi::lua_setmetatable(state, -2);

            // Convert to CallbackError and attach traceback
            let traceback = if ffi::lua_checkstack(state, ffi::LUA_TRACEBACK_STACK) != 0 {
                ffi::luaL_traceback(state, state, ptr::null(), 0);
                let traceback = to_string(state, -1);
                ffi::lua_pop(state, 1);
                traceback
            } else {
                "<not enough stack space for traceback>".to_string()
            };
            let cause = Arc::new((*wrapped_error).0.clone());
            (*wrapped_error).0 = Error::CallbackError { traceback, cause };

            ffi::lua_error(state)
        }
        Err(p) => {
            ffi::lua_settop(state, 1);
            ptr::write(ud as *mut WrappedPanic, WrappedPanic(Some(p)));
            get_gc_metatable_for::<WrappedPanic>(state);
            ffi::lua_setmetatable(state, -2);
            ffi::lua_error(state)
        }
    }
}
// In the context of a lua callback, this will call the given function and if the given function
// returns an error, *or if the given function panics*, this will result in a call to `lua_error` (a
// longjmp). The error or panic is wrapped in such a way that when calling `pop_error` back on
// the Rust side, it will resume the panic.
//
// This function assumes the structure of the stack at the beginning of a callback, that the only
// elements on the stack are the arguments to the callback.
//
// This function uses some of the bottom of the stack for error handling, the given callback will be
// given the number of arguments available as an argument, and should return the number of returns
// as normal, but cannot assume that the arguments available start at 0.
In the context of a lua callback, this will call the given function and if the given function
returns an error, *or if the given function panics*, this will result in a call to `lua_error` (a
longjmp). The error or panic is wrapped in such a way that when calling `pop_error` back on
the Rust side, it will resume the panic.

This function assumes the structure of the stack at the beginning of a callback, that the only
elements on the stack are the arguments to the callback.

This function uses some of the bottom of the stack for error handling, the given callback will be
given the number of arguments available as an argument, and should return the number of returns
as normal, but cannot assume that the arguments available start at 0.
In the context of a lua callback this will call the given function and if the given function returns an error * or if the given function panics * this will result in a call to ` lua_error ` ( a longjmp ) . The error or panic is wrapped in such a way that when calling ` pop_error ` back on the Rust side it will resume the panic . This function assumes the structure of the stack at the beginning of a callback that the only elements on the stack are the arguments to the callback . This function uses some of the bottom of the stack for error handling the given callback will be given the number of arguments available as an argument and should return the number of returns as normal but cannot assume that the arguments available start at 0 .
pub unsafe fn callback_error<F, R>(state: *mut ffi::lua_State, f: F) -> R
where
    F: FnOnce(c_int) -> Result<R>,
{
    let nargs = ffi::lua_gettop(state);
    // We need 2 extra stack spaces to store preallocated memory and error/panic metatable
    let extra_stack = if nargs < 2 { 2 - nargs } else { 1 };
    ffi::luaL_checkstack(
        state,
        extra_stack,
        cstr!("not enough stack space for callback error handling"),
    );
    // We cannot shadow Rust errors with Lua ones, we pre-allocate enough memory
    // to store a wrapped error or panic *before* we proceed.
    let ud = ffi::lua_newuserdata(
        state,
        mem::size_of::<WrappedError>().max(mem::size_of::<WrappedPanic>()),
    );
    ffi::lua_rotate(state, 1, 1);
    match catch_unwind(AssertUnwindSafe(|| f(nargs))) {
        Ok(Ok(r)) => {
            ffi::lua_remove(state, 1);
            r
        }
        Ok(Err(err)) => {
            ffi::lua_settop(state, 1);
            let wrapped_error = ud as *mut WrappedError;
            ptr::write(wrapped_error, WrappedError(err));
            get_gc_metatable_for::<WrappedError>(state);
            ffi::lua_setmetatable(state, -2);
            // Convert to CallbackError and attach traceback
            let traceback = if ffi::lua_checkstack(state, ffi::LUA_TRACEBACK_STACK) != 0 {
                ffi::luaL_traceback(state, state, ptr::null(), 0);
                let traceback = to_string(state, -1);
                ffi::lua_pop(state, 1);
                traceback
            } else {
                "<not enough stack space for traceback>".to_string()
            };
            let cause = Arc::new((*wrapped_error).0.clone());
            (*wrapped_error).0 = Error::CallbackError { traceback, cause };
            ffi::lua_error(state)
        }
        Err(p) => {
            ffi::lua_settop(state, 1);
            ptr::write(ud as *mut WrappedPanic, WrappedPanic(Some(p)));
            get_gc_metatable_for::<WrappedPanic>(state);
            ffi::lua_setmetatable(state, -2);
            ffi::lua_error(state)
        }
    }
}
pub unsafe fn callback_error < F , R > ( state : * mut ffi :: lua_State , f : F ) -> R where F : FnOnce ( c_int ) -> Result < R > , { let nargs = ffi :: lua_gettop ( state ) ; // We need 2 extra stack spaces to store preallocated memory and error/panic metatable let extra_stack = if nargs < 2 { 2 - nargs } else { 1 } ; ffi :: luaL_checkstack ( state , extra_stack , cstr ! ( " " ) , ) ; // We cannot shadow Rust errors with Lua ones, we pre-allocate enough memory // to store a wrapped error or panic *before* we proceed. let ud = ffi :: lua_newuserdata ( state , mem :: size_of :: < WrappedError > ( ) . max ( mem :: size_of :: < WrappedPanic > ( ) ) , ) ; ffi :: lua_rotate ( state , 1 , 1 ) ; match catch_unwind ( AssertUnwindSafe ( | | f ( nargs ) ) ) { Ok ( Ok ( r ) ) => { ffi :: lua_remove ( state , 1 ) ; r } Ok ( Err ( err ) ) => { ffi :: lua_settop ( state , 1 ) ; let wrapped_error = ud as * mut WrappedError ; ptr :: write ( wrapped_error , WrappedError ( err ) ) ; get_gc_metatable_for :: < WrappedError > ( state ) ; ffi :: lua_setmetatable ( state , - 2 ) ; // Convert to CallbackError and attach traceback let traceback = if ffi :: lua_checkstack ( state , ffi :: LUA_TRACEBACK_STACK ) != 0 { ffi :: luaL_traceback ( state , state , ptr :: null ( ) , 0 ) ; let traceback = to_string ( state , - 1 ) ; ffi :: lua_pop ( state , 1 ) ; traceback } else { " " . to_string ( ) } ; let cause = Arc :: new ( ( * wrapped_error ) . 0 . clone ( ) ) ; ( * wrapped_error ) . 0 = Error :: CallbackError { traceback , cause } ; ffi :: lua_error ( state ) } Err ( p ) => { ffi :: lua_settop ( state , 1 ) ; ptr :: write ( ud as * mut WrappedPanic , WrappedPanic ( Some ( p ) ) ) ; get_gc_metatable_for :: < WrappedPanic > ( state ) ; ffi :: lua_setmetatable ( state , - 2 ) ; ffi :: lua_error ( state ) } } }
In the context of a lua callback, this will call the given function and if the given function
returns an error, *or if the given function panics*, this will result in a call to `lua_error` (a
longjmp).
In the context of a lua callback this will call the given function and if the given function returns an error * or if the given function panics * this will result in a call to ` lua_error ` ( a longjmp ) .
state
*mut ffi::lua_State
f
F
state
*mut ffi::lua_State
f
F