Skip to main content

mlua_extras/typed/class/
standard.rs

1use std::{borrow::Cow, collections::BTreeMap};
2
3use mlua::{AnyUserData, FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, Lua};
4
5use crate::{
6    MaybeSend, ser::to_lua_repr, typed::{Field, Func, Index, IntoDocComment, StaticField, Type}
7};
8
9use super::{
10    Typed, TypedDataDocumentation, TypedDataFields, TypedDataMethods, TypedMultiValue,
11    TypedUserData,
12};
13
14#[derive(Default, Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
15pub struct TypedClass {
16    pub type_doc: Option<Cow<'static, str>>,
17
18    pub derives: Vec<String>,
19
20    pub fields: BTreeMap<Index, Field>,
21    pub static_fields: BTreeMap<Index, StaticField>,
22    pub meta_fields: BTreeMap<Index, Field>,
23    pub static_meta_fields: BTreeMap<Index, StaticField>,
24
25    pub methods: BTreeMap<Index, Func>,
26    pub meta_methods: BTreeMap<Index, Func>,
27
28    pub functions: BTreeMap<Index, Func>,
29    pub meta_functions: BTreeMap<Index, Func>,
30}
31impl TypedClass {
32    /// Check if any of there are any meta fields, functions, or methods present
33    pub fn is_meta_empty(&self) -> bool {
34        self.meta_fields.is_empty()
35            && self.static_meta_fields.is_empty()
36            && self.meta_functions.is_empty()
37            && self.meta_methods.is_empty()
38    }
39}
40
41/// Type information for a lua `class`. This happens to be a [`TypedUserData`]
42#[derive(Default, Debug, Clone)]
43pub struct TypedClassBuilder {
44    lua: Lua,
45
46    queued_doc: Option<Cow<'static, str>>,
47    queued_ty: Option<Type>,
48    queued_params: Vec<(Option<Type>, String, Option<Cow<'static, str>>)>,
49    queued_returns: Vec<(Option<Type>, Option<Cow<'static, str>>)>,
50
51    pub typed_class: TypedClass,
52}
53
54impl From<TypedClassBuilder> for Type {
55    fn from(value: TypedClassBuilder) -> Self {
56        Type::Class(Box::new(value.typed_class))
57    }
58}
59
60impl TypedClassBuilder {
61    pub fn new<T: TypedUserData>() -> Self {
62        let mut tcb = Self::default();
63        T::add_documentation(&mut tcb);
64        T::add_fields(&mut tcb);
65        T::add_methods(&mut tcb);
66        tcb
67    }
68
69    pub fn build(self) -> TypedClass {
70        self.typed_class
71    }
72
73    /// Skip/Remove a field field from the class definition
74    pub fn skip_field(mut self, idx: impl Into<Index>) -> Self {
75        self.typed_class.fields.remove(&idx.into());
76        self
77    }
78
79    /// Skip/Remove a method from the class definition
80    pub fn skip_method(mut self, idx: impl Into<Index>) -> Self {
81        self.typed_class.methods.remove(&idx.into());
82        self
83    }
84
85    /// Skip/Remove a meta method from the class definition
86    pub fn skip_meta_method(mut self, idx: impl Into<Index>) -> Self {
87        self.typed_class.meta_methods.remove(&idx.into());
88        self
89    }
90
91    /// Skip/Remove a function from the class definition
92    pub fn skip_function(mut self, idx: impl Into<Index>) -> Self {
93        self.typed_class.functions.remove(&idx.into());
94        self
95    }
96
97    /// Skip/Remove a meta function from the class definition
98    pub fn skip_meta_function(mut self, idx: impl Into<Index>) -> Self {
99        self.typed_class.meta_functions.remove(&idx.into());
100        self
101    }
102
103    /// Creates a new typed field and adds it to the class's type information
104    ///
105    /// # Example
106    ///
107    /// ```
108    /// use mlua_extras::typed::{TypedClassBuilder, Type};
109    ///
110    /// static NAME: &str = "mlua_extras";
111    ///
112    /// TypedClassBuilder::default()
113    ///     .field("data1", Type::string() | Type::nil(), "doc comment goes last")
114    ///     .field("data2", Type::array(Type::string()), ()) // Can also use `None` instead of `()`
115    ///     .field("message", Type::string(), format!("A message for {NAME}"));
116    /// ```
117    pub fn field(mut self, key: impl Into<Index>, ty: Type, doc: impl IntoDocComment) -> Self {
118        self.typed_class.fields.insert(key.into(), Field::new(ty, doc));
119        self
120    }
121
122    pub fn static_field<V>(mut self, key: impl Into<Index>, value: V, doc: impl IntoDocComment) -> Self 
123    where
124        V: Typed + IntoLua
125    {
126        let value = match value.into_lua(&self.lua) {
127            Ok(value) => to_lua_repr(&value).map_err(mlua::Error::runtime),
128            Err(err) => Err(err)
129        };
130
131        if let Ok(value) = value {
132            self.typed_class.static_fields.insert(key.into(), StaticField::new(V::ty(), doc, value));
133        }
134        self
135    }
136
137    pub fn inherit(mut self, parent: &TypedClass) -> Self {
138        self.typed_class.static_fields.extend(parent.static_fields.clone());
139        self
140    }
141
142    /// Creates a new typed function and adds it to the class's type information
143    ///
144    /// # Example
145    ///
146    /// ```
147    /// use mlua_extras::typed::{TypedClassBuilder, Type};
148    ///
149    /// TypedClassBuilder::default()
150    ///     .function::<String, ()>("greet", "Greet the given name")
151    ///     // Can use `None` instead of `()` for specifying the doc comment
152    ///     .function::<String, ()>("hello", ());
153    /// ```
154    pub fn function<Params, Returns>(
155        mut self,
156        key: impl Into<Index>,
157        doc: impl IntoDocComment,
158    ) -> Self
159    where
160        Params: TypedMultiValue,
161        Returns: TypedMultiValue,
162    {
163        self.typed_class.functions.insert(
164            key.into(),
165            Func::new::<Params, Returns>(
166                doc,
167                self.queued_params.drain(..).collect(),
168                self.queued_returns.drain(..).collect(),
169            ),
170        );
171        self
172    }
173
174    /// Creates a new typed method and adds it to the class's type information.
175    ///
176    /// As with methods in lua, the `self` parameter is implicit and has the same type as the
177    /// parent class.
178    ///
179    /// # Example
180    ///
181    /// ```
182    /// use mlua_extras::typed::{TypedClassBuilder, Type};
183    ///
184    /// TypedClassBuilder::default()
185    ///     .method::<String, ()>("greet", "Greet the given name")
186    ///     // Can use `None` instead of `()` for specifying the doc comment
187    ///     .method::<String, ()>("hello", ());
188    /// ```
189    pub fn method<Params, Returns>(
190        mut self,
191        key: impl Into<Index>,
192        doc: impl IntoDocComment,
193    ) -> Self
194    where
195        Params: TypedMultiValue,
196        Returns: TypedMultiValue,
197    {
198        self.typed_class.methods.insert(
199            key.into(),
200            Func::new::<Params, Returns>(
201                doc,
202                self.queued_params.drain(..).collect(),
203                self.queued_returns.drain(..).collect(),
204            ),
205        );
206        self
207    }
208
209    /// Creates a new typed field and adds it to the class's meta type information
210    ///
211    /// # Example
212    ///
213    /// ```
214    /// use mlua_extras::typed::{TypedClassBuilder, Type};
215    ///
216    /// static NAME: &str = "mlua_extras";
217    ///
218    /// TypedClassBuilder::default()
219    ///     .meta_field("data1", Type::string() | Type::nil(), "doc comment goes last")
220    ///     .meta_field("data2", Type::array(Type::string()), ()) // Can also use `None` instead of `()`
221    ///     .meta_field("message", Type::string(), format!("A message for {NAME}"));
222    /// ```
223    pub fn meta_field(mut self, key: impl Into<Index>, ty: Type, doc: impl IntoDocComment) -> Self {
224        self.typed_class.meta_fields.insert(key.into(), Field::new(ty, doc));
225        self
226    }
227
228    /// Creates a new typed function and adds it to the class's meta type information
229    ///
230    /// # Example
231    ///
232    /// ```
233    /// use mlua_extras::typed::{TypedClassBuilder, Type};
234    ///
235    /// TypedClassBuilder::default()
236    ///     .meta_function::<String, ()>("greet", "Greet the given name")
237    ///     // Can use `None` instead of `()` for specifying the doc comment
238    ///     .meta_function::<String, ()>("hello", ());
239    /// ```
240    pub fn meta_function<Params, Returns>(
241        mut self,
242        key: impl Into<Index>,
243        doc: impl IntoDocComment,
244    ) -> Self
245    where
246        Params: TypedMultiValue,
247        Returns: TypedMultiValue,
248    {
249        self.typed_class.meta_functions.insert(
250            key.into(),
251            Func::new::<Params, Returns>(
252                doc,
253                self.queued_params.drain(..).collect(),
254                self.queued_returns.drain(..).collect(),
255            ),
256        );
257        self
258    }
259
260    /// Creates a new typed method and adds it to the class's type information.
261    ///
262    /// As with methods in lua, the `self` parameter is implicit and has the same type as the
263    /// parent class.
264    ///
265    /// # Example
266    ///
267    /// ```
268    /// use mlua_extras::typed::{TypedClassBuilder, Type};
269    ///
270    /// static NAME: &str = "mlua_extras";
271    ///
272    /// TypedClassBuilder::default()
273    ///     .method::<String, ()>("greet", "Greet the given name")
274    ///     // Can use `None` instead of `()` for specifying the doc comment
275    ///     .method::<String, ()>("hello", ());
276    /// ```
277    pub fn meta_method<Params, Returns>(
278        mut self,
279        key: impl Into<Index>,
280        doc: impl IntoDocComment,
281    ) -> Self
282    where
283        Params: TypedMultiValue,
284        Returns: TypedMultiValue,
285    {
286        self.typed_class.meta_methods.insert(
287            key.into(),
288            Func::new::<Params, Returns>(
289                doc,
290                self.queued_params.drain(..).collect(),
291                self.queued_returns.drain(..).collect(),
292            ),
293        );
294        self
295    }
296
297    /// Add a child class that this class derives
298    pub fn derive(mut self, parent: impl std::fmt::Display) -> Self {
299        self.typed_class.derives.push(parent.to_string());
300        self
301    }
302}
303
304impl<T: TypedUserData> TypedDataDocumentation<T> for TypedClassBuilder {
305    fn add(&mut self, doc: &str) -> &mut Self {
306        if let Some(type_doc) = self.typed_class.type_doc.as_mut() {
307            *type_doc = format!("{type_doc}\n{doc}").into()
308        } else {
309            self.typed_class.type_doc = Some(doc.to_string().into())
310        }
311        self
312    }
313}
314
315impl<T: TypedUserData> TypedDataFields<T> for TypedClassBuilder {
316    fn document(&mut self, doc: impl IntoDocComment) -> &mut Self {
317        self.queued_doc = doc.into_doc_comment();
318        self
319    }
320
321    fn coerce(&mut self, ty: impl Into<Type>) -> &mut Self {
322        self.queued_ty = Some(ty.into());
323        self
324    }
325
326    fn add_field<V>(&mut self, name: impl Into<String>, value: V)
327    where
328        V: IntoLua + Clone + 'static + Typed,
329    {
330        let value = match value.into_lua(&self.lua) {
331            Ok(value) => to_lua_repr(&value).map_err(mlua::Error::runtime),
332            Err(err) => Err(err)
333        };
334
335        if let Ok(value) = value {
336            let name: Cow<'static, str> = name.into().into();
337            let ty = self.queued_ty.take().unwrap_or(V::as_param());
338            let value: Cow<'static, str> = value.into();
339
340            self.typed_class.static_fields
341                .insert(
342                    name.into(),
343                    StaticField::new(
344                        ty,
345                        self.queued_doc.take(),
346                        value,
347                    )
348                );
349        }
350    }
351
352    fn add_field_function_set<S, A, F>(&mut self, name: S, _: F)
353    where
354        S: Into<String>,
355        A: FromLua + Typed,
356        F: 'static + MaybeSend + FnMut(&Lua, AnyUserData, A) -> mlua::Result<()>,
357    {
358        let name: Cow<'static, str> = name.into().into();
359        let ty = self.queued_ty.take().unwrap_or(A::as_param());
360        self.typed_class.fields
361            .entry(name.into())
362            .and_modify({
363                let ty = ty.clone();
364                |v| {
365                    if let Some(doc) = self.queued_doc.take() {
366                        v.doc = Some(match v.doc.take() {
367                            Some(d) => format!("{d}\n{doc}").into(),
368                            None => doc
369                        });
370                    }
371                    v.ty = v.ty.clone() | ty;
372                }
373            })
374            .or_insert(Field {
375                ty,
376                doc: self.queued_doc.take().map(|v| v.into()),
377            });
378    }
379
380    fn add_field_function_get<S, R, F>(&mut self, name: S, _: F)
381    where
382        S: Into<String>,
383        R: IntoLua + Typed,
384        F: 'static + MaybeSend + Fn(&Lua, AnyUserData) -> mlua::Result<R>,
385    {
386        let name: Cow<'static, str> = name.into().into();
387        let ty = self.queued_ty.take().unwrap_or(R::as_return());
388        self.typed_class.fields
389            .entry(name.into())
390            .and_modify({
391                let ty = ty.clone();
392                |v| {
393                    if let Some(doc) = self.queued_doc.take() {
394                        v.doc = Some(match v.doc.take() {
395                            Some(d) => format!("{d}\n{doc}").into(),
396                            None => doc
397                        });
398                    }
399                    v.ty = v.ty.clone() | ty;
400                }
401            })
402            .or_insert(Field {
403                ty,
404                doc: self.queued_doc.take().map(|v| v.into()),
405            });
406    }
407
408    fn add_field_function_get_set<S, R, A, GET, SET>(&mut self, name: S, _: GET, _: SET)
409    where
410        S: Into<String>,
411        R: IntoLua + Typed,
412        A: FromLua + Typed,
413        GET: 'static + MaybeSend + Fn(&Lua, AnyUserData) -> mlua::Result<R>,
414        SET: 'static + MaybeSend + Fn(&Lua, AnyUserData, A) -> mlua::Result<()>,
415    {
416        let name: Cow<'static, str> = name.into().into();
417        let ty = self.queued_ty.take().unwrap_or(A::as_param() | R::as_return());
418        self.typed_class.fields
419            .entry(name.into())
420            .and_modify({
421                let ty = ty.clone();
422                |v| {
423                    if let Some(doc) = self.queued_doc.take() {
424                        v.doc = Some(match v.doc.take() {
425                            Some(d) => format!("{d}\n{doc}").into(),
426                            None => doc
427                        });
428                    }
429                    v.ty = v.ty.clone() | ty;
430                }
431            })
432            .or_insert(Field {
433                ty,
434                doc: self.queued_doc.take().map(|v| v.into()),
435            });
436    }
437
438    fn add_field_method_set<S, A, M>(&mut self, name: S, _: M)
439    where
440        S: Into<String>,
441        A: FromLua + Typed,
442        M: 'static + MaybeSend + FnMut(&Lua, &mut T, A) -> mlua::Result<()>,
443    {
444        let name: Cow<'static, str> = name.into().into();
445        let ty = self.queued_ty.take().unwrap_or(A::as_param());
446        self.typed_class.fields
447            .entry(name.into())
448            .and_modify({
449                let ty = ty.clone();
450                |v| {
451                    if let Some(doc) = self.queued_doc.take() {
452                        v.doc = Some(match v.doc.take() {
453                            Some(d) => format!("{d}\n{doc}").into(),
454                            None => doc
455                        });
456                    }
457                    v.ty = v.ty.clone() | ty;
458                }
459            })
460            .or_insert(Field {
461                ty,
462                doc: self.queued_doc.take().map(|v| v.into()),
463            });
464    }
465
466    fn add_field_method_get<S, R, M>(&mut self, name: S, _: M)
467    where
468        S: Into<String>,
469        R: IntoLua + Typed,
470        M: 'static + MaybeSend + Fn(&Lua, &T) -> mlua::Result<R>,
471    {
472        let name: Cow<'static, str> = name.into().into();
473        let ty = self.queued_ty.take().unwrap_or(R::as_return());
474        self.typed_class.fields
475            .entry(name.into())
476            .and_modify({
477                let ty = ty.clone();
478                |v| {
479                    if let Some(doc) = self.queued_doc.take() {
480                        v.doc = Some(match v.doc.take() {
481                            Some(d) => format!("{d}\n{doc}").into(),
482                            None => doc
483                        });
484                    }
485                    v.ty = v.ty.clone() | ty;
486                }
487            })
488            .or_insert(Field {
489                ty,
490                doc: self.queued_doc.take().map(|v| v.into()),
491            });
492    }
493
494    fn add_field_method_get_set<S, R, A, GET, SET>(&mut self, name: S, _: GET, _: SET)
495    where
496        S: Into<String>,
497        R: IntoLua + Typed,
498        A: FromLua + Typed,
499        GET: 'static + MaybeSend + Fn(&Lua, &T) -> mlua::Result<R>,
500        SET: 'static + MaybeSend + Fn(&Lua, &mut T, A) -> mlua::Result<()>,
501    {
502        let name: Cow<'static, str> = name.into().into();
503        let ty = self.queued_ty.take().unwrap_or(A::as_param() | R::as_return());
504        self.typed_class.fields
505            .entry(name.into())
506            .and_modify({
507                let ty = ty.clone();
508                |v| {
509                    if let Some(doc) = self.queued_doc.take() {
510                        v.doc = Some(match v.doc.take() {
511                            Some(d) => format!("{d}\n{doc}").into(),
512                            None => doc
513                        });
514                    }
515                    v.ty = v.ty.clone() | ty;
516                }
517            })
518            .or_insert(Field {
519                ty,
520                doc: self.queued_doc.take().map(|v| v.into()),
521            });
522    }
523
524    fn add_meta_field<V>(&mut self, meta: impl Into<String>, value: V)
525    where
526        V: IntoLua + Typed + 'static,
527    {
528        let value = match value.into_lua(&self.lua) {
529            Ok(value) => to_lua_repr(&value).map_err(mlua::Error::runtime),
530            Err(err) => Err(err)
531        };
532
533        if let Ok(value) = value {
534            let name: Cow<'static, str> = meta.into().into();
535            let ty = self.queued_ty.take().unwrap_or(V::as_param());
536            let value: Cow<'static, str> = value.into();
537
538            self.typed_class.static_meta_fields
539                .insert(
540                    name.into(),
541                    StaticField::new(
542                        ty,
543                        self.queued_doc.take(),
544                        value,
545                    )
546                );
547        }
548    }
549
550    fn add_meta_field_with<R, F>(&mut self, meta: impl Into<String>, _: F)
551        where
552            F: 'static + MaybeSend + Fn(&Lua) -> mlua::Result<R>,
553            R: IntoLua + Typed {
554
555        let name: Cow<'static, str> = meta.into().into();
556        let ty = self.queued_ty.take().unwrap_or(R::as_return());
557        self.typed_class.meta_fields
558            .entry(name.into())
559            .and_modify({
560                let ty = ty.clone();
561                |v| {
562                    if let Some(doc) = self.queued_doc.take() {
563                        v.doc = Some(match v.doc.take() {
564                            Some(d) => format!("{d}\n{doc}").into(),
565                            None => doc
566                        });
567                    }
568                    v.ty = v.ty.clone() | ty;
569                }
570            })
571            .or_insert(Field {
572                ty,
573                doc: self.queued_doc.take().map(|v| v.into()),
574            });
575    }
576}
577
578impl<T: TypedUserData> TypedDataMethods<T> for TypedClassBuilder {
579    fn document(&mut self, doc: impl IntoDocComment) -> &mut Self {
580        self.queued_doc = doc.into_doc_comment();
581        self
582    }
583
584    fn param(&mut self, name: impl std::fmt::Display, doc: impl IntoDocComment) -> &mut Self {
585        self.queued_params.push((None, name.to_string(), doc.into_doc_comment()));
586        self
587    }
588
589    fn param_as(&mut self, ty: impl Into<Type>, name: impl std::fmt::Display, doc: impl IntoDocComment) -> &mut Self {
590        self.queued_params.push((Some(ty.into()), name.to_string(), doc.into_doc_comment()));
591        self
592    }
593
594    fn ret(&mut self, doc: impl IntoDocComment) -> &mut Self {
595        if let Some(doc) = doc.into_doc_comment() {
596            self.queued_returns.push((None, Some(doc)));
597        }
598        self
599    }
600
601    
602    fn ret_as(&mut self, ty: impl Into<Type>, doc: impl IntoDocComment) -> &mut Self {
603        self.queued_returns.push((Some(ty.into()), doc.into_doc_comment()));
604        self
605    }
606
607    fn index<I: Typed>(&mut self, idx: isize, doc: impl IntoDocComment) -> &mut Self {
608        self.typed_class.fields.insert(idx.into(), Field { ty: I::as_param(), doc: doc.into_doc_comment() });
609        self
610    }
611
612    fn index_as(&mut self, idx: isize, ty: impl Into<Type>, doc: impl IntoDocComment) -> &mut Self {
613        self.typed_class.fields.insert(idx.into(), Field { ty: ty.into(), doc: doc.into_doc_comment() });
614        self
615    }
616
617    fn add_method<S, A, R, M>(&mut self, name: S, _: M)
618    where
619        S: Into<String>,
620        A: FromLuaMulti + TypedMultiValue,
621        R: IntoLuaMulti + TypedMultiValue,
622        M: 'static + MaybeSend + Fn(&Lua, &T, A) -> mlua::Result<R>,
623    {
624        let name: Cow<'static, str> = name.into().into();
625        self.typed_class.methods.insert(
626            name.into(),
627            Func::new::<A, R>(
628                self.queued_doc.take(),
629                self.queued_params.drain(..).collect(),
630                self.queued_returns.drain(..).collect(),
631            ),
632        );
633    }
634
635    fn add_function<S, A, R, F>(&mut self, name: S, _: F)
636    where
637        S: Into<String>,
638        A: FromLuaMulti + TypedMultiValue,
639        R: IntoLuaMulti + TypedMultiValue,
640        F: 'static + MaybeSend + Fn(&Lua, A) -> mlua::Result<R>,
641    {
642        let name: Cow<'static, str> = name.into().into();
643        self.typed_class.functions.insert(
644            name.into(),
645            Func::new::<A, R>(
646                self.queued_doc.take(),
647                self.queued_params.drain(..).collect(),
648                self.queued_returns.drain(..).collect(),
649            ),
650        );
651    }
652
653    fn add_method_mut<S, A, R, M>(&mut self, name: S, _: M)
654    where
655        S: Into<String>,
656        A: FromLuaMulti + TypedMultiValue,
657        R: IntoLuaMulti + TypedMultiValue,
658        M: 'static + MaybeSend + FnMut(&Lua, &mut T, A) -> mlua::Result<R>,
659    {
660        let name: Cow<'static, str> = name.into().into();
661        self.typed_class.methods.insert(
662            name.into(),
663            Func::new::<A, R>(
664                self.queued_doc.take(),
665                self.queued_params.drain(..).collect(),
666                self.queued_returns.drain(..).collect(),
667            ),
668        );
669    }
670
671    fn add_meta_method<A, R, M>(&mut self, meta: impl Into<String>, _: M)
672    where
673        A: FromLuaMulti + TypedMultiValue,
674        R: IntoLuaMulti + TypedMultiValue,
675        M: 'static + MaybeSend + Fn(&Lua, &T, A) -> mlua::Result<R>,
676    {
677        let name: Cow<'static, str> = meta.into().into();
678        self.typed_class.meta_methods.insert(
679            name.into(),
680            Func::new::<A, R>(
681                self.queued_doc.take(),
682                self.queued_params.drain(..).collect(),
683                self.queued_returns.drain(..).collect(),
684            ),
685        );
686    }
687
688    #[cfg(feature = "async")]
689    fn add_async_method<S: Into<String>, A, R, M, MR>(&mut self, name: S, _: M)
690    where
691        T: 'static,
692        M: Fn(Lua, mlua::UserDataRef<T>, A) -> MR + MaybeSend + 'static,
693        A: FromLuaMulti + TypedMultiValue,
694        MR: std::future::Future<Output = mlua::Result<R>> + MaybeSend + 'static,
695        R: IntoLuaMulti + TypedMultiValue,
696    {
697        let name: Cow<'static, str> = name.into().into();
698        self.typed_class.methods.insert(
699            name.into(),
700            Func::new::<A, R>(
701                self.queued_doc.take(),
702                self.queued_params.drain(..).collect(),
703                self.queued_returns.drain(..).collect(),
704            ),
705        );
706    }
707
708    #[cfg(feature = "async")]
709    fn add_async_method_mut<S: Into<String>, A, R, M, MR>(&mut self, name: S, _method: M)
710    where
711        T: 'static,
712        M: Fn(Lua, mlua::UserDataRefMut<T>, A) -> MR + MaybeSend + 'static,
713        A: FromLuaMulti + TypedMultiValue,
714        MR: std::future::Future<Output = mlua::Result<R>> + MaybeSend + 'static,
715        R: IntoLuaMulti + TypedMultiValue,
716    {
717        let name: Cow<'static, str> = name.into().into();
718        self.typed_class.methods.insert(
719            name.into(),
720            Func::new::<A, R>(
721                self.queued_doc.take(),
722                self.queued_params.drain(..).collect(),
723                self.queued_returns.drain(..).collect(),
724            ),
725        );
726    }
727
728    fn add_function_mut<S, A, R, F>(&mut self, name: S, _: F)
729    where
730        S: Into<String>,
731        A: FromLuaMulti + TypedMultiValue,
732        R: IntoLuaMulti + TypedMultiValue,
733        F: 'static + MaybeSend + FnMut(&Lua, A) -> mlua::Result<R>,
734    {
735        let name: Cow<'static, str> = name.into().into();
736        self.typed_class.functions.insert(
737            name.into(),
738            Func::new::<A, R>(
739                self.queued_doc.take(),
740                self.queued_params.drain(..).collect(),
741                self.queued_returns.drain(..).collect(),
742            ),
743        );
744    }
745
746    fn add_meta_function<A, R, F>(&mut self, meta: impl Into<String>, _: F)
747    where
748        A: FromLuaMulti + TypedMultiValue,
749        R: IntoLuaMulti + TypedMultiValue,
750        F: 'static + MaybeSend + Fn(&Lua, A) -> mlua::Result<R>,
751    {
752        let name: Cow<'static, str> = meta.into().into();
753        self.typed_class.meta_functions.insert(
754            name.into(),
755            Func::new::<A, R>(
756                self.queued_doc.take(),
757                self.queued_params.drain(..).collect(),
758                self.queued_returns.drain(..).collect(),
759            ),
760        );
761    }
762
763    #[cfg(feature = "async")]
764    fn add_async_function<S, A, R, F, FR>(&mut self, name: S, _: F)
765    where
766        S: Into<String>,
767        A: FromLuaMulti + TypedMultiValue,
768        R: IntoLuaMulti + TypedMultiValue,
769        F: 'static + MaybeSend + Fn(Lua, A) -> FR,
770        FR: 'static + MaybeSend + std::future::Future<Output = mlua::Result<R>>,
771    {
772        let name: Cow<'static, str> = name.into().into();
773        self.typed_class.functions.insert(
774            name.into(),
775            Func::new::<A, R>(
776                self.queued_doc.take(),
777                self.queued_params.drain(..).collect(),
778                self.queued_returns.drain(..).collect(),
779            ),
780        );
781    }
782
783    fn add_meta_method_mut<A, R, M>(&mut self, meta: impl Into<String>, _: M)
784    where
785        A: FromLuaMulti + TypedMultiValue,
786        R: IntoLuaMulti + TypedMultiValue,
787        M: 'static + MaybeSend + FnMut(&Lua, &mut T, A) -> mlua::Result<R>,
788    {
789        let name: Cow<'static, str> = meta.into().into();
790        self.typed_class.meta_methods.insert(
791            name.into(),
792            Func::new::<A, R>(
793                self.queued_doc.take(),
794                self.queued_params.drain(..).collect(),
795                self.queued_returns.drain(..).collect(),
796            ),
797        );
798    }
799
800    fn add_meta_function_mut<A, R, F>(&mut self, meta: impl Into<String>, _: F)
801    where
802        A: FromLuaMulti + TypedMultiValue,
803        R: IntoLuaMulti + TypedMultiValue,
804        F: 'static + MaybeSend + FnMut(&Lua, A) -> mlua::Result<R>,
805    {
806        let name: Cow<'static, str> = meta.into().into();
807        self.typed_class.meta_functions.insert(
808            name.into(),
809            Func::new::<A, R>(
810                self.queued_doc.take(),
811                self.queued_params.drain(..).collect(),
812                self.queued_returns.drain(..).collect(),
813            ),
814        );
815    }
816}