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