Refactor `userdata::MetaMethod`.

Take `impl AsRef<str>` as name of metamethod (instead of `Into<MetaMethod>`) in UserDataMethods/UserDataFields.
Change position of generic args in userdata.
This commit is contained in:
Alex Orlenko 2022-12-24 19:16:58 +00:00
parent 22c6e9a7e7
commit d67332a3ac
No known key found for this signature in database
GPG Key ID: 4C150C250863B96D
5 changed files with 311 additions and 414 deletions

View File

@ -29,7 +29,7 @@ use crate::types::{
Callback, CallbackUpvalue, DestructedUserdata, Integer, LightUserData, LuaRef, MaybeSend,
Number, RegistryKey,
};
use crate::userdata::{AnyUserData, UserData, UserDataCell};
use crate::userdata::{AnyUserData, MetaMethod, UserData, UserDataCell};
use crate::userdata_impl::{StaticUserDataFields, StaticUserDataMethods, UserDataProxy};
use crate::util::{
self, assert_stack, callback_error, check_stack, get_destructed_userdata_metatable,
@ -2515,16 +2515,16 @@ impl Lua {
push_table(state, 0, metatable_nrec as c_int, true)?;
for (k, m) in methods.meta_methods {
self.push_value(Value::Function(self.create_callback(m)?))?;
rawset_field(state, -2, k.validate()?.name())?;
rawset_field(state, -2, MetaMethod::validate(&k)?)?;
}
#[cfg(feature = "async")]
for (k, m) in methods.async_meta_methods {
self.push_value(Value::Function(self.create_async_callback(m)?))?;
rawset_field(state, -2, k.validate()?.name())?;
rawset_field(state, -2, MetaMethod::validate(&k)?)?;
}
for (k, f) in fields.meta_fields {
self.push_value(f(self)?)?;
rawset_field(state, -2, k.validate()?.name())?;
rawset_field(state, -2, MetaMethod::validate(&k)?)?;
}
let metatable_index = ffi::lua_absindex(state, -1);

View File

@ -371,11 +371,11 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
for (k, m) in ud_methods.meta_methods {
let data = data.clone();
lua.push_value(Value::Function(wrap_method(self, data, ud_ptr, m)?))?;
rawset_field(state, -2, k.validate()?.name())?;
rawset_field(state, -2, MetaMethod::validate(&k)?)?;
}
for (k, f) in ud_fields.meta_fields {
lua.push_value(f(mem::transmute(lua))?)?;
rawset_field(state, -2, k.validate()?.name())?;
rawset_field(state, -2, MetaMethod::validate(&k)?)?;
}
let metatable_index = ffi::lua_absindex(state, -1);
@ -611,7 +611,7 @@ enum NonStaticMethod<'lua, T> {
struct NonStaticUserDataMethods<'lua, T: UserData> {
methods: Vec<(String, NonStaticMethod<'lua, T>)>,
meta_methods: Vec<(MetaMethod, NonStaticMethod<'lua, T>)>,
meta_methods: Vec<(String, NonStaticMethod<'lua, T>)>,
}
impl<'lua, T: UserData> Default for NonStaticUserDataMethods<'lua, T> {
@ -624,170 +624,154 @@ impl<'lua, T: UserData> Default for NonStaticUserDataMethods<'lua, T> {
}
impl<'lua, T: UserData> UserDataMethods<'lua, T> for NonStaticUserDataMethods<'lua, T> {
fn add_method<A, R, M>(&mut self, name: &str, method: M)
fn add_method<M, A, R>(&mut self, name: impl AsRef<str>, method: M)
where
M: Fn(&'lua Lua, &T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
M: 'static + MaybeSend + Fn(&'lua Lua, &T, A) -> Result<R>,
{
self.methods.push((
name.into(),
NonStaticMethod::Method(Box::new(move |lua, ud, args| {
method(lua, ud, A::from_lua_multi(args, lua)?)?.into_lua_multi(lua)
})),
));
let method = NonStaticMethod::Method(Box::new(move |lua, ud, args| {
method(lua, ud, A::from_lua_multi(args, lua)?)?.into_lua_multi(lua)
}));
self.methods.push((name.as_ref().into(), method));
}
fn add_method_mut<A, R, M>(&mut self, name: &str, mut method: M)
fn add_method_mut<M, A, R>(&mut self, name: impl AsRef<str>, mut method: M)
where
M: FnMut(&'lua Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<R>,
{
self.methods.push((
name.into(),
NonStaticMethod::MethodMut(Box::new(move |lua, ud, args| {
method(lua, ud, A::from_lua_multi(args, lua)?)?.into_lua_multi(lua)
})),
));
let method = NonStaticMethod::MethodMut(Box::new(move |lua, ud, args| {
method(lua, ud, A::from_lua_multi(args, lua)?)?.into_lua_multi(lua)
}));
self.methods.push((name.as_ref().into(), method));
}
#[cfg(feature = "async")]
fn add_async_method<A, R, M, MR>(&mut self, _name: &str, _method: M)
fn add_async_method<M, A, MR, R>(&mut self, _name: impl AsRef<str>, _method: M)
where
T: Clone,
M: Fn(&'lua Lua, T, A) -> MR + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
MR: Future<Output = Result<R>> + 'lua,
R: IntoLuaMulti<'lua>,
M: 'static + MaybeSend + Fn(&'lua Lua, T, A) -> MR,
MR: 'lua + Future<Output = Result<R>>,
{
// The panic should never happen as async non-static code wouldn't compile
// Non-static lifetime must be bounded to 'lua lifetime
mlua_panic!("asynchronous methods are not supported for non-static userdata")
panic!("asynchronous methods are not supported for non-static userdata")
}
fn add_function<A, R, F>(&mut self, name: &str, function: F)
fn add_function<F, A, R>(&mut self, name: impl AsRef<str>, function: F)
where
F: Fn(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> Result<R>,
{
self.methods.push((
name.into(),
NonStaticMethod::Function(Box::new(move |lua, args| {
function(lua, A::from_lua_multi(args, lua)?)?.into_lua_multi(lua)
})),
));
let func = NonStaticMethod::Function(Box::new(move |lua, args| {
function(lua, A::from_lua_multi(args, lua)?)?.into_lua_multi(lua)
}));
self.methods.push((name.as_ref().into(), func));
}
fn add_function_mut<A, R, F>(&mut self, name: &str, mut function: F)
fn add_function_mut<F, A, R>(&mut self, name: impl AsRef<str>, mut function: F)
where
F: FnMut(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
F: 'static + MaybeSend + FnMut(&'lua Lua, A) -> Result<R>,
{
self.methods.push((
name.into(),
NonStaticMethod::FunctionMut(Box::new(move |lua, args| {
function(lua, A::from_lua_multi(args, lua)?)?.into_lua_multi(lua)
})),
));
let func = NonStaticMethod::FunctionMut(Box::new(move |lua, args| {
function(lua, A::from_lua_multi(args, lua)?)?.into_lua_multi(lua)
}));
self.methods.push((name.as_ref().into(), func));
}
#[cfg(feature = "async")]
fn add_async_function<A, R, F, FR>(&mut self, _name: &str, _function: F)
fn add_async_function<F, A, FR, R>(&mut self, _name: impl AsRef<str>, _function: F)
where
F: Fn(&'lua Lua, A) -> FR + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
FR: Future<Output = Result<R>> + 'lua,
R: IntoLuaMulti<'lua>,
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> FR,
FR: 'lua + Future<Output = Result<R>>,
{
// The panic should never happen as async non-static code wouldn't compile
// Non-static lifetime must be bounded to 'lua lifetime
mlua_panic!("asynchronous functions are not supported for non-static userdata")
panic!("asynchronous functions are not supported for non-static userdata")
}
fn add_meta_method<A, R, M>(&mut self, meta: impl Into<MetaMethod>, method: M)
fn add_meta_method<M, A, R>(&mut self, name: impl AsRef<str>, method: M)
where
M: Fn(&'lua Lua, &T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
M: 'static + MaybeSend + Fn(&'lua Lua, &T, A) -> Result<R>,
{
self.meta_methods.push((
meta.into(),
NonStaticMethod::Method(Box::new(move |lua, ud, args| {
method(lua, ud, A::from_lua_multi(args, lua)?)?.into_lua_multi(lua)
})),
));
let method = NonStaticMethod::Method(Box::new(move |lua, ud, args| {
method(lua, ud, A::from_lua_multi(args, lua)?)?.into_lua_multi(lua)
}));
self.meta_methods.push((name.as_ref().into(), method));
}
fn add_meta_method_mut<A, R, M>(&mut self, meta: impl Into<MetaMethod>, mut method: M)
fn add_meta_method_mut<M, A, R>(&mut self, name: impl AsRef<str>, mut method: M)
where
M: FnMut(&'lua Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<R>,
{
self.meta_methods.push((
meta.into(),
NonStaticMethod::MethodMut(Box::new(move |lua, ud, args| {
method(lua, ud, A::from_lua_multi(args, lua)?)?.into_lua_multi(lua)
})),
));
let method = NonStaticMethod::MethodMut(Box::new(move |lua, ud, args| {
method(lua, ud, A::from_lua_multi(args, lua)?)?.into_lua_multi(lua)
}));
self.meta_methods.push((name.as_ref().into(), method));
}
#[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
fn add_async_meta_method<A, R, M, MR>(&mut self, _meta: impl Into<MetaMethod>, _method: M)
fn add_async_meta_method<M, A, MR, R>(&mut self, _name: impl AsRef<str>, _method: M)
where
T: Clone,
M: Fn(&'lua Lua, T, A) -> MR + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
MR: Future<Output = Result<R>> + 'lua,
R: IntoLuaMulti<'lua>,
M: 'static + MaybeSend + Fn(&'lua Lua, T, A) -> MR,
MR: 'lua + Future<Output = Result<R>>,
{
// The panic should never happen as async non-static code wouldn't compile
// Non-static lifetime must be bounded to 'lua lifetime
mlua_panic!("asynchronous meta methods are not supported for non-static userdata")
panic!("asynchronous meta methods are not supported for non-static userdata")
}
fn add_meta_function<A, R, F>(&mut self, meta: impl Into<MetaMethod>, function: F)
fn add_meta_function<F, A, R>(&mut self, name: impl AsRef<str>, function: F)
where
F: Fn(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> Result<R>,
{
self.meta_methods.push((
meta.into(),
NonStaticMethod::Function(Box::new(move |lua, args| {
function(lua, A::from_lua_multi(args, lua)?)?.into_lua_multi(lua)
})),
));
let func = NonStaticMethod::Function(Box::new(move |lua, args| {
function(lua, A::from_lua_multi(args, lua)?)?.into_lua_multi(lua)
}));
self.meta_methods.push((name.as_ref().into(), func));
}
fn add_meta_function_mut<A, R, F>(&mut self, meta: impl Into<MetaMethod>, mut function: F)
fn add_meta_function_mut<F, A, R>(&mut self, name: impl AsRef<str>, mut function: F)
where
F: FnMut(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
F: 'static + MaybeSend + FnMut(&'lua Lua, A) -> Result<R>,
{
self.meta_methods.push((
meta.into(),
NonStaticMethod::FunctionMut(Box::new(move |lua, args| {
function(lua, A::from_lua_multi(args, lua)?)?.into_lua_multi(lua)
})),
));
let func = NonStaticMethod::FunctionMut(Box::new(move |lua, args| {
function(lua, A::from_lua_multi(args, lua)?)?.into_lua_multi(lua)
}));
self.meta_methods.push((name.as_ref().into(), func));
}
#[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
fn add_async_meta_function<A, R, F, FR>(&mut self, _meta: impl Into<MetaMethod>, _function: F)
fn add_async_meta_function<F, A, FR, R>(&mut self, _name: impl AsRef<str>, _function: F)
where
F: Fn(&'lua Lua, A) -> FR + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
FR: Future<Output = Result<R>> + 'lua,
R: IntoLuaMulti<'lua>,
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> FR,
FR: 'lua + Future<Output = Result<R>>,
{
// The panic should never happen as async non-static code wouldn't compile
// Non-static lifetime must be bounded to 'lua lifetime
mlua_panic!("asynchronous meta functions are not supported for non-static userdata")
panic!("asynchronous meta functions are not supported for non-static userdata")
}
}
@ -795,7 +779,7 @@ struct NonStaticUserDataFields<'lua, T: UserData> {
field_getters: Vec<(String, NonStaticMethod<'lua, T>)>,
field_setters: Vec<(String, NonStaticMethod<'lua, T>)>,
#[allow(clippy::type_complexity)]
meta_fields: Vec<(MetaMethod, Box<dyn Fn(&'lua Lua) -> Result<Value<'lua>>>)>,
meta_fields: Vec<(String, Box<dyn Fn(&'lua Lua) -> Result<Value<'lua>>>)>,
}
impl<'lua, T: UserData> Default for NonStaticUserDataFields<'lua, T> {
@ -809,75 +793,67 @@ impl<'lua, T: UserData> Default for NonStaticUserDataFields<'lua, T> {
}
impl<'lua, T: UserData> UserDataFields<'lua, T> for NonStaticUserDataFields<'lua, T> {
fn add_field_method_get<R, M>(&mut self, name: &str, method: M)
fn add_field_method_get<M, R>(&mut self, name: impl AsRef<str>, method: M)
where
M: Fn(&'lua Lua, &T) -> Result<R> + MaybeSend + 'static,
R: IntoLua<'lua>,
M: 'static + MaybeSend + Fn(&'lua Lua, &T) -> Result<R>,
{
self.field_getters.push((
name.into(),
NonStaticMethod::Method(Box::new(move |lua, ud, _| {
method(lua, ud)?.into_lua_multi(lua)
})),
));
let method = NonStaticMethod::Method(Box::new(move |lua, ud, _| {
method(lua, ud)?.into_lua_multi(lua)
}));
self.field_getters.push((name.as_ref().into(), method));
}
fn add_field_method_set<A, M>(&mut self, name: &str, mut method: M)
fn add_field_method_set<M, A>(&mut self, name: impl AsRef<str>, mut method: M)
where
M: FnMut(&'lua Lua, &mut T, A) -> Result<()> + MaybeSend + 'static,
A: FromLua<'lua>,
M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<()>,
{
self.field_setters.push((
name.into(),
NonStaticMethod::MethodMut(Box::new(move |lua, ud, args| {
method(lua, ud, A::from_lua_multi(args, lua)?)?.into_lua_multi(lua)
})),
));
let method = NonStaticMethod::MethodMut(Box::new(move |lua, ud, args| {
method(lua, ud, A::from_lua_multi(args, lua)?)?.into_lua_multi(lua)
}));
self.field_setters.push((name.as_ref().into(), method));
}
fn add_field_function_get<R, F>(&mut self, name: &str, function: F)
fn add_field_function_get<F, R>(&mut self, name: impl AsRef<str>, function: F)
where
F: Fn(&'lua Lua, AnyUserData<'lua>) -> Result<R> + MaybeSend + 'static,
R: IntoLua<'lua>,
F: 'static + MaybeSend + Fn(&'lua Lua, AnyUserData<'lua>) -> Result<R>,
{
self.field_getters.push((
name.into(),
NonStaticMethod::Function(Box::new(move |lua, args| {
function(lua, AnyUserData::from_lua_multi(args, lua)?)?.into_lua_multi(lua)
})),
));
let func = NonStaticMethod::Function(Box::new(move |lua, args| {
function(lua, AnyUserData::from_lua_multi(args, lua)?)?.into_lua_multi(lua)
}));
self.field_getters.push((name.as_ref().into(), func));
}
fn add_field_function_set<A, F>(&mut self, name: &str, mut function: F)
fn add_field_function_set<F, A>(&mut self, name: impl AsRef<str>, mut function: F)
where
F: FnMut(&'lua Lua, AnyUserData<'lua>, A) -> Result<()> + MaybeSend + 'static,
A: FromLua<'lua>,
F: 'static + MaybeSend + FnMut(&'lua Lua, AnyUserData<'lua>, A) -> Result<()>,
{
self.field_setters.push((
name.into(),
NonStaticMethod::FunctionMut(Box::new(move |lua, args| {
let (ud, val) = <_>::from_lua_multi(args, lua)?;
function(lua, ud, val)?.into_lua_multi(lua)
})),
));
let func = NonStaticMethod::FunctionMut(Box::new(move |lua, args| {
let (ud, val) = <_>::from_lua_multi(args, lua)?;
function(lua, ud, val)?.into_lua_multi(lua)
}));
self.field_setters.push((name.as_ref().into(), func));
}
fn add_meta_field_with<R, F>(&mut self, meta: impl Into<MetaMethod>, f: F)
fn add_meta_field_with<F, R>(&mut self, name: impl AsRef<str>, f: F)
where
F: 'static + MaybeSend + Fn(&'lua Lua) -> Result<R>,
F: Fn(&'lua Lua) -> Result<R> + MaybeSend + 'static,
R: IntoLua<'lua>,
{
let meta = meta.into();
let name = name.as_ref().to_string();
self.meta_fields.push((
meta.clone(),
name.clone(),
Box::new(move |lua| {
let value = f(lua)?.into_lua(lua)?;
if meta == MetaMethod::Index || meta == MetaMethod::NewIndex {
if name == MetaMethod::Index || name == MetaMethod::NewIndex {
match value {
Value::Nil | Value::Table(_) | Value::Function(_) => {}
_ => {
return Err(Error::MetaMethodTypeError {
method: meta.to_string(),
method: name.clone(),
type_name: value.type_name(),
message: Some("expected nil, table or function".to_string()),
})

View File

@ -1,7 +1,7 @@
use std::any::TypeId;
use std::cell::{Ref, RefCell, RefMut};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::hash::Hash;
use std::ops::{Deref, DerefMut};
use std::os::raw::{c_char, c_int};
use std::string::String as StdString;
@ -36,7 +36,7 @@ pub(crate) const USER_VALUE_MAXSLOT: usize = 8;
/// generally no need to do so: [`UserData`] implementors can instead just implement `Drop`.
///
/// [`UserData`]: crate::UserData
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MetaMethod {
/// The `+` operator.
Add,
@ -141,23 +141,17 @@ pub enum MetaMethod {
/// [lua_doc]: https://www.lua.org/manual/5.4/manual.html#3.3.8
#[cfg(any(feature = "lua54"))]
Close,
/// A custom metamethod.
///
/// Must not be in the protected list: `__gc`, `__metatable`, `__mlua*`.
Custom(StdString),
}
impl PartialEq for MetaMethod {
fn eq(&self, other: &Self) -> bool {
self.name() == other.name()
impl PartialEq<MetaMethod> for &str {
fn eq(&self, other: &MetaMethod) -> bool {
*self == other.name()
}
}
impl Eq for MetaMethod {}
impl Hash for MetaMethod {
fn hash<H: Hasher>(&self, state: &mut H) {
self.name().hash(state);
impl PartialEq<MetaMethod> for String {
fn eq(&self, other: &MetaMethod) -> bool {
self == other.name()
}
}
@ -169,7 +163,7 @@ impl fmt::Display for MetaMethod {
impl MetaMethod {
/// Returns Lua metamethod name, usually prefixed by two underscores.
pub fn name(&self) -> &str {
pub const fn name(self) -> &'static str {
match self {
MetaMethod::Add => "__add",
MetaMethod::Sub => "__sub",
@ -218,84 +212,22 @@ impl MetaMethod {
#[cfg(feature = "lua54")]
MetaMethod::Close => "__close",
MetaMethod::Custom(ref name) => name,
}
}
pub(crate) fn validate(self) -> Result<Self> {
match self {
MetaMethod::Custom(name) if name == "__gc" => Err(Error::MetaMethodRestricted(name)),
MetaMethod::Custom(name) if name == "__metatable" => {
Err(Error::MetaMethodRestricted(name))
}
MetaMethod::Custom(name) if name.starts_with("__mlua") => {
Err(Error::MetaMethodRestricted(name))
}
_ => Ok(self),
pub(crate) fn validate(name: &str) -> Result<&str> {
match name {
"__gc" => Err(Error::MetaMethodRestricted(name.to_string())),
"__metatable" => Err(Error::MetaMethodRestricted(name.to_string())),
_ if name.starts_with("__mlua") => Err(Error::MetaMethodRestricted(name.to_string())),
name => Ok(name),
}
}
}
impl From<StdString> for MetaMethod {
fn from(name: StdString) -> Self {
match name.as_str() {
"__add" => MetaMethod::Add,
"__sub" => MetaMethod::Sub,
"__mul" => MetaMethod::Mul,
"__div" => MetaMethod::Div,
"__mod" => MetaMethod::Mod,
"__pow" => MetaMethod::Pow,
"__unm" => MetaMethod::Unm,
#[cfg(any(feature = "lua54", feature = "lua53"))]
"__idiv" => MetaMethod::IDiv,
#[cfg(any(feature = "lua54", feature = "lua53"))]
"__band" => MetaMethod::BAnd,
#[cfg(any(feature = "lua54", feature = "lua53"))]
"__bor" => MetaMethod::BOr,
#[cfg(any(feature = "lua54", feature = "lua53"))]
"__bxor" => MetaMethod::BXor,
#[cfg(any(feature = "lua54", feature = "lua53"))]
"__bnot" => MetaMethod::BNot,
#[cfg(any(feature = "lua54", feature = "lua53"))]
"__shl" => MetaMethod::Shl,
#[cfg(any(feature = "lua54", feature = "lua53"))]
"__shr" => MetaMethod::Shr,
"__concat" => MetaMethod::Concat,
"__len" => MetaMethod::Len,
"__eq" => MetaMethod::Eq,
"__lt" => MetaMethod::Lt,
"__le" => MetaMethod::Le,
"__index" => MetaMethod::Index,
"__newindex" => MetaMethod::NewIndex,
"__call" => MetaMethod::Call,
"__tostring" => MetaMethod::ToString,
#[cfg(any(
feature = "lua54",
feature = "lua53",
feature = "lua52",
feature = "luajit52"
))]
"__pairs" => MetaMethod::Pairs,
#[cfg(any(feature = "lua52", feature = "luajit52"))]
"__ipairs" => MetaMethod::IPairs,
#[cfg(feature = "luau")]
"__iter" => MetaMethod::Iter,
#[cfg(feature = "lua54")]
"__close" => MetaMethod::Close,
_ => MetaMethod::Custom(name),
}
}
}
impl From<&str> for MetaMethod {
fn from(name: &str) -> Self {
MetaMethod::from(name.to_owned())
impl AsRef<str> for MetaMethod {
fn as_ref(&self) -> &str {
self.name()
}
}
@ -310,22 +242,22 @@ pub trait UserDataMethods<'lua, T: UserData> {
///
/// If `add_meta_method` is used to set the `__index` metamethod, the `__index` metamethod will
/// be used as a fall-back if no regular method is found.
fn add_method<A, R, M>(&mut self, name: &str, method: M)
fn add_method<M, A, R>(&mut self, name: impl AsRef<str>, method: M)
where
M: Fn(&'lua Lua, &T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
M: 'static + MaybeSend + Fn(&'lua Lua, &T, A) -> Result<R>;
R: IntoLuaMulti<'lua>;
/// Add a regular method which accepts a `&mut T` as the first parameter.
///
/// Refer to [`add_method`] for more information about the implementation.
///
/// [`add_method`]: #method.add_method
fn add_method_mut<A, R, M>(&mut self, name: &str, method: M)
fn add_method_mut<M, A, R>(&mut self, name: impl AsRef<str>, method: M)
where
M: FnMut(&'lua Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<R>;
R: IntoLuaMulti<'lua>;
/// Add an async method which accepts a `T` as the first parameter and returns Future.
/// The passed `T` is cloned from the original value.
@ -337,13 +269,13 @@ pub trait UserDataMethods<'lua, T: UserData> {
/// [`add_method`]: #method.add_method
#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
fn add_async_method<A, R, M, MR>(&mut self, name: &str, method: M)
fn add_async_method<M, A, MR, R>(&mut self, name: impl AsRef<str>, method: M)
where
T: Clone,
M: Fn(&'lua Lua, T, A) -> MR + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
M: 'static + MaybeSend + Fn(&'lua Lua, T, A) -> MR,
MR: 'lua + Future<Output = Result<R>>;
MR: Future<Output = Result<R>> + 'lua,
R: IntoLuaMulti<'lua>;
/// Add a regular method as a function which accepts generic arguments, the first argument will
/// be a [`AnyUserData`] of type `T` if the method is called with Lua method syntax:
@ -355,22 +287,22 @@ pub trait UserDataMethods<'lua, T: UserData> {
/// [`AnyUserData`]: crate::AnyUserData
/// [`add_method`]: #method.add_method
/// [`add_method_mut`]: #method.add_method_mut
fn add_function<A, R, F>(&mut self, name: &str, function: F)
fn add_function<F, A, R>(&mut self, name: impl AsRef<str>, function: F)
where
F: Fn(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> Result<R>;
R: IntoLuaMulti<'lua>;
/// Add a regular method as a mutable function which accepts generic arguments.
///
/// This is a version of [`add_function`] that accepts a FnMut argument.
///
/// [`add_function`]: #method.add_function
fn add_function_mut<A, R, F>(&mut self, name: &str, function: F)
fn add_function_mut<F, A, R>(&mut self, name: impl AsRef<str>, function: F)
where
F: FnMut(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
F: 'static + MaybeSend + FnMut(&'lua Lua, A) -> Result<R>;
R: IntoLuaMulti<'lua>;
/// Add a regular method as an async function which accepts generic arguments
/// and returns Future.
@ -382,12 +314,12 @@ pub trait UserDataMethods<'lua, T: UserData> {
/// [`add_function`]: #method.add_function
#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
fn add_async_function<A, R, F, FR>(&mut self, name: &str, function: F)
fn add_async_function<F, A, FR, R>(&mut self, name: impl AsRef<str>, function: F)
where
F: Fn(&'lua Lua, A) -> FR + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> FR,
FR: 'lua + Future<Output = Result<R>>;
FR: Future<Output = Result<R>> + 'lua,
R: IntoLuaMulti<'lua>;
/// Add a metamethod which accepts a `&T` as the first parameter.
///
@ -397,11 +329,11 @@ pub trait UserDataMethods<'lua, T: UserData> {
/// side has a metatable. To prevent this, use [`add_meta_function`].
///
/// [`add_meta_function`]: #method.add_meta_function
fn add_meta_method<A, R, M>(&mut self, meta: impl Into<MetaMethod>, method: M)
fn add_meta_method<M, A, R>(&mut self, name: impl AsRef<str>, method: M)
where
M: Fn(&'lua Lua, &T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
M: 'static + MaybeSend + Fn(&'lua Lua, &T, A) -> Result<R>;
R: IntoLuaMulti<'lua>;
/// Add a metamethod as a function which accepts a `&mut T` as the first parameter.
///
@ -411,11 +343,11 @@ pub trait UserDataMethods<'lua, T: UserData> {
/// side has a metatable. To prevent this, use [`add_meta_function`].
///
/// [`add_meta_function`]: #method.add_meta_function
fn add_meta_method_mut<A, R, M>(&mut self, meta: impl Into<MetaMethod>, method: M)
fn add_meta_method_mut<M, A, R>(&mut self, name: impl AsRef<str>, method: M)
where
M: FnMut(&'lua Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<R>;
R: IntoLuaMulti<'lua>;
/// Add an async metamethod which accepts a `T` as the first parameter and returns Future.
/// The passed `T` is cloned from the original value.
@ -427,35 +359,35 @@ pub trait UserDataMethods<'lua, T: UserData> {
/// [`add_meta_method`]: #method.add_meta_method
#[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
fn add_async_meta_method<A, R, M, MR>(&mut self, name: impl Into<MetaMethod>, method: M)
fn add_async_meta_method<M, A, MR, R>(&mut self, name: impl AsRef<str>, method: M)
where
T: Clone,
M: Fn(&'lua Lua, T, A) -> MR + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
M: 'static + MaybeSend + Fn(&'lua Lua, T, A) -> MR,
MR: 'lua + Future<Output = Result<R>>;
MR: Future<Output = Result<R>> + 'lua,
R: IntoLuaMulti<'lua>;
/// Add a metamethod which accepts generic arguments.
///
/// Metamethods for binary operators can be triggered if either the left or right argument to
/// the binary operator has a metatable, so the first argument here is not necessarily a
/// userdata of type `T`.
fn add_meta_function<A, R, F>(&mut self, meta: impl Into<MetaMethod>, function: F)
fn add_meta_function<F, A, R>(&mut self, name: impl AsRef<str>, function: F)
where
F: Fn(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> Result<R>;
R: IntoLuaMulti<'lua>;
/// Add a metamethod as a mutable function which accepts generic arguments.
///
/// This is a version of [`add_meta_function`] that accepts a FnMut argument.
///
/// [`add_meta_function`]: #method.add_meta_function
fn add_meta_function_mut<A, R, F>(&mut self, meta: impl Into<MetaMethod>, function: F)
fn add_meta_function_mut<F, A, R>(&mut self, name: impl AsRef<str>, function: F)
where
F: FnMut(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
F: 'static + MaybeSend + FnMut(&'lua Lua, A) -> Result<R>;
R: IntoLuaMulti<'lua>;
/// Add a metamethod which accepts generic arguments and returns Future.
///
@ -466,12 +398,12 @@ pub trait UserDataMethods<'lua, T: UserData> {
/// [`add_meta_function`]: #method.add_meta_function
#[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
fn add_async_meta_function<A, R, F, FR>(&mut self, name: impl Into<MetaMethod>, function: F)
fn add_async_meta_function<F, A, FR, R>(&mut self, name: impl AsRef<str>, function: F)
where
F: Fn(&'lua Lua, A) -> FR + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> FR,
FR: 'lua + Future<Output = Result<R>>;
FR: Future<Output = Result<R>> + 'lua,
R: IntoLuaMulti<'lua>;
//
// Below are internal methods used in generated code
@ -485,16 +417,11 @@ pub trait UserDataMethods<'lua, T: UserData> {
fn add_async_callback(&mut self, _name: String, _callback: AsyncCallback<'lua, 'static>) {}
#[doc(hidden)]
fn add_meta_callback(&mut self, _meta: MetaMethod, _callback: Callback<'lua, 'static>) {}
fn add_meta_callback(&mut self, _name: String, _callback: Callback<'lua, 'static>) {}
#[doc(hidden)]
#[cfg(feature = "async")]
fn add_async_meta_callback(
&mut self,
_meta: MetaMethod,
_callback: AsyncCallback<'lua, 'static>,
) {
}
fn add_async_meta_callback(&mut self, _name: String, _callback: AsyncCallback<'lua, 'static>) {}
}
/// Field registry for [`UserData`] implementors.
@ -508,10 +435,10 @@ pub trait UserDataFields<'lua, T: UserData> {
///
/// If `add_meta_method` is used to set the `__index` metamethod, the `__index` metamethod will
/// be used as a fall-back if no regular field or method are found.
fn add_field_method_get<R, M>(&mut self, name: &str, method: M)
fn add_field_method_get<M, R>(&mut self, name: impl AsRef<str>, method: M)
where
R: IntoLua<'lua>,
M: 'static + MaybeSend + Fn(&'lua Lua, &T) -> Result<R>;
M: Fn(&'lua Lua, &T) -> Result<R> + MaybeSend + 'static,
R: IntoLua<'lua>;
/// Add a regular field setter as a method which accepts a `&mut T` as the first parameter.
///
@ -520,10 +447,10 @@ pub trait UserDataFields<'lua, T: UserData> {
///
/// If `add_meta_method` is used to set the `__newindex` metamethod, the `__newindex` metamethod will
/// be used as a fall-back if no regular field is found.
fn add_field_method_set<A, M>(&mut self, name: &str, method: M)
fn add_field_method_set<M, A>(&mut self, name: impl AsRef<str>, method: M)
where
A: FromLua<'lua>,
M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<()>;
M: FnMut(&'lua Lua, &mut T, A) -> Result<()> + MaybeSend + 'static,
A: FromLua<'lua>;
/// Add a regular field getter as a function which accepts a generic [`AnyUserData`] of type `T`
/// argument.
@ -532,10 +459,10 @@ pub trait UserDataFields<'lua, T: UserData> {
///
/// [`AnyUserData`]: crate::AnyUserData
/// [`add_field_method_get`]: #method.add_field_method_get
fn add_field_function_get<R, F>(&mut self, name: &str, function: F)
fn add_field_function_get<F, R>(&mut self, name: impl AsRef<str>, function: F)
where
R: IntoLua<'lua>,
F: 'static + MaybeSend + Fn(&'lua Lua, AnyUserData<'lua>) -> Result<R>;
F: Fn(&'lua Lua, AnyUserData<'lua>) -> Result<R> + MaybeSend + 'static,
R: IntoLua<'lua>;
/// Add a regular field setter as a function which accepts a generic [`AnyUserData`] of type `T`
/// first argument.
@ -544,10 +471,10 @@ pub trait UserDataFields<'lua, T: UserData> {
///
/// [`AnyUserData`]: crate::AnyUserData
/// [`add_field_method_set`]: #method.add_field_method_set
fn add_field_function_set<A, F>(&mut self, name: &str, function: F)
fn add_field_function_set<F, A>(&mut self, name: impl AsRef<str>, function: F)
where
A: FromLua<'lua>,
F: 'static + MaybeSend + FnMut(&'lua Lua, AnyUserData<'lua>, A) -> Result<()>;
F: FnMut(&'lua Lua, AnyUserData<'lua>, A) -> Result<()> + MaybeSend + 'static,
A: FromLua<'lua>;
/// Add a metamethod value computed from `f`.
///
@ -557,10 +484,10 @@ pub trait UserDataFields<'lua, T: UserData> {
///
/// `mlua` will trigger an error on an attempt to define a protected metamethod,
/// like `__gc` or `__metatable`.
fn add_meta_field_with<R, F>(&mut self, meta: impl Into<MetaMethod>, f: F)
fn add_meta_field_with<F, R>(&mut self, name: impl AsRef<str>, f: F)
where
R: IntoLua<'lua>,
F: 'static + MaybeSend + Fn(&'lua Lua) -> Result<R>;
F: Fn(&'lua Lua) -> Result<R> + MaybeSend + 'static,
R: IntoLua<'lua>;
//
// Below are internal methods used in generated code
@ -642,10 +569,12 @@ pub trait UserDataFields<'lua, T: UserData> {
/// [`UserDataMethods`]: crate::UserDataMethods
pub trait UserData: Sized {
/// Adds custom fields specific to this userdata.
fn add_fields<'lua, F: UserDataFields<'lua, Self>>(_fields: &mut F) {}
#[allow(unused_variables)]
fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) {}
/// Adds custom methods and operators specific to this userdata.
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(_methods: &mut M) {}
#[allow(unused_variables)]
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {}
}
// Wraps UserData in a way to always implement `serde::Serialize` trait.
@ -661,7 +590,7 @@ impl<T> UserDataCell<T> {
#[inline]
pub(crate) fn new_ser(data: T) -> Self
where
T: 'static + Serialize,
T: Serialize + 'static,
{
UserDataCell(RefCell::new(UserDataWrapped::new_ser(data)))
}
@ -686,7 +615,7 @@ impl<T> UserDataCell<T> {
// Consumes this `UserDataCell`, returning the wrapped value.
#[inline]
fn into_inner(self) -> T {
unsafe fn into_inner(self) -> T {
self.0.into_inner().into_inner()
}
}
@ -707,17 +636,17 @@ impl<T> UserDataWrapped<T> {
#[inline]
fn new_ser(data: T) -> Self
where
T: 'static + Serialize,
T: Serialize + 'static,
{
UserDataWrapped::Serializable(Box::new(data))
}
#[inline]
fn into_inner(self) -> T {
unsafe fn into_inner(self) -> T {
match self {
Self::Default(data) => *data,
#[cfg(feature = "serialize")]
Self::Serializable(data) => unsafe { *Box::from_raw(Box::into_raw(data) as *mut T) },
Self::Serializable(data) => *Box::from_raw(Box::into_raw(data) as *mut T),
}
}
}
@ -796,7 +725,7 @@ impl OwnedAnyUserData {
impl<'lua> AnyUserData<'lua> {
/// Checks whether the type of this userdata is `T`.
pub fn is<T: 'static + UserData>(&self) -> bool {
pub fn is<T: UserData + 'static>(&self) -> bool {
match self.inspect(|_: &UserDataCell<T>| Ok(())) {
Ok(()) => true,
Err(Error::UserDataTypeMismatch) => false,
@ -811,7 +740,7 @@ impl<'lua> AnyUserData<'lua> {
/// Returns a `UserDataBorrowError` if the userdata is already mutably borrowed. Returns a
/// `UserDataTypeMismatch` if the userdata is not of type `T`.
#[inline]
pub fn borrow<T: 'static + UserData>(&self) -> Result<Ref<T>> {
pub fn borrow<T: UserData + 'static>(&self) -> Result<Ref<T>> {
self.inspect(|cell| cell.try_borrow())
}
@ -822,7 +751,7 @@ impl<'lua> AnyUserData<'lua> {
/// Returns a `UserDataBorrowMutError` if the userdata cannot be mutably borrowed.
/// Returns a `UserDataTypeMismatch` if the userdata is not of type `T`.
#[inline]
pub fn borrow_mut<T: 'static + UserData>(&self) -> Result<RefMut<T>> {
pub fn borrow_mut<T: UserData + 'static>(&self) -> Result<RefMut<T>> {
self.inspect(|cell| cell.try_borrow_mut())
}
@ -830,7 +759,7 @@ impl<'lua> AnyUserData<'lua> {
/// Sets the special "destructed" metatable that prevents any further operations with this userdata.
///
/// Keeps associated user values unchanged (they will be collected by Lua's GC).
pub fn take<T: 'static + UserData>(&self) -> Result<T> {
pub fn take<T: UserData + 'static>(&self) -> Result<T> {
let lua = self.0.lua;
let state = lua.state();
unsafe {
@ -980,12 +909,13 @@ impl<'lua> AnyUserData<'lua> {
/// The value can be retrieved with [`get_named_user_value`].
///
/// [`get_named_user_value`]: #method.get_named_user_value
pub fn set_named_user_value<V>(&self, name: &str, v: V) -> Result<()>
pub fn set_named_user_value<V>(&self, name: impl AsRef<str>, v: V) -> Result<()>
where
V: IntoLua<'lua>,
{
let lua = self.0.lua;
let state = lua.state();
let name = name.as_ref();
unsafe {
let _sg = StackGuard::new(state);
check_stack(state, 5)?;
@ -1018,12 +948,13 @@ impl<'lua> AnyUserData<'lua> {
/// Returns an associated value by name set by [`set_named_user_value`].
///
/// [`set_named_user_value`]: #method.set_named_user_value
pub fn get_named_user_value<V>(&self, name: &str) -> Result<V>
pub fn get_named_user_value<V>(&self, name: impl AsRef<str>) -> Result<V>
where
V: FromLua<'lua>,
{
let lua = self.0.lua;
let state = lua.state();
let name = name.as_ref();
unsafe {
let _sg = StackGuard::new(state);
check_stack(state, 4)?;
@ -1098,9 +1029,9 @@ impl<'lua> AnyUserData<'lua> {
Ok(false)
}
fn inspect<'a, T, R, F>(&'a self, func: F) -> Result<R>
fn inspect<'a, T, F, R>(&'a self, func: F) -> Result<R>
where
T: 'static + UserData,
T: UserData + 'static,
F: FnOnce(&'a UserDataCell<T>) -> Result<R>,
{
let lua = self.0.lua;
@ -1149,8 +1080,8 @@ impl<'lua> UserDataMetatable<'lua> {
///
/// If no value is associated to `key`, returns the `Nil` value.
/// Access to restricted metamethods such as `__gc` or `__metatable` will cause an error.
pub fn get<K: Into<MetaMethod>, V: FromLua<'lua>>(&self, key: K) -> Result<V> {
self.0.raw_get(key.into().validate()?.name())
pub fn get<V: FromLua<'lua>>(&self, key: impl AsRef<str>) -> Result<V> {
self.0.raw_get(MetaMethod::validate(key.as_ref())?)
}
/// Sets a key-value pair in the metatable.
@ -1159,18 +1090,18 @@ impl<'lua> UserDataMetatable<'lua> {
/// Access to restricted metamethods such as `__gc` or `__metatable` will cause an error.
/// Setting `__index` or `__newindex` metamethods is also restricted because their values are cached
/// for `mlua` internal usage.
pub fn set<K: Into<MetaMethod>, V: IntoLua<'lua>>(&self, key: K, value: V) -> Result<()> {
let key = key.into().validate()?;
pub fn set<V: IntoLua<'lua>>(&self, key: impl AsRef<str>, value: V) -> Result<()> {
let key = MetaMethod::validate(key.as_ref())?;
// `__index` and `__newindex` cannot be changed in runtime, because values are cached
if key == MetaMethod::Index || key == MetaMethod::NewIndex {
return Err(Error::MetaMethodRestricted(key.to_string()));
}
self.0.raw_set(key.name(), value)
self.0.raw_set(key, value)
}
/// Checks whether the metatable contains a non-nil value for `key`.
pub fn contains<K: Into<MetaMethod>>(&self, key: K) -> Result<bool> {
self.0.contains_key(key.into().validate()?.name())
pub fn contains(&self, key: impl AsRef<str>) -> Result<bool> {
self.0.contains_key(MetaMethod::validate(key.as_ref())?)
}
/// Consumes this metatable and returns an iterator over the pairs of the metatable.
@ -1197,15 +1128,15 @@ impl<'lua, V> Iterator for UserDataMetatablePairs<'lua, V>
where
V: FromLua<'lua>,
{
type Item = Result<(MetaMethod, V)>;
type Item = Result<(String, V)>;
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.0.next()? {
Ok((key, value)) => {
// Skip restricted metamethods
if let Ok(metamethod) = MetaMethod::from(key).validate() {
break Some(Ok((metamethod, value)));
if MetaMethod::validate(&key).is_ok() {
break Some(Ok((key, value)));
}
}
Err(e) => break Some(Err(e)),

View File

@ -19,21 +19,21 @@ use std::rc::Rc;
#[cfg(feature = "async")]
use {
crate::types::AsyncCallback,
futures_core::future::Future,
futures_util::future::{self, TryFutureExt},
std::future::Future,
};
pub(crate) struct StaticUserDataMethods<'lua, T: 'static + UserData> {
pub(crate) struct StaticUserDataMethods<'lua, T: UserData + 'static> {
pub(crate) methods: Vec<(String, Callback<'lua, 'static>)>,
#[cfg(feature = "async")]
pub(crate) async_methods: Vec<(String, AsyncCallback<'lua, 'static>)>,
pub(crate) meta_methods: Vec<(MetaMethod, Callback<'lua, 'static>)>,
pub(crate) meta_methods: Vec<(String, Callback<'lua, 'static>)>,
#[cfg(feature = "async")]
pub(crate) async_meta_methods: Vec<(MetaMethod, AsyncCallback<'lua, 'static>)>,
pub(crate) async_meta_methods: Vec<(String, AsyncCallback<'lua, 'static>)>,
_type: PhantomData<T>,
}
impl<'lua, T: 'static + UserData> Default for StaticUserDataMethods<'lua, T> {
impl<'lua, T: UserData + 'static> Default for StaticUserDataMethods<'lua, T> {
fn default() -> StaticUserDataMethods<'lua, T> {
StaticUserDataMethods {
methods: Vec::new(),
@ -47,134 +47,135 @@ impl<'lua, T: 'static + UserData> Default for StaticUserDataMethods<'lua, T> {
}
}
impl<'lua, T: 'static + UserData> UserDataMethods<'lua, T> for StaticUserDataMethods<'lua, T> {
fn add_method<A, R, M>(&mut self, name: &str, method: M)
impl<'lua, T: UserData + 'static> UserDataMethods<'lua, T> for StaticUserDataMethods<'lua, T> {
fn add_method<M, A, R>(&mut self, name: impl AsRef<str>, method: M)
where
M: Fn(&'lua Lua, &T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
M: 'static + MaybeSend + Fn(&'lua Lua, &T, A) -> Result<R>,
{
self.methods.push((name.into(), Self::box_method(method)));
}
fn add_method_mut<A, R, M>(&mut self, name: &str, method: M)
where
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<R>,
{
self.methods
.push((name.into(), Self::box_method_mut(method)));
.push((name.as_ref().into(), Self::box_method(method)));
}
fn add_method_mut<M, A, R>(&mut self, name: impl AsRef<str>, method: M)
where
M: FnMut(&'lua Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
{
self.methods
.push((name.as_ref().into(), Self::box_method_mut(method)));
}
#[cfg(feature = "async")]
fn add_async_method<A, R, M, MR>(&mut self, name: &str, method: M)
fn add_async_method<M, A, MR, R>(&mut self, name: impl AsRef<str>, method: M)
where
T: Clone,
M: Fn(&'lua Lua, T, A) -> MR + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
MR: Future<Output = Result<R>> + 'lua,
R: IntoLuaMulti<'lua>,
M: 'static + MaybeSend + Fn(&'lua Lua, T, A) -> MR,
MR: 'lua + Future<Output = Result<R>>,
{
self.async_methods
.push((name.into(), Self::box_async_method(method)));
.push((name.as_ref().into(), Self::box_async_method(method)));
}
fn add_function<A, R, F>(&mut self, name: &str, function: F)
fn add_function<F, A, R>(&mut self, name: impl AsRef<str>, function: F)
where
F: Fn(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> Result<R>,
{
self.methods
.push((name.into(), Self::box_function(function)));
.push((name.as_ref().into(), Self::box_function(function)));
}
fn add_function_mut<A, R, F>(&mut self, name: &str, function: F)
fn add_function_mut<F, A, R>(&mut self, name: impl AsRef<str>, function: F)
where
F: FnMut(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
F: 'static + MaybeSend + FnMut(&'lua Lua, A) -> Result<R>,
{
self.methods
.push((name.into(), Self::box_function_mut(function)));
.push((name.as_ref().into(), Self::box_function_mut(function)));
}
#[cfg(feature = "async")]
fn add_async_function<A, R, F, FR>(&mut self, name: &str, function: F)
fn add_async_function<F, A, FR, R>(&mut self, name: impl AsRef<str>, function: F)
where
F: Fn(&'lua Lua, A) -> FR + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
FR: Future<Output = Result<R>> + 'lua,
R: IntoLuaMulti<'lua>,
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> FR,
FR: 'lua + Future<Output = Result<R>>,
{
self.async_methods
.push((name.into(), Self::box_async_function(function)));
.push((name.as_ref().into(), Self::box_async_function(function)));
}
fn add_meta_method<A, R, M>(&mut self, meta: impl Into<MetaMethod>, method: M)
fn add_meta_method<M, A, R>(&mut self, name: impl AsRef<str>, method: M)
where
M: Fn(&'lua Lua, &T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
M: 'static + MaybeSend + Fn(&'lua Lua, &T, A) -> Result<R>,
{
self.meta_methods
.push((meta.into(), Self::box_method(method)));
.push((name.as_ref().into(), Self::box_method(method)));
}
fn add_meta_method_mut<A, R, M>(&mut self, meta: impl Into<MetaMethod>, method: M)
fn add_meta_method_mut<M, A, R>(&mut self, name: impl AsRef<str>, method: M)
where
M: FnMut(&'lua Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<R>,
{
self.meta_methods
.push((meta.into(), Self::box_method_mut(method)));
.push((name.as_ref().into(), Self::box_method_mut(method)));
}
#[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
fn add_async_meta_method<A, R, M, MR>(&mut self, meta: impl Into<MetaMethod>, method: M)
fn add_async_meta_method<M, A, MR, R>(&mut self, name: impl AsRef<str>, method: M)
where
T: Clone,
M: Fn(&'lua Lua, T, A) -> MR + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
MR: Future<Output = Result<R>> + 'lua,
R: IntoLuaMulti<'lua>,
M: 'static + MaybeSend + Fn(&'lua Lua, T, A) -> MR,
MR: 'lua + Future<Output = Result<R>>,
{
self.async_meta_methods
.push((meta.into(), Self::box_async_method(method)));
.push((name.as_ref().into(), Self::box_async_method(method)));
}
fn add_meta_function<A, R, F>(&mut self, meta: impl Into<MetaMethod>, function: F)
fn add_meta_function<F, A, R>(&mut self, name: impl AsRef<str>, function: F)
where
F: Fn(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> Result<R>,
{
self.meta_methods
.push((meta.into(), Self::box_function(function)));
.push((name.as_ref().into(), Self::box_function(function)));
}
fn add_meta_function_mut<A, R, F>(&mut self, meta: impl Into<MetaMethod>, function: F)
fn add_meta_function_mut<F, A, R>(&mut self, name: impl AsRef<str>, function: F)
where
F: FnMut(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
F: 'static + MaybeSend + FnMut(&'lua Lua, A) -> Result<R>,
{
self.meta_methods
.push((meta.into(), Self::box_function_mut(function)));
.push((name.as_ref().into(), Self::box_function_mut(function)));
}
#[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
fn add_async_meta_function<A, R, F, FR>(&mut self, meta: impl Into<MetaMethod>, function: F)
fn add_async_meta_function<F, A, FR, R>(&mut self, name: impl AsRef<str>, function: F)
where
F: Fn(&'lua Lua, A) -> FR + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
FR: Future<Output = Result<R>> + 'lua,
R: IntoLuaMulti<'lua>,
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> FR,
FR: 'lua + Future<Output = Result<R>>,
{
self.async_meta_methods
.push((meta.into(), Self::box_async_function(function)));
.push((name.as_ref().into(), Self::box_async_function(function)));
}
// Below are internal methods used in generated code
@ -188,26 +189,22 @@ impl<'lua, T: 'static + UserData> UserDataMethods<'lua, T> for StaticUserDataMet
self.async_methods.push((name, callback));
}
fn add_meta_callback(&mut self, meta: MetaMethod, callback: Callback<'lua, 'static>) {
self.meta_methods.push((meta, callback));
fn add_meta_callback(&mut self, name: String, callback: Callback<'lua, 'static>) {
self.meta_methods.push((name, callback));
}
#[cfg(feature = "async")]
fn add_async_meta_callback(
&mut self,
meta: MetaMethod,
callback: AsyncCallback<'lua, 'static>,
) {
fn add_async_meta_callback(&mut self, meta: String, callback: AsyncCallback<'lua, 'static>) {
self.async_meta_methods.push((meta, callback))
}
}
impl<'lua, T: 'static + UserData> StaticUserDataMethods<'lua, T> {
fn box_method<A, R, M>(method: M) -> Callback<'lua, 'static>
impl<'lua, T: UserData + 'static> StaticUserDataMethods<'lua, T> {
fn box_method<M, A, R>(method: M) -> Callback<'lua, 'static>
where
M: Fn(&'lua Lua, &T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
M: 'static + MaybeSend + Fn(&'lua Lua, &T, A) -> Result<R>,
{
Box::new(move |lua, mut args| {
if let Some(front) = args.pop_front() {
@ -264,11 +261,11 @@ impl<'lua, T: 'static + UserData> StaticUserDataMethods<'lua, T> {
})
}
fn box_method_mut<A, R, M>(method: M) -> Callback<'lua, 'static>
fn box_method_mut<M, A, R>(method: M) -> Callback<'lua, 'static>
where
M: FnMut(&'lua Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<R>,
{
let method = RefCell::new(method);
Box::new(move |lua, mut args| {
@ -334,13 +331,13 @@ impl<'lua, T: 'static + UserData> StaticUserDataMethods<'lua, T> {
}
#[cfg(feature = "async")]
fn box_async_method<A, R, M, MR>(method: M) -> AsyncCallback<'lua, 'static>
fn box_async_method<M, A, MR, R>(method: M) -> AsyncCallback<'lua, 'static>
where
T: Clone,
M: Fn(&'lua Lua, T, A) -> MR + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
MR: Future<Output = Result<R>> + 'lua,
R: IntoLuaMulti<'lua>,
M: 'static + MaybeSend + Fn(&'lua Lua, T, A) -> MR,
MR: 'lua + Future<Output = Result<R>>,
{
Box::new(move |lua, mut args| {
let fut_res = || {
@ -405,20 +402,20 @@ impl<'lua, T: 'static + UserData> StaticUserDataMethods<'lua, T> {
})
}
fn box_function<A, R, F>(function: F) -> Callback<'lua, 'static>
fn box_function<F, A, R>(function: F) -> Callback<'lua, 'static>
where
F: Fn(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> Result<R>,
{
Box::new(move |lua, args| function(lua, A::from_lua_multi(args, lua)?)?.into_lua_multi(lua))
}
fn box_function_mut<A, R, F>(function: F) -> Callback<'lua, 'static>
fn box_function_mut<F, A, R>(function: F) -> Callback<'lua, 'static>
where
F: FnMut(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
F: 'static + MaybeSend + FnMut(&'lua Lua, A) -> Result<R>,
{
let function = RefCell::new(function);
Box::new(move |lua, args| {
@ -430,12 +427,12 @@ impl<'lua, T: 'static + UserData> StaticUserDataMethods<'lua, T> {
}
#[cfg(feature = "async")]
fn box_async_function<A, R, F, FR>(function: F) -> AsyncCallback<'lua, 'static>
fn box_async_function<F, A, FR, R>(function: F) -> AsyncCallback<'lua, 'static>
where
F: Fn(&'lua Lua, A) -> FR + MaybeSend + 'static,
A: FromLuaMulti<'lua>,
FR: Future<Output = Result<R>> + 'lua,
R: IntoLuaMulti<'lua>,
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> FR,
FR: 'lua + Future<Output = Result<R>>,
{
Box::new(move |lua, args| {
let args = match A::from_lua_multi(args, lua) {
@ -449,18 +446,18 @@ impl<'lua, T: 'static + UserData> StaticUserDataMethods<'lua, T> {
}
}
pub(crate) struct StaticUserDataFields<'lua, T: 'static + UserData> {
pub(crate) struct StaticUserDataFields<'lua, T: UserData + 'static> {
pub(crate) field_getters: Vec<(String, Callback<'lua, 'static>)>,
pub(crate) field_setters: Vec<(String, Callback<'lua, 'static>)>,
#[allow(clippy::type_complexity)]
pub(crate) meta_fields: Vec<(
MetaMethod,
String,
Box<dyn Fn(&'lua Lua) -> Result<Value<'lua>> + 'static>,
)>,
_type: PhantomData<T>,
}
impl<'lua, T: 'static + UserData> Default for StaticUserDataFields<'lua, T> {
impl<'lua, T: UserData + 'static> Default for StaticUserDataFields<'lua, T> {
fn default() -> StaticUserDataFields<'lua, T> {
StaticUserDataFields {
field_getters: Vec::new(),
@ -471,67 +468,61 @@ impl<'lua, T: 'static + UserData> Default for StaticUserDataFields<'lua, T> {
}
}
impl<'lua, T: 'static + UserData> UserDataFields<'lua, T> for StaticUserDataFields<'lua, T> {
fn add_field_method_get<R, M>(&mut self, name: &str, method: M)
impl<'lua, T: UserData + 'static> UserDataFields<'lua, T> for StaticUserDataFields<'lua, T> {
fn add_field_method_get<M, R>(&mut self, name: impl AsRef<str>, method: M)
where
M: Fn(&'lua Lua, &T) -> Result<R> + MaybeSend + 'static,
R: IntoLua<'lua>,
M: 'static + MaybeSend + Fn(&'lua Lua, &T) -> Result<R>,
{
self.field_getters.push((
name.into(),
StaticUserDataMethods::box_method(move |lua, data, ()| method(lua, data)),
));
let method = StaticUserDataMethods::box_method(move |lua, data, ()| method(lua, data));
self.field_getters.push((name.as_ref().into(), method));
}
fn add_field_method_set<A, M>(&mut self, name: &str, method: M)
fn add_field_method_set<M, A>(&mut self, name: impl AsRef<str>, method: M)
where
M: FnMut(&'lua Lua, &mut T, A) -> Result<()> + MaybeSend + 'static,
A: FromLua<'lua>,
M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<()>,
{
self.field_setters
.push((name.into(), StaticUserDataMethods::box_method_mut(method)));
let method = StaticUserDataMethods::box_method_mut(method);
self.field_setters.push((name.as_ref().into(), method));
}
fn add_field_function_get<R, F>(&mut self, name: &str, function: F)
fn add_field_function_get<F, R>(&mut self, name: impl AsRef<str>, function: F)
where
F: Fn(&'lua Lua, AnyUserData<'lua>) -> Result<R> + MaybeSend + 'static,
R: IntoLua<'lua>,
F: 'static + MaybeSend + Fn(&'lua Lua, AnyUserData<'lua>) -> Result<R>,
{
self.field_getters.push((
name.into(),
StaticUserDataMethods::<T>::box_function(function),
));
let func = StaticUserDataMethods::<T>::box_function(function);
self.field_getters.push((name.as_ref().into(), func));
}
fn add_field_function_set<A, F>(&mut self, name: &str, mut function: F)
fn add_field_function_set<F, A>(&mut self, name: impl AsRef<str>, mut function: F)
where
F: FnMut(&'lua Lua, AnyUserData<'lua>, A) -> Result<()> + MaybeSend + 'static,
A: FromLua<'lua>,
F: 'static + MaybeSend + FnMut(&'lua Lua, AnyUserData<'lua>, A) -> Result<()>,
{
self.field_setters.push((
name.into(),
StaticUserDataMethods::<T>::box_function_mut(move |lua, (data, val)| {
function(lua, data, val)
}),
));
let func = StaticUserDataMethods::<T>::box_function_mut(move |lua, (data, val)| {
function(lua, data, val)
});
self.field_setters.push((name.as_ref().into(), func));
}
fn add_meta_field_with<R, F>(&mut self, meta: impl Into<MetaMethod>, f: F)
fn add_meta_field_with<F, R>(&mut self, name: impl AsRef<str>, f: F)
where
F: Fn(&'lua Lua) -> Result<R> + MaybeSend + 'static,
R: IntoLua<'lua>,
F: 'static + MaybeSend + Fn(&'lua Lua) -> Result<R>,
{
let meta = meta.into();
let name = name.as_ref().to_string();
self.meta_fields.push((
meta.clone(),
name.clone(),
Box::new(move |lua| {
let value = f(lua)?.into_lua(lua)?;
if meta == MetaMethod::Index || meta == MetaMethod::NewIndex {
if name == MetaMethod::Index || name == MetaMethod::NewIndex {
match value {
Value::Nil | Value::Table(_) | Value::Function(_) => {}
_ => {
return Err(Error::MetaMethodTypeError {
method: meta.to_string(),
method: name.to_string(),
type_name: value.type_name(),
message: Some("expected nil, table or function".to_string()),
})
@ -566,7 +557,7 @@ unsafe fn get_userdata_mut<'a, T>(state: *mut ffi::lua_State) -> Result<RefMut<'
macro_rules! lua_userdata_impl {
($type:ty) => {
impl<T: 'static + UserData> UserData for $type {
impl<T: UserData + 'static> UserData for $type {
fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) {
let mut orig_fields = StaticUserDataFields::default();
T::add_fields(&mut orig_fields);

View File

@ -543,7 +543,7 @@ fn test_metatable() -> Result<()> {
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_function("my_type_name", |_, data: AnyUserData| {
let metatable = data.get_metatable()?;
metatable.get::<_, String>("__type_name")
metatable.get::<String>("__type_name")
});
}
}
@ -561,7 +561,7 @@ fn test_metatable() -> Result<()> {
let ud: AnyUserData = globals.get("ud")?;
let metatable = ud.get_metatable()?;
match metatable.get::<_, Value>("__gc") {
match metatable.get::<Value>("__gc") {
Ok(_) => panic!("expected MetaMethodRestricted, got no error"),
Err(Error::MetaMethodRestricted(_)) => {}
Err(e) => panic!("expected MetaMethodRestricted, got {:?}", e),
@ -575,11 +575,10 @@ fn test_metatable() -> Result<()> {
let mut methods = metatable
.pairs()
.into_iter()
.map(|kv: Result<(_, Value)>| Ok(kv?.0))
.collect::<Result<Vec<_>>>()?;
methods.sort_by_cached_key(|k| k.name().to_owned());
assert_eq!(methods, vec![MetaMethod::Index, "__type_name".into()]);
methods.sort();
assert_eq!(methods, vec!["__index", "__type_name"]);
#[derive(Copy, Clone)]
struct MyUserData2(i64);