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