elua/src/function.rs

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 }