Add mlua_derive proc macro module

This commit is contained in:
Alex Orlenko 2019-10-01 18:11:51 +01:00
parent cade76137a
commit 224ed8ff52
4 changed files with 67 additions and 4 deletions

View File

@ -13,6 +13,11 @@ license = "MIT"
# [badges]
# travis-ci = { repository = "khvzak/mlua", branch = "master" }
[workspace]
members = [
"mlua_derive",
]
[dependencies]
libc = { version = "0.2" }
num-traits = { version = "0.2.6" }

13
mlua_derive/Cargo.toml Normal file
View File

@ -0,0 +1,13 @@
[package]
name = "mlua_derive"
version = "0.1.0"
authors = ["Alex Orlenko <zxteam@protonmail.com>"]
edition = "2018"
[lib]
proc-macro = true
[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
syn = { version = "1.0", features = ["full"] }

35
mlua_derive/src/lib.rs Normal file
View File

@ -0,0 +1,35 @@
extern crate proc_macro;
use proc_macro::TokenStream;
use proc_macro2::{Ident, Span};
use quote::quote_spanned;
use syn::{parse_macro_input, spanned::Spanned, AttributeArgs, Error, ItemFn};
#[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);
if args.len() > 0 {
let err = Error::new(Span::call_site(), "the number of arguments must be zero")
.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 wrapped = quote_spanned! { span =>
#[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()
}
};
wrapped.into()
}

View File

@ -100,6 +100,18 @@ impl Lua {
}
}
// Executes module entrypoint function, which returns only one Value.
// The returned value then pushed to the Lua stack.
#[doc(hidden)]
pub fn entrypoint1<'lua, 'callback, R, F>(&'lua self, func: F) -> Result<c_int>
where
R: ToLua<'callback>,
F: 'static + Send + 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) }
}
/// Returns true if the garbage collector is currently running automatically.
pub fn gc_is_running(&self) -> bool {
unsafe { ffi::lua_gc(self.main_state, ffi::LUA_GCISRUNNING, 0) != 0 }
@ -718,8 +730,7 @@ impl Lua {
}
// Uses 2 stack spaces, does not call checkstack
// TODO: return to original
pub unsafe fn push_value(&self, value: Value) -> Result<()> {
pub(crate) unsafe fn push_value(&self, value: Value) -> Result<()> {
match value {
Value::Nil => {
ffi::lua_pushnil(self.state);
@ -770,8 +781,7 @@ impl Lua {
}
// Uses 2 stack spaces, does not call checkstack
// TODO: return to original
pub unsafe fn pop_value(&self) -> Value {
pub(crate) unsafe fn pop_value(&self) -> Value {
match ffi::lua_type(self.state, -1) {
ffi::LUA_TNIL => {
ffi::lua_pop(self.state, 1);