Improve module mode:
- Don't hide module function inside `luaopen_%` function. - Raise Lua exception instead of panic if module function returns error.
This commit is contained in:
parent
3b9d8a7b5f
commit
08ffeb0ca9
|
@ -32,3 +32,8 @@ fn rust_module_second(lua: &Lua) -> LuaResult<LuaTable> {
|
|||
exports.set("userdata", lua.create_userdata(MyUserData(123))?)?;
|
||||
Ok(exports)
|
||||
}
|
||||
|
||||
#[mlua::lua_module]
|
||||
fn rust_module_error(_: &Lua) -> LuaResult<LuaTable> {
|
||||
Err("custom module error".to_lua_err())
|
||||
}
|
||||
|
|
|
@ -1,39 +1,38 @@
|
|||
use proc_macro::TokenStream;
|
||||
use proc_macro2::{Ident, Span};
|
||||
use quote::quote_spanned;
|
||||
use syn::{parse_macro_input, spanned::Spanned, AttributeArgs, Error, ItemFn};
|
||||
use quote::quote;
|
||||
use syn::{parse_macro_input, AttributeArgs, Error, ItemFn};
|
||||
|
||||
#[cfg(feature = "macros")]
|
||||
use {
|
||||
crate::chunk::Chunk, proc_macro::TokenTree, proc_macro2::TokenStream as TokenStream2,
|
||||
proc_macro_error::proc_macro_error, quote::quote,
|
||||
proc_macro_error::proc_macro_error,
|
||||
};
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn lua_module(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let args = parse_macro_input!(attr as AttributeArgs);
|
||||
let item = parse_macro_input!(item as ItemFn);
|
||||
let func = parse_macro_input!(item as ItemFn);
|
||||
|
||||
if !args.is_empty() {
|
||||
let err = Error::new(Span::call_site(), "the number of arguments must be zero")
|
||||
let err = Error::new(Span::call_site(), "the macro does not support arguments")
|
||||
.to_compile_error();
|
||||
return err.into();
|
||||
}
|
||||
|
||||
let span = item.span();
|
||||
let item_name = item.sig.ident.clone();
|
||||
let ext_entrypoint_name = Ident::new(&format!("luaopen_{}", item.sig.ident), Span::call_site());
|
||||
let func_name = func.sig.ident.clone();
|
||||
let ext_entrypoint_name = Ident::new(&format!("luaopen_{}", func_name), Span::call_site());
|
||||
|
||||
let wrapped = quote_spanned! { span =>
|
||||
mlua::require_module_feature!();
|
||||
let wrapped = quote! {
|
||||
::mlua::require_module_feature!();
|
||||
|
||||
#func
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn #ext_entrypoint_name(state: *mut mlua::lua_State) -> std::os::raw::c_int {
|
||||
#item
|
||||
|
||||
mlua::Lua::init_from_ptr(state)
|
||||
.entrypoint1(#item_name)
|
||||
.unwrap()
|
||||
unsafe extern "C" fn #ext_entrypoint_name(state: *mut ::mlua::lua_State) -> ::std::os::raw::c_int {
|
||||
::mlua::Lua::init_from_ptr(state)
|
||||
.entrypoint1(#func_name)
|
||||
.expect("cannot initialize module")
|
||||
}
|
||||
};
|
||||
|
||||
|
|
10
src/lua.rs
10
src/lua.rs
|
@ -536,7 +536,15 @@ impl Lua {
|
|||
F: 'static + MaybeSend + Fn(&'callback Lua) -> Result<R>,
|
||||
{
|
||||
let cb = self.create_callback(Box::new(move |lua, _| func(lua)?.to_lua_multi(lua)))?;
|
||||
unsafe { self.push_value(cb.call(())?).map(|_| 1) }
|
||||
match cb.call(()) {
|
||||
Ok(res) => unsafe { self.push_value(res)? },
|
||||
Err(err) => unsafe {
|
||||
self.push_value(Value::Error(err))?;
|
||||
// This longjmp is undesired, but we cannot wrap it to a C
|
||||
ffi::lua_error(self.state)
|
||||
},
|
||||
}
|
||||
Ok(1)
|
||||
}
|
||||
|
||||
/// Sets a 'hook' function that will periodically be called as Lua code executes.
|
||||
|
|
|
@ -28,6 +28,19 @@ fn test_module_multi() -> Result<()> {
|
|||
.exec()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_module_error() -> Result<()> {
|
||||
let lua = make_lua()?;
|
||||
lua.load(
|
||||
r#"
|
||||
local ok, err = pcall(require, "rust_module.error")
|
||||
assert(not ok)
|
||||
assert(string:find(tostring(err), "custom module error"))
|
||||
"#,
|
||||
)
|
||||
.exec()
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
feature = "lua54",
|
||||
feature = "lua53",
|
||||
|
|
Loading…
Reference in a new issue