use std::{borrow::Cow, marker::PhantomData};
use mlua::{FromLua, FromLuaMulti, Function, IntoLua, IntoLuaMulti, Lua, Value};
use crate::MaybeSend;
use super::{Type, Typed, TypedMultiValue};
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord)]
pub struct Param {
pub name: Option<Cow<'static, str>>,
pub ty: Type,
}
impl<I: Into<Cow<'static, str>>> From<(I, Type)> for Param {
fn from((name, ty): (I, Type)) -> Self {
Param {
name: Some(name.into()),
ty,
}
}
}
impl From<Type> for Param {
fn from(value: Type) -> Self {
Param {
name: None,
ty: value,
}
}
}
pub trait IntoTypedFunction<'lua, Params: TypedMultiValue, Response: TypedMultiValue> {
fn into_typed_function(
self,
lua: &'lua Lua,
) -> mlua::Result<TypedFunction<'lua, Params, Response>>;
}
impl<'lua, F, Params, Response> IntoTypedFunction<'lua, Params, Response> for F
where
Params: TypedMultiValue + FromLuaMulti<'lua>,
Response: TypedMultiValue + IntoLuaMulti<'lua>,
F: Fn(&'lua Lua, Params) -> mlua::Result<Response> + MaybeSend + 'static,
{
fn into_typed_function(
self,
lua: &'lua Lua,
) -> mlua::Result<TypedFunction<'lua, Params, Response>> {
Ok(TypedFunction {
inner: lua.create_function(self)?,
_p: PhantomData,
_r: PhantomData,
})
}
}
impl<'lua, Params, Response> IntoTypedFunction<'lua, Params, Response> for Function<'lua>
where
Params: TypedMultiValue + FromLuaMulti<'lua>,
Response: TypedMultiValue + IntoLuaMulti<'lua>,
{
fn into_typed_function(
self,
_lua: &'lua Lua,
) -> mlua::Result<TypedFunction<'lua, Params, Response>> {
Ok(TypedFunction {
inner: self,
_p: PhantomData,
_r: PhantomData,
})
}
}
impl<'lua, Params, Response> IntoTypedFunction<'lua, Params, Response>
for &TypedFunction<'lua, Params, Response>
where
Params: TypedMultiValue + FromLuaMulti<'lua>,
Response: TypedMultiValue + IntoLuaMulti<'lua>,
{
fn into_typed_function(
self,
_lua: &'lua Lua,
) -> mlua::Result<TypedFunction<'lua, Params, Response>> {
Ok(TypedFunction {
inner: self.inner.clone(),
_p: PhantomData,
_r: PhantomData,
})
}
}
impl<'lua, Params, Response> IntoTypedFunction<'lua, Params, Response> for ()
where
Params: TypedMultiValue + FromLuaMulti<'lua>,
Response: TypedMultiValue + IntoLuaMulti<'lua>,
{
fn into_typed_function(
self,
lua: &'lua Lua,
) -> mlua::Result<TypedFunction<'lua, Params, Response>> {
Ok(TypedFunction {
inner: lua.create_function(|_, _: Params| Ok(()))?,
_p: PhantomData,
_r: PhantomData,
})
}
}
pub struct TypedFunction<'lua, Params, Response>
where
Params: TypedMultiValue,
Response: TypedMultiValue,
{
inner: Function<'lua>,
_p: PhantomData<Params>,
_r: PhantomData<Response>,
}
impl<'lua, Params, Response> TypedFunction<'lua, Params, Response>
where
Params: TypedMultiValue + IntoLuaMulti<'lua>,
Response: TypedMultiValue + FromLuaMulti<'lua>,
{
pub fn call(&self, params: Params) -> mlua::Result<Response> {
self.inner.call::<Params, Response>(params)
}
pub unsafe fn call_unsafe(&self, params: Params) -> Response {
self.inner.call::<Params, Response>(params).unwrap()
}
pub fn from_rust<F>(&self, lua: &'lua Lua, func: F) -> mlua::Result<Self>
where
Params: TypedMultiValue + FromLuaMulti<'lua>,
Response: TypedMultiValue + IntoLuaMulti<'lua>,
F: Fn(&'lua Lua, Params) -> mlua::Result<Response> + MaybeSend + 'static,
{
Ok(Self {
inner: lua.create_function(func)?,
_p: PhantomData,
_r: PhantomData,
})
}
}
impl<'lua, Params, Response> FromLua<'lua> for TypedFunction<'lua, Params, Response>
where
Params: TypedMultiValue,
Response: TypedMultiValue,
{
fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> mlua::prelude::LuaResult<Self> {
Ok(Self {
inner: FromLua::from_lua(value, lua)?,
_p: PhantomData,
_r: PhantomData,
})
}
}
impl<'lua, Params, Response> IntoLua<'lua> for TypedFunction<'lua, Params, Response>
where
Params: TypedMultiValue,
Response: TypedMultiValue,
{
fn into_lua(self, _lua: &'lua Lua) -> mlua::prelude::LuaResult<Value<'lua>> {
Ok(Value::Function(self.inner))
}
}
impl<'lua, Params, Response> Typed for TypedFunction<'lua, Params, Response>
where
Params: TypedMultiValue,
Response: TypedMultiValue,
{
fn ty() -> Type {
Type::Function {
params: Params::get_types_as_params(),
returns: Response::get_types(),
}
}
}