diff --git a/ewext/noita_api/src/lib.rs b/ewext/noita_api/src/lib.rs index 77daa5b4..20b8c2b1 100644 --- a/ewext/noita_api/src/lib.rs +++ b/ewext/noita_api/src/lib.rs @@ -14,6 +14,7 @@ noita_api_macro::generate_components!(); pub mod raw { use super::{Color, ComponentID, EntityID, Obj}; + use crate::lua::LuaPutValue; use std::borrow::Cow; use crate::lua::LuaState; diff --git a/ewext/noita_api/src/lua.rs b/ewext/noita_api/src/lua.rs index 4c91522e..ef544f37 100644 --- a/ewext/noita_api/src/lua.rs +++ b/ewext/noita_api/src/lua.rs @@ -1,6 +1,7 @@ pub mod lua_bindings; use std::{ + borrow::Cow, cell::Cell, ffi::{c_char, c_int, CStr}, mem, slice, @@ -10,6 +11,8 @@ use std::{ use eyre::{bail, Context, OptionExt}; use lua_bindings::{lua_CFunction, lua_State, Lua51, LUA_GLOBALSINDEX}; +use crate::{Color, ComponentID, EntityID, Obj}; + thread_local! { static CURRENT_LUA_STATE: Cell> = Cell::default(); } @@ -121,6 +124,7 @@ impl LuaState { } } +/// Used for types that can be returned from functions that were defined in rust to lua. pub trait LuaFnRet { fn do_return(self, lua: LuaState) -> c_int; } @@ -150,3 +154,93 @@ impl LuaFnRet for eyre::Result { } } } + +/// Trait for arguments that can be put on lua stack. +pub(crate) trait LuaPutValue { + fn put(&self, lua: LuaState); + fn is_non_empty(&self) -> bool { + true + } +} + +impl LuaPutValue for i32 { + fn put(&self, lua: LuaState) { + lua.push_integer(*self as isize); + } +} + +impl LuaPutValue for isize { + fn put(&self, lua: LuaState) { + lua.push_integer(*self); + } +} + +impl LuaPutValue for u32 { + fn put(&self, lua: LuaState) { + lua.push_integer(unsafe { mem::transmute::<_, i32>(*self) as isize }); + } +} + +impl LuaPutValue for f64 { + fn put(&self, lua: LuaState) { + lua.push_number(*self); + } +} + +impl LuaPutValue for bool { + fn put(&self, lua: LuaState) { + lua.push_bool(*self); + } +} + +impl LuaPutValue for Cow<'_, str> { + fn put(&self, lua: LuaState) { + lua.push_string(self.as_ref()); + } +} + +impl LuaPutValue for str { + fn put(&self, lua: LuaState) { + lua.push_string(self); + } +} + +impl LuaPutValue for EntityID { + fn put(&self, lua: LuaState) { + self.0.put(lua); + } +} + +impl LuaPutValue for ComponentID { + fn put(&self, lua: LuaState) { + self.0.put(lua); + } +} + +impl LuaPutValue for Color { + fn put(&self, _lua: LuaState) { + todo!() + } +} + +impl LuaPutValue for Obj { + fn put(&self, _lua: LuaState) { + todo!() + } +} + +impl LuaPutValue for Option { + fn put(&self, lua: LuaState) { + match self { + Some(val) => val.put(lua), + None => lua.push_nil(), + } + } + + fn is_non_empty(&self) -> bool { + match self { + Some(val) => val.is_non_empty(), + None => false, + } + } +} diff --git a/ewext/noita_api_macro/src/lib.rs b/ewext/noita_api_macro/src/lib.rs index d2c73078..0dab6765 100644 --- a/ewext/noita_api_macro/src/lib.rs +++ b/ewext/noita_api_macro/src/lib.rs @@ -228,19 +228,23 @@ fn generate_code_for_api_fn(api_fn: ApiFn) -> proc_macro2::TokenStream { } }); - let put_args = api_fn.args.iter().map(|arg| { - let optional = arg.default.is_some(); + let put_args_pre = api_fn.args.iter().enumerate().map(|(i, arg)| { let arg_name = format_ident!("{}", arg.name); - let arg_push = arg.typ.generate_lua_push(arg_name.clone()); - if optional { - quote! { - match #arg_name { - Some(#arg_name) => #arg_push, - None => lua.push_nil(), - } + let i = i as i32; + quote! { + if LuaPutValue::is_non_empty(&#arg_name) { + last_non_empty = #i; + } + } + }); + + let put_args = api_fn.args.iter().enumerate().map(|(i, arg)| { + let arg_name = format_ident!("{}", arg.name); + let i = i as i32; + quote! { + if #i <= last_non_empty { + LuaPutValue::put(&#arg_name, lua); } - } else { - arg_push } }); @@ -266,7 +270,6 @@ fn generate_code_for_api_fn(api_fn: ApiFn) -> proc_macro2::TokenStream { let fn_name_c = name_to_c_literal(api_fn.fn_name); - let arg_count = api_fn.args.len() as i32; let ret_count = api_fn.rets.len() as i32; quote! { @@ -275,9 +278,12 @@ fn generate_code_for_api_fn(api_fn: ApiFn) -> proc_macro2::TokenStream { let lua = LuaState::current()?; lua.get_global(#fn_name_c); - #(#put_args;)* - lua.call(#arg_count, #ret_count); + let mut last_non_empty: i32 = -1; + #(#put_args_pre)* + #(#put_args)* + + lua.call(last_non_empty+1, #ret_count); let ret = Ok(#ret_expr); lua.pop_last_n(#ret_count);