1use std::{borrow::Cow, marker::PhantomData};
2
3use mlua::{FromLua, FromLuaMulti, Function, IntoLua, IntoLuaMulti, Lua, Value};
4
5use crate::MaybeSend;
6
7use super::{Type, Typed, TypedMultiValue};
8
9#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord)]
11pub struct Param {
12 pub doc: Option<Cow<'static, str>>,
13 pub name: Option<Cow<'static, str>>,
15 pub(crate) ty: Type,
17}
18
19impl Param {
20 pub fn set_name(&mut self, name: impl Into<Cow<'static, str>>) -> &mut Self {
22 self.name = Some(name.into());
23 self
24 }
25
26 pub fn set_doc(&mut self, doc: impl Into<Cow<'static, str>>) -> &mut Self {
28 self.doc = Some(doc.into());
29 self
30 }
31}
32
33#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord)]
35pub struct Return {
36 pub doc: Option<Cow<'static, str>>,
37 pub(crate) ty: Type,
39}
40
41impl Return {
42 pub fn set_doc(&mut self, doc: impl Into<Cow<'static, str>>) -> &mut Self {
44 self.doc = Some(doc.into());
45 self
46 }
47}
48
49impl<I: Into<Cow<'static, str>>> From<(I, Type)> for Param {
50 fn from((name, ty): (I, Type)) -> Self {
51 Param {
52 doc: None,
53 name: Some(name.into()),
54 ty,
55 }
56 }
57}
58
59impl From<Type> for Param {
60 fn from(value: Type) -> Self {
61 Param {
62 doc: None,
63 name: None,
64 ty: value,
65 }
66 }
67}
68
69pub trait IntoTypedFunction<'lua, Params: TypedMultiValue, Response: TypedMultiValue> {
72 fn into_typed_function(
73 self,
74 lua: &'lua Lua,
75 ) -> mlua::Result<TypedFunction<'lua, Params, Response>>;
76}
77
78impl<'lua, F, Params, Response> IntoTypedFunction<'lua, Params, Response> for F
79where
80 Params: TypedMultiValue + FromLuaMulti<'lua>,
81 Response: TypedMultiValue + IntoLuaMulti<'lua>,
82 F: Fn(&'lua Lua, Params) -> mlua::Result<Response> + MaybeSend + 'static,
83{
84 fn into_typed_function(
85 self,
86 lua: &'lua Lua,
87 ) -> mlua::Result<TypedFunction<'lua, Params, Response>> {
88 Ok(TypedFunction {
89 inner: lua.create_function(self)?,
90 _p: PhantomData,
91 _r: PhantomData,
92 })
93 }
94}
95
96impl<'lua, Params, Response> IntoTypedFunction<'lua, Params, Response> for Function<'lua>
97where
98 Params: TypedMultiValue + FromLuaMulti<'lua>,
99 Response: TypedMultiValue + IntoLuaMulti<'lua>,
100{
101 fn into_typed_function(
102 self,
103 _lua: &'lua Lua,
104 ) -> mlua::Result<TypedFunction<'lua, Params, Response>> {
105 Ok(TypedFunction {
106 inner: self,
107 _p: PhantomData,
108 _r: PhantomData,
109 })
110 }
111}
112
113impl<'lua, Params, Response> IntoTypedFunction<'lua, Params, Response>
114 for &TypedFunction<'lua, Params, Response>
115where
116 Params: TypedMultiValue + FromLuaMulti<'lua>,
117 Response: TypedMultiValue + IntoLuaMulti<'lua>,
118{
119 fn into_typed_function(
120 self,
121 _lua: &'lua Lua,
122 ) -> mlua::Result<TypedFunction<'lua, Params, Response>> {
123 Ok(TypedFunction {
124 inner: self.inner.clone(),
125 _p: PhantomData,
126 _r: PhantomData,
127 })
128 }
129}
130
131impl<'lua, Params, Response> IntoTypedFunction<'lua, Params, Response> for ()
132where
133 Params: TypedMultiValue + FromLuaMulti<'lua>,
134 Response: TypedMultiValue + IntoLuaMulti<'lua>,
135{
136 fn into_typed_function(
137 self,
138 lua: &'lua Lua,
139 ) -> mlua::Result<TypedFunction<'lua, Params, Response>> {
140 Ok(TypedFunction {
141 inner: lua.create_function(|_, _: Params| Ok(()))?,
142 _p: PhantomData,
143 _r: PhantomData,
144 })
145 }
146}
147
148pub struct TypedFunction<'lua, Params, Response>
152where
153 Params: TypedMultiValue,
154 Response: TypedMultiValue,
155{
156 inner: Function<'lua>,
157 _p: PhantomData<Params>,
158 _r: PhantomData<Response>,
159}
160
161impl<'lua, Params, Response> TypedFunction<'lua, Params, Response>
162where
163 Params: TypedMultiValue + IntoLuaMulti<'lua>,
164 Response: TypedMultiValue + FromLuaMulti<'lua>,
165{
166 pub fn call(&self, params: Params) -> mlua::Result<Response> {
169 self.inner.call::<Params, Response>(params)
170 }
171
172 pub unsafe fn call_unsafe(&self, params: Params) -> Response {
179 self.inner.call::<Params, Response>(params).unwrap()
180 }
181
182 pub fn from_rust<F>(&self, lua: &'lua Lua, func: F) -> mlua::Result<Self>
186 where
187 Params: TypedMultiValue + FromLuaMulti<'lua>,
188 Response: TypedMultiValue + IntoLuaMulti<'lua>,
189 F: Fn(&'lua Lua, Params) -> mlua::Result<Response> + MaybeSend + 'static,
190 {
191 Ok(Self {
192 inner: lua.create_function(func)?,
193 _p: PhantomData,
194 _r: PhantomData,
195 })
196 }
197}
198
199impl<'lua, Params, Response> FromLua<'lua> for TypedFunction<'lua, Params, Response>
200where
201 Params: TypedMultiValue,
202 Response: TypedMultiValue,
203{
204 fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> mlua::prelude::LuaResult<Self> {
205 Ok(Self {
206 inner: FromLua::from_lua(value, lua)?,
207 _p: PhantomData,
208 _r: PhantomData,
209 })
210 }
211}
212
213impl<'lua, Params, Response> IntoLua<'lua> for TypedFunction<'lua, Params, Response>
214where
215 Params: TypedMultiValue,
216 Response: TypedMultiValue,
217{
218 fn into_lua(self, _lua: &'lua Lua) -> mlua::prelude::LuaResult<Value<'lua>> {
219 Ok(Value::Function(self.inner))
220 }
221}
222
223impl<'lua, Params, Response> Typed for TypedFunction<'lua, Params, Response>
224where
225 Params: TypedMultiValue,
226 Response: TypedMultiValue,
227{
228 fn ty() -> Type {
229 Type::Function {
230 params: Params::get_types_as_params(),
231 returns: Response::get_types().into_iter().map(|ty| Return { doc: None, ty }).collect(),
232 }
233 }
234}