elua/src/function.rs

170 lines
4.5 KiB
Rust
Raw Normal View History

2024-01-22 03:53:53 +00:00
use std::ffi::CStr;
use crate::{LuaRef, FromLuaStack, State, PushToLuaStack};
use mlua_sys as lua;
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 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 exec<A, R>(&self, args: A) -> crate::Result<R>
where
A: FunctionArgs,
R: FunctionResults<'a>,
{
unsafe {
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)
}
}
}
pub trait FunctionArgs {
fn len(&self) -> usize;
fn push_args_to_lua_stack(&self, state: &State) -> crate::Result<()>;
}
impl<'a, T> FunctionArgs for T
where
T: PushToLuaStack,
{
fn len(&self) -> usize {
1
}
fn push_args_to_lua_stack(&self, state: &State) -> crate::Result<()> {
unsafe {
self.push_to_lua_stack(state)?;
}
Ok(())
}
}
pub trait FunctionResults<'a>: Sized {
fn len() -> usize;
fn results_from_lua_stack(state: &'a State) -> crate::Result<Self>;
}
impl<'a> FunctionResults<'a> for () {
fn len() -> usize {
0
}
fn results_from_lua_stack(_state: &'a State) -> crate::Result<Self> {
Ok(())
}
}
impl<'a, T: FromLuaStack<'a>> FunctionResults<'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<$first: PushToLuaStack, $($name: PushToLuaStack,)+> FunctionArgs 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: &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>,)+> FunctionResults<'a> for ($first, $($name,)+) {
fn len() -> usize {
$count
}
fn results_from_lua_stack(state: &'a State) -> crate::Result<Self> {
Ok(unsafe { ( $first::from_lua_stack(state)?, $( $name::from_lua_stack(state)?, )+ ) })
}
}
impl_function_arg_tuple!( $count - 1, $( $name ),+ );
);
// implements FunctionArgs and FunctionResults for a tuple with a single element
( $count: expr, $only: tt ) => {
#[allow(non_snake_case)]
impl<$only: PushToLuaStack> FunctionArgs for ($only,) {
fn len(&self) -> usize {
1
}
fn push_args_to_lua_stack(&self, state: &State) -> crate::Result<()> {
let (a,) = self;
unsafe {
a.push_to_lua_stack(state)?;
}
Ok(())
}
}
impl<'a, $only: FromLuaStack<'a>> FunctionResults<'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 }