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