192 lines
5.4 KiB
Rust
192 lines
5.4 KiB
Rust
use std::ffi::CStr;
|
|
|
|
use crate::{AsLua, FromLuaStack, LuaRef, PushToLuaStack, StackGuard, State};
|
|
|
|
use mlua_sys as lua;
|
|
|
|
#[derive(Clone)]
|
|
pub struct Function<'a> {
|
|
state: &'a State,
|
|
lref: LuaRef
|
|
}
|
|
|
|
impl<'a> FromLuaStack<'a> for Function<'a> {
|
|
unsafe fn from_lua_stack(state: &'a crate::State) -> crate::Result<Self> {
|
|
Ok(Self {
|
|
state,
|
|
lref: LuaRef::from_stack(state)?,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl<'a> PushToLuaStack<'a> for Function<'a> {
|
|
unsafe fn push_to_lua_stack(&self, state: &State) -> crate::Result<()> {
|
|
self.lref.push_to_lua_stack(state)
|
|
}
|
|
}
|
|
|
|
impl<'a> Function<'a> {
|
|
pub fn from_ref(state: &'a State, lref: LuaRef) -> Self {
|
|
Self {
|
|
state,
|
|
lref,
|
|
}
|
|
}
|
|
|
|
pub fn exec<A, R>(&self, args: A) -> crate::Result<R>
|
|
where
|
|
A: PushToLuaStackMulti<'a>,
|
|
R: FromLuaStackMulti<'a>,
|
|
{
|
|
unsafe {
|
|
let _g = StackGuard::new(self.state);
|
|
|
|
self.push_to_lua_stack(self.state)?;
|
|
args.push_args_to_lua_stack(self.state)?;
|
|
|
|
let arg_len = args.len() as i32;
|
|
let res_len = R::len() as i32;
|
|
let s = self.state.state_ptr();
|
|
if lua::lua_pcall(s, arg_len, res_len, 0) != 0 {
|
|
let s = lua::lua_tostring(s, -1);
|
|
let s = CStr::from_ptr(s);
|
|
let s = s.to_str().unwrap();
|
|
|
|
return Err(crate::Error::runtime(s));
|
|
}
|
|
|
|
R::results_from_lua_stack(self.state)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> AsLua<'a> for Function<'a> {
|
|
fn as_lua(&self, lua: &'a State) -> crate::Result<crate::Value<'a>> {
|
|
Ok(crate::Value::Function(self.clone()))
|
|
}
|
|
}
|
|
|
|
pub trait PushToLuaStackMulti<'a> {
|
|
fn len(&self) -> usize;
|
|
fn push_args_to_lua_stack(&self, state: &'a State) -> crate::Result<()>;
|
|
}
|
|
|
|
impl<'a, T> PushToLuaStackMulti<'a> for T
|
|
where
|
|
T: PushToLuaStack<'a>,
|
|
{
|
|
fn len(&self) -> usize {
|
|
1
|
|
}
|
|
|
|
fn push_args_to_lua_stack(&self, state: &'a State) -> crate::Result<()> {
|
|
unsafe {
|
|
self.push_to_lua_stack(state)?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
pub trait FromLuaStackMulti<'a>: Sized {
|
|
fn len() -> usize;
|
|
fn results_from_lua_stack(state: &'a State) -> crate::Result<Self>;
|
|
}
|
|
|
|
impl<'a> FromLuaStackMulti<'a> for () {
|
|
fn len() -> usize {
|
|
1
|
|
}
|
|
|
|
fn results_from_lua_stack(_state: &'a State) -> crate::Result<Self> {
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl<'a, T: FromLuaStack<'a>> FromLuaStackMulti<'a> for T {
|
|
fn len() -> usize {
|
|
1
|
|
}
|
|
|
|
fn results_from_lua_stack(state: &'a State) -> crate::Result<Self> {
|
|
unsafe { T::from_lua_stack(state) }
|
|
}
|
|
}
|
|
|
|
macro_rules! impl_function_arg_tuple {
|
|
( $count: expr, $first: tt, $( $name: tt ),+ ) => (
|
|
#[allow(non_snake_case)]
|
|
impl<'a, $first: PushToLuaStack<'a>, $($name: PushToLuaStack<'a>,)+> PushToLuaStackMulti<'a> for ($first, $($name,)+) {
|
|
fn len(&self) -> usize {
|
|
// this will end up generating $count - 1 - 1 - 1... hopefully the compiler will
|
|
// optimize that out
|
|
$count
|
|
}
|
|
|
|
fn push_args_to_lua_stack(&self, state: &'a State) -> crate::Result<()> {
|
|
let ($first, $($name,)+) = self;
|
|
|
|
unsafe {
|
|
$first.push_to_lua_stack(state)?;
|
|
$( $name.push_to_lua_stack(state)?; )+
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl<'a, $first: FromLuaStack<'a>, $($name: FromLuaStack<'a>,)+> FromLuaStackMulti<'a> for ($first, $($name,)+) {
|
|
fn len() -> usize {
|
|
$count
|
|
}
|
|
|
|
fn results_from_lua_stack(state: &'a State) -> crate::Result<Self> {
|
|
unsafe {
|
|
let ($( $name, )+ $first) = ( $( $name::from_lua_stack(state)?, )+ $first::from_lua_stack(state)? );
|
|
|
|
Ok( ($first, $( $name, )+) )
|
|
}
|
|
//Ok(unsafe { ( $( $name::from_lua_stack(state)?, )+ $first::from_lua_stack(state)? ) })
|
|
//Ok(unsafe { ( $first::from_lua_stack(state)?, $( $name::from_lua_stack(state)?, )+ ) })
|
|
}
|
|
}
|
|
|
|
impl_function_arg_tuple!( $count - 1, $( $name ),+ );
|
|
);
|
|
|
|
// implements PushToLuaStackMulti and FromLuaStackMulti for a tuple with a single element
|
|
( $count: expr, $only: tt ) => {
|
|
#[allow(non_snake_case)]
|
|
impl<'a, $only: PushToLuaStack<'a>> PushToLuaStackMulti<'a> for ($only,) {
|
|
fn len(&self) -> usize {
|
|
1
|
|
}
|
|
|
|
fn push_args_to_lua_stack(&self, state: &'a State) -> crate::Result<()> {
|
|
let (a,) = self;
|
|
|
|
unsafe {
|
|
a.push_to_lua_stack(state)?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl<'a, $only: FromLuaStack<'a>> FromLuaStackMulti<'a> for ($only,) {
|
|
fn len() -> usize {
|
|
1
|
|
}
|
|
|
|
fn results_from_lua_stack(state: &'a State) -> crate::Result<Self> {
|
|
Ok(unsafe { ( $only::from_lua_stack(state)?, ) })
|
|
}
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
// hopefully 16 is more than enough
|
|
// if you have 16 function results, and need more than 16, you NEED help
|
|
impl_function_arg_tuple! { 16, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16 }
|