use std::{any::Any, borrow::Cow, collections::BTreeMap};
use mlua::{AnyUserData, FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, Lua, MetaMethod};
use crate::{typed::{function::Return, generator::FunctionBuilder, Field, Func, Index, IntoDocComment, Type}, MaybeSend};
use super::{Typed, TypedDataDocumentation, TypedDataFields, TypedDataMethods, TypedMultiValue, TypedUserData};
#[derive(Default, Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct TypedClassBuilder {
pub type_doc: Option<Cow<'static, str>>,
queued_doc: Option<String>,
pub fields: BTreeMap<Index, Field>,
pub static_fields: BTreeMap<Index, Field>,
pub meta_fields: BTreeMap<Index, Field>,
pub methods: BTreeMap<Index, Func>,
pub meta_methods: BTreeMap<Index, Func>,
pub functions: BTreeMap<Index, Func>,
pub meta_functions: BTreeMap<Index, Func>,
}
impl From<TypedClassBuilder> for Type {
fn from(value: TypedClassBuilder) -> Self {
Type::Class(Box::new(value))
}
}
impl TypedClassBuilder {
pub fn new<T: TypedUserData>() -> Self {
let mut gen = Self::default();
T::add_documentation(&mut gen);
T::add_fields(&mut gen);
T::add_methods(&mut gen);
gen
}
pub fn is_meta_empty(&self) -> bool {
self.meta_fields.is_empty()
&& self.meta_functions.is_empty()
&& self.meta_methods.is_empty()
}
pub fn field(mut self, key: impl Into<Index>, ty: Type, doc: impl IntoDocComment) -> Self {
self.fields.insert(key.into(), Field::new(ty, doc));
self
}
pub fn function<Params, Returns>(mut self, key: impl Into<Index>, doc: impl IntoDocComment) -> Self
where
Params: TypedMultiValue,
Returns: TypedMultiValue,
{
self.functions.insert(key.into(), Func::new::<Params, Returns>(doc));
self
}
pub fn function_with<Params, Returns, F, R>(mut self, key: impl Into<Index>, doc: impl IntoDocComment, generator: F) -> Self
where
Params: TypedMultiValue,
Returns: TypedMultiValue,
F: Fn(&mut FunctionBuilder<Params, Returns>) -> R,
R: Any,
{
let mut builder = FunctionBuilder::default();
generator(&mut builder);
self.functions.insert(key.into(), Func {
params: builder.params,
returns: builder.returns,
doc: doc.into_doc_comment()
});
self
}
pub fn method<Params, Returns>(mut self, key: impl Into<Index>, doc: impl IntoDocComment) -> Self
where
Params: TypedMultiValue,
Returns: TypedMultiValue,
{
self.methods.insert(key.into(), Func::new::<Params, Returns>(doc));
self
}
pub fn method_with<Params, Returns, F, R>(mut self, key: impl Into<Index>, doc: impl IntoDocComment, generator: F) -> Self
where
Params: TypedMultiValue,
Returns: TypedMultiValue,
F: Fn(&mut FunctionBuilder<Params, Returns>) -> R,
R: Any,
{
let mut builder = FunctionBuilder::default();
generator(&mut builder);
self.methods.insert(key.into(), Func {
params: builder.params,
returns: builder.returns,
doc: doc.into_doc_comment()
});
self
}
pub fn meta_field(mut self, key: impl Into<Index>, ty: Type, doc: impl IntoDocComment) -> Self {
self.meta_fields.insert(key.into(), Field::new(ty, doc));
self
}
pub fn meta_function<Params, Returns>(mut self, key: impl Into<Index>, doc: impl IntoDocComment) -> Self
where
Params: TypedMultiValue,
Returns: TypedMultiValue,
{
self.meta_functions.insert(key.into(), Func::new::<Params, Returns>(doc));
self
}
pub fn meta_function_with<Params, Returns, F, R>(mut self, key: impl Into<Index>, doc: impl IntoDocComment, generator: F) -> Self
where
F: Fn(&mut FunctionBuilder<Params, Returns>) -> R,
R: Any,
Params: TypedMultiValue,
Returns: TypedMultiValue,
{
let mut builder = FunctionBuilder::default();
generator(&mut builder);
self.meta_functions.insert(key.into(), Func {
params: builder.params,
returns: builder.returns,
doc: doc.into_doc_comment()
});
self
}
pub fn meta_method<Params, Returns>(mut self, key: impl Into<Index>, doc: impl IntoDocComment) -> Self
where
Params: TypedMultiValue,
Returns: TypedMultiValue,
{
self.meta_methods.insert(key.into(), Func::new::<Params, Returns>(doc));
self
}
pub fn meta_method_with<Params, Returns, F, R>(mut self, key: impl Into<Index>, doc: impl IntoDocComment, generator: F) -> Self
where
F: Fn(&mut FunctionBuilder<Params, Returns>) -> R,
R: Any,
Params: TypedMultiValue,
Returns: TypedMultiValue,
{
let mut builder = FunctionBuilder::default();
generator(&mut builder);
self.meta_methods.insert(key.into(), Func {
params: builder.params,
returns: builder.returns,
doc: doc.into_doc_comment()
});
self
}
}
impl<T: TypedUserData> TypedDataDocumentation<T> for TypedClassBuilder {
fn add(&mut self, doc: &str) -> &mut Self {
if let Some(type_doc) = self.type_doc.as_mut() {
*type_doc = format!("{type_doc}\n{doc}").into()
} else {
self.type_doc = Some(doc.to_string().into())
}
self
}
}
impl<T: TypedUserData> TypedDataFields<T> for TypedClassBuilder {
fn document(&mut self, doc: &str) -> &mut Self {
self.queued_doc = Some(doc.to_string());
self
}
fn add_field<V>(&mut self, name: impl Into<String>, _: V)
where
V: IntoLua + Clone + 'static + Typed,
{
let name: Cow<'static, str> = name.into().into();
self.static_fields
.entry(name.into())
.and_modify(|v| {
v.doc = self.queued_doc.take().map(|v| v.into());
v.ty = v.ty.clone() | V::ty();
})
.or_insert(Field {
ty: V::ty(),
doc: self.queued_doc.take().map(|v| v.into()),
});
}
fn add_field_function_set<S, A, F>(&mut self, name: S, _: F)
where
S: Into<String>,
A: FromLua + Typed,
F: 'static + MaybeSend + FnMut(&Lua, AnyUserData, A) -> mlua::Result<()>,
{
let name: Cow<'static, str> = name.into().into();
self.static_fields
.entry(name.into())
.and_modify(|v| {
v.doc = self.queued_doc.take().map(|v| v.into());
v.ty = v.ty.clone() | A::ty();
})
.or_insert(Field {
ty: A::ty(),
doc: self.queued_doc.take().map(|v| v.into()),
});
}
fn add_field_function_get<S, R, F>(&mut self, name: S, _: F)
where
S: Into<String>,
R: IntoLua + Typed,
F: 'static + MaybeSend + Fn(&Lua, AnyUserData) -> mlua::Result<R>,
{
let name: Cow<'static, str> = name.into().into();
self.static_fields
.entry(name.into())
.and_modify(|v| {
v.doc = self.queued_doc.take().map(|v| v.into());
v.ty = v.ty.clone() | R::ty();
})
.or_insert(Field {
ty: R::ty(),
doc: self.queued_doc.take().map(|v| v.into()),
});
}
fn add_field_function_get_set<S, R, A, GET, SET>(&mut self, name: S, _: GET, _: SET)
where
S: Into<String>,
R: IntoLua + Typed,
A: FromLua + Typed,
GET: 'static + MaybeSend + Fn(&Lua, AnyUserData) -> mlua::Result<R>,
SET: 'static + MaybeSend + Fn(&Lua, AnyUserData, A) -> mlua::Result<()>,
{
let name: Cow<'static, str> = name.into().into();
self.static_fields
.entry(name.into())
.and_modify(|v| {
v.doc = self.queued_doc.take().map(|v| v.into());
v.ty = v.ty.clone() | A::ty() | R::ty();
})
.or_insert(Field {
ty: A::ty() | R::ty(),
doc: self.queued_doc.take().map(|v| v.into()),
});
}
fn add_field_method_set<S, A, M>(&mut self, name: S, _: M)
where
S: Into<String>,
A: FromLua + Typed,
M: 'static + MaybeSend + FnMut(&Lua, &mut T, A) -> mlua::Result<()>,
{
let name: Cow<'static, str> = name.into().into();
self.fields
.entry(name.into())
.and_modify(|v| {
v.doc = self.queued_doc.take().map(|v| v.into());
v.ty = v.ty.clone() | A::ty();
})
.or_insert(Field {
ty: A::ty(),
doc: self.queued_doc.take().map(|v| v.into()),
});
}
fn add_field_method_get<S, R, M>(&mut self, name: S, _: M)
where
S: Into<String>,
R: IntoLua + Typed,
M: 'static + MaybeSend + Fn(&Lua, &T) -> mlua::Result<R>,
{
let name: Cow<'static, str> = name.into().into();
self.fields
.entry(name.into())
.and_modify(|v| {
v.doc = self.queued_doc.take().map(|v| v.into());
v.ty = v.ty.clone() | R::ty();
})
.or_insert(Field {
ty: R::ty(),
doc: self.queued_doc.take().map(|v| v.into()),
});
}
fn add_field_method_get_set<S, R, A, GET, SET>(&mut self, name: S, _: GET, _: SET)
where
S: Into<String>,
R: IntoLua + Typed,
A: FromLua + Typed,
GET: 'static + MaybeSend + Fn(&Lua, &T) -> mlua::Result<R>,
SET: 'static + MaybeSend + Fn(&Lua, &mut T, A) -> mlua::Result<()>,
{
let name: Cow<'static, str> = name.into().into();
self.fields
.entry(name.into())
.and_modify(|v| {
v.doc = self.queued_doc.take().map(|v| v.into());
v.ty = v.ty.clone() | A::ty() | R::ty();
})
.or_insert(Field {
ty: A::ty() | R::ty(),
doc: self.queued_doc.take().map(|v| v.into()),
});
}
fn add_meta_field<R, F>(&mut self, meta: MetaMethod, _: F)
where
F: 'static + MaybeSend + Fn(&Lua) -> mlua::Result<R>,
R: IntoLua + Typed,
{
let name: Cow<'static, str> = meta.as_ref().to_string().into();
self.meta_fields
.entry(name.into())
.and_modify(|v| {
v.doc = self.queued_doc.take().map(|v| v.into());
v.ty = v.ty.clone() | R::ty();
})
.or_insert(Field {
ty: R::ty(),
doc: self.queued_doc.take().map(|v| v.into()),
});
}
}
impl<T: TypedUserData> TypedDataMethods<T> for TypedClassBuilder {
fn document(&mut self, documentation: &str) -> &mut Self {
self.queued_doc = Some(documentation.to_string());
self
}
fn add_method<S, A, R, M>(&mut self, name: S, _: M)
where
S: Into<String>,
A: FromLuaMulti + TypedMultiValue,
R: IntoLuaMulti + TypedMultiValue,
M: 'static + MaybeSend + Fn(&Lua, &T, A) -> mlua::Result<R>,
{
let name: Cow<'static, str> = name.into().into();
self.methods.insert(
name.into(),
Func {
params: A::get_types_as_params(),
returns: R::get_types_as_returns(),
doc: self.queued_doc.take().map(|v| v.into()),
},
);
}
fn add_method_with<S, A, R, M, G>(&mut self, name: S, _method: M, generator: G)
where
S: Into<String>,
A: FromLuaMulti + TypedMultiValue,
R: IntoLuaMulti + TypedMultiValue,
M: 'static + MaybeSend + Fn(&Lua, &T, A) -> mlua::Result<R>,
G: Fn(&mut FunctionBuilder<A, R>) {
let mut builder = FunctionBuilder::<A, R>::default();
generator(&mut builder);
let name: Cow<'static, str> = name.into().into();
self.methods.insert(
name.into(),
Func {
params: builder.params,
returns: builder.returns,
doc: self.queued_doc.take().map(|v| v.into()),
},
);
}
fn add_function<S, A, R, F>(&mut self, name: S, _: F)
where
S: Into<String>,
A: FromLuaMulti + TypedMultiValue,
R: IntoLuaMulti + TypedMultiValue,
F: 'static + MaybeSend + Fn(&Lua, A) -> mlua::Result<R>,
{
let name: Cow<'static, str> = name.into().into();
self.functions.insert(
name.into(),
Func {
params: A::get_types_as_params(),
returns: R::get_types_as_returns(),
doc: self.queued_doc.take().map(|v| v.into()),
},
);
}
fn add_function_with<S, A, R, F, G>(&mut self, name: S, _function: F, generator: G)
where
S: Into<String>,
A: FromLuaMulti + TypedMultiValue,
R: IntoLuaMulti + TypedMultiValue,
F: 'static + MaybeSend + Fn(&Lua, A) -> mlua::Result<R>,
G: Fn(&mut FunctionBuilder<A, R>) {
let mut builder = FunctionBuilder::<A, R>::default();
generator(&mut builder);
let name: Cow<'static, str> = name.into().into();
self.functions.insert(
name.into(),
Func {
params: builder.params,
returns: builder.returns,
doc: self.queued_doc.take().map(|v| v.into()),
},
);
}
fn add_method_mut<S, A, R, M>(&mut self, name: S, _: M)
where
S: Into<String>,
A: FromLuaMulti + TypedMultiValue,
R: IntoLuaMulti + TypedMultiValue,
M: 'static + MaybeSend + FnMut(&Lua, &mut T, A) -> mlua::Result<R>,
{
let name: Cow<'static, str> = name.into().into();
self.methods.insert(
name.into(),
Func {
params: A::get_types_as_params(),
returns: R::get_types_as_returns(),
doc: self.queued_doc.take().map(|v| v.into()),
},
);
}
fn add_method_mut_with<S, A, R, M, G>(&mut self, name: S, _method: M, generator: G)
where
S: Into<String>,
A: FromLuaMulti + TypedMultiValue,
R: IntoLuaMulti + TypedMultiValue,
M: 'static + MaybeSend + FnMut(&Lua, &mut T, A) -> mlua::Result<R>,
G: Fn(&mut FunctionBuilder<A, R>) {
let mut builder = FunctionBuilder::<A, R>::default();
generator(&mut builder);
let name: Cow<'static, str> = name.into().into();
self.methods.insert(
name.into(),
Func {
params: builder.params,
returns: builder.returns,
doc: self.queued_doc.take().map(|v| v.into()),
},
);
}
fn add_meta_method<A, R, M>(&mut self, meta: MetaMethod, _: M)
where
A: FromLuaMulti + TypedMultiValue,
R: IntoLuaMulti + TypedMultiValue,
M: 'static + MaybeSend + Fn(&Lua, &T, A) -> mlua::Result<R>,
{
let name: Cow<'static, str> = meta.as_ref().to_string().into();
self.meta_methods.insert(
name.into(),
Func {
params: A::get_types_as_params(),
returns: R::get_types_as_returns(),
doc: self.queued_doc.take().map(|v| v.into()),
},
);
}
fn add_meta_method_with<A, R, M, G>(&mut self, meta: MetaMethod, _method: M, generator: G)
where
A: FromLuaMulti + TypedMultiValue,
R: IntoLuaMulti + TypedMultiValue,
M: 'static + MaybeSend + Fn(&Lua, &T, A) -> mlua::Result<R>,
G: Fn(&mut FunctionBuilder<A, R>) {
let mut builder = FunctionBuilder::<A, R>::default();
generator(&mut builder);
let name: Cow<'static, str> = meta.as_ref().to_string().into();
self.meta_methods.insert(
name.into(),
Func {
params: builder.params,
returns: builder.returns,
doc: self.queued_doc.take().map(|v| v.into()),
},
);
}
#[cfg(feature = "async")]
fn add_async_method<'s, S: ?Sized + AsRef<str>, A, R, M, MR>(&mut self, name: S, _: M)
where
T: 'static,
M: Fn(&Lua, &'s T, A) -> MR + MaybeSend + 'static,
A: FromLuaMulti + TypedMultiValue,
MR: std::future::Future<Output = mlua::Result<R>> + 's,
R: IntoLuaMulti + TypedMultiValue,
{
let name: Cow<'static, str> = name.as_ref().to_string().into();
self.methods.insert(
name.into(),
Func {
params: A::get_types_as_params(),
returns: R::get_types_as_returns(),
doc: self.queued_doc.take().map(|v| v.into()),
},
);
}
#[cfg(feature = "async")]
fn add_async_method_with<'s, S: ?Sized + AsRef<str>, A, R, M, MR, G>(&mut self, name: S, _method: M, generator: G)
where
T: 'static,
M: Fn(&Lua, &'s T, A) -> MR + MaybeSend + 'static,
A: FromLuaMulti + TypedMultiValue,
MR: std::future::Future<Output = mlua::Result<R>> + 's,
R: IntoLuaMulti + TypedMultiValue,
G: Fn(&mut FunctionBuilder<A, R>) {
let mut builder = FunctionBuilder::<A, R>::default();
generator(&mut builder);
let name: Cow<'static, str> = name.as_ref().to_string().into();
self.methods.insert(
name.into(),
Func {
params: builder.params,
returns: builder.returns,
doc: self.queued_doc.take().map(|v| v.into()),
},
);
}
#[cfg(feature = "async")]
fn add_async_method_mut<'s, S: ?Sized + AsRef<str>, A, R, M, MR>(&mut self, name: S, method: M)
where
T: 'static,
M: Fn(&Lua, &'s mut T, A) -> MR + MaybeSend + 'static,
A: FromLuaMulti + TypedMultiValue,
MR: std::future::Future<Output = mlua::Result<R>> + 's,
R: IntoLuaMulti + TypedMultiValue {
let name: Cow<'static, str> = name.as_ref().to_string().into();
self.methods.insert(
name.into(),
Func {
params: A::get_types_as_params(),
returns: R::get_types_as_returns(),
doc: self.queued_doc.take().map(|v| v.into()),
},
);
}
#[cfg(feature = "async")]
fn add_async_method_mut_with<'s, S: ?Sized + AsRef<str>, A, R, M, MR, G>(&mut self, name: S, _method: M, generator: G)
where
T: 'static,
M: Fn(&Lua, &'s mut T, A) -> MR + MaybeSend + 'static,
A: FromLuaMulti + TypedMultiValue,
MR: std::future::Future<Output = mlua::Result<R>> + 's,
R: IntoLuaMulti + TypedMultiValue,
G: Fn(&mut FunctionBuilder<A, R>) {
let mut builder = FunctionBuilder::<A, R>::default();
generator(&mut builder);
let name: Cow<'static, str> = name.as_ref().to_string().into();
self.methods.insert(
name.into(),
Func {
params: builder.params,
returns: builder.returns,
doc: self.queued_doc.take().map(|v| v.into()),
},
);
}
fn add_function_mut<S, A, R, F>(&mut self, name: S, _: F)
where
S: Into<String>,
A: FromLuaMulti + TypedMultiValue,
R: IntoLuaMulti + TypedMultiValue,
F: 'static + MaybeSend + FnMut(&Lua, A) -> mlua::Result<R>,
{
let name: Cow<'static, str> = name.into().into();
self.functions.insert(
name.into(),
Func {
params: A::get_types_as_params(),
returns: R::get_types_as_returns(),
doc: self.queued_doc.take().map(|v| v.into()),
},
);
}
fn add_function_mut_with<S, A, R, F, G>(&mut self, name: S, _function: F, generator: G)
where
S: Into<String>,
A: FromLuaMulti + TypedMultiValue,
R: IntoLuaMulti + TypedMultiValue,
F: 'static + MaybeSend + FnMut(&Lua, A) -> mlua::Result<R>,
G: Fn(&mut FunctionBuilder<A, R>) {
let mut builder = FunctionBuilder::<A, R>::default();
generator(&mut builder);
let name: Cow<'static, str> = name.into().into();
self.functions.insert(
name.into(),
Func {
params: builder.params,
returns: builder.returns,
doc: self.queued_doc.take().map(|v| v.into()),
},
);
}
fn add_meta_function<A, R, F>(&mut self, meta: MetaMethod, _: F)
where
A: FromLuaMulti + TypedMultiValue,
R: IntoLuaMulti + TypedMultiValue,
F: 'static + MaybeSend + Fn(&Lua, A) -> mlua::Result<R>,
{
let name: Cow<'static, str> = meta.as_ref().to_string().into();
self.meta_functions.insert(
name.into(),
Func {
params: A::get_types_as_params(),
returns: R::get_types_as_returns(),
doc: self.queued_doc.take().map(|v| v.into()),
},
);
}
fn add_meta_function_with<A, R, F, G>(&mut self, meta: MetaMethod, _function: F, generator: G)
where
A: FromLuaMulti + TypedMultiValue,
R: IntoLuaMulti + TypedMultiValue,
F: 'static + MaybeSend + Fn(&Lua, A) -> mlua::Result<R>,
G: Fn(&mut FunctionBuilder<A, R>) {
let mut builder = FunctionBuilder::<A, R>::default();
generator(&mut builder);
let name: Cow<'static, str> = meta.as_ref().to_string().into();
self.functions.insert(
name.into(),
Func {
params: builder.params,
returns: builder.returns,
doc: self.queued_doc.take().map(|v| v.into()),
},
);
}
#[cfg(feature = "async")]
fn add_async_function<S: ?Sized, A, R, F, FR>(&mut self, name: S, _: F)
where
S: AsRef<str>,
A: FromLuaMulti + TypedMultiValue,
R: IntoLuaMulti + TypedMultiValue,
F: 'static + MaybeSend + Fn(&Lua, A) -> FR,
FR: std::future::Future<Output = mlua::Result<R>>,
{
let name: Cow<'static, str> = name.as_ref().to_string().into();
self.functions.insert(
name.into(),
Func {
params: A::get_types_as_params(),
returns: R::get_types_as_returns(),
doc: self.queued_doc.take().map(|v| v.into()),
},
);
}
#[cfg(feature = "async")]
fn add_async_function_with<S: ?Sized, A, R, F, FR, G>(&mut self, name: S, _function: F, generator: G)
where
S: AsRef<str>,
A: FromLuaMulti + TypedMultiValue,
R: IntoLuaMulti + TypedMultiValue,
F: 'static + MaybeSend + Fn(&Lua, A) -> FR,
FR: std::future::Future<Output = mlua::Result<R>>,
G: Fn(&mut FunctionBuilder<A, R>) {
let mut builder = FunctionBuilder::<A, R>::default();
generator(&mut builder);
let name: Cow<'static, str> = name.as_ref().to_string().into();
self.functions.insert(
name.into(),
Func {
params: builder.params,
returns: builder.returns,
doc: self.queued_doc.take().map(|v| v.into()),
},
);
}
fn add_meta_method_mut<A, R, M>(&mut self, meta: MetaMethod, _: M)
where
A: FromLuaMulti + TypedMultiValue,
R: IntoLuaMulti + TypedMultiValue,
M: 'static + MaybeSend + FnMut(&Lua, &mut T, A) -> mlua::Result<R>,
{
let name: Cow<'static, str> = meta.as_ref().to_string().into();
self.meta_methods.insert(
name.into(),
Func {
params: A::get_types_as_params(),
returns: R::get_types_as_returns(),
doc: self.queued_doc.take().map(|v| v.into()),
},
);
}
fn add_meta_method_mut_with<A, R, M, G>(&mut self, meta: MetaMethod, _method: M, generator: G)
where
A: FromLuaMulti + TypedMultiValue,
R: IntoLuaMulti + TypedMultiValue,
M: 'static + MaybeSend + FnMut(&Lua, &mut T, A) -> mlua::Result<R>,
G: Fn(&mut FunctionBuilder<A, R>) {
let mut builder = FunctionBuilder::<A, R>::default();
generator(&mut builder);
let name: Cow<'static, str> = meta.as_ref().to_string().into();
self.meta_methods.insert(
name.into(),
Func {
params: builder.params,
returns: builder.returns,
doc: self.queued_doc.take().map(|v| v.into()),
},
);
}
fn add_meta_function_mut<A, R, F>(&mut self, meta: MetaMethod, _: F)
where
A: FromLuaMulti + TypedMultiValue,
R: IntoLuaMulti + TypedMultiValue,
F: 'static + MaybeSend + FnMut(&Lua, A) -> mlua::Result<R>,
{
let name: Cow<'static, str> = meta.as_ref().to_string().into();
self.meta_functions.insert(
name.into(),
Func {
params: A::get_types_as_params(),
returns: R::get_types().into_iter().map(|ty| Return { doc: None, ty }).collect(),
doc: self.queued_doc.take().map(|v| v.into()),
},
);
}
fn add_meta_function_mut_with<A, R, F, G>(&mut self, meta: MetaMethod, _function: F, generator: G)
where
A: FromLuaMulti + TypedMultiValue,
R: IntoLuaMulti + TypedMultiValue,
F: 'static + MaybeSend + FnMut(&Lua, A) -> mlua::Result<R>,
G: Fn(&mut FunctionBuilder<A, R>) {
let mut builder = FunctionBuilder::<A, R>::default();
generator(&mut builder);
let name: Cow<'static, str> = meta.as_ref().to_string().into();
self.meta_functions.insert(
name.into(),
Func {
params: builder.params,
returns: builder.returns,
doc: self.queued_doc.take().map(|v| v.into()),
},
);
}
}