summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Orlenko <zxteam@protonmail.com>2023-06-07 12:18:24 +0100
committerAlex Orlenko <zxteam@protonmail.com>2023-06-07 12:18:24 +0100
commit5a135a331a0a772af8d7980cf7f2bffef956f066 (patch)
treeaf9ba6a8b8271dd38d546674b3d60a9daa040192
parente7b712e29f48d9b8dbdc4493e7eb506d9f5a0b54 (diff)
downloadmlua-5a135a331a0a772af8d7980cf7f2bffef956f066.zip
Add `UserDataFields::add_field()` method to add static fields to UserData.
Plus `UserDataFields::add_meta_field()` for static meta fields. Fix propagating fields to wrapped UserData types.
-rw-r--r--src/lua.rs60
-rw-r--r--src/scope.rs58
-rw-r--r--src/userdata.rs58
-rw-r--r--src/userdata_impl.rs133
-rw-r--r--src/util/mod.rs27
-rw-r--r--tests/userdata.rs20
6 files changed, 218 insertions, 138 deletions
diff --git a/src/lua.rs b/src/lua.rs
index 8e6a8a2..ebd1260 100644
--- a/src/lua.rs
+++ b/src/lua.rs
@@ -1857,7 +1857,10 @@ impl Lua {
pub fn scope<'lua, 'scope, R>(
&'lua self,
f: impl FnOnce(&Scope<'lua, 'scope>) -> Result<R>,
- ) -> Result<R> {
+ ) -> Result<R>
+ where
+ 'lua: 'scope,
+ {
f(&Scope::new(self))
}
@@ -2487,7 +2490,7 @@ impl Lua {
unsafe fn register_userdata_metatable<'lua, T: 'static>(
&'lua self,
- registry: UserDataRegistrar<'lua, T>,
+ mut registry: UserDataRegistrar<'lua, T>,
) -> Result<Integer> {
let state = self.state();
let _sg = StackGuard::new(state);
@@ -2510,7 +2513,7 @@ impl Lua {
let mut has_name = false;
for (k, f) in registry.meta_fields {
has_name = has_name || k == "__name";
- self.push_value(f(self)?)?;
+ self.push_value(f(self, MultiValue::new())?.pop_front().unwrap())?;
rawset_field(state, -2, MetaMethod::validate(&k)?)?;
}
// Set `__name` if not provided
@@ -2523,6 +2526,32 @@ impl Lua {
let mut extra_tables_count = 0;
+ let fields_nrec = registry.fields.len();
+ if fields_nrec > 0 {
+ // If __index is a table then update it inplace
+ let index_type = ffi::lua_getfield(state, metatable_index, cstr!("__index"));
+ match index_type {
+ ffi::LUA_TNIL | ffi::LUA_TTABLE => {
+ if index_type == ffi::LUA_TNIL {
+ // Create a new table
+ ffi::lua_pop(state, 1);
+ push_table(state, 0, fields_nrec as c_int, true)?;
+ }
+ for (k, f) in registry.fields {
+ self.push_value(f(self, MultiValue::new())?.pop_front().unwrap())?;
+ rawset_field(state, -2, &k)?;
+ }
+ rawset_field(state, metatable_index, "__index")?;
+ }
+ _ => {
+ // Propagate fields to the field getters
+ for (k, f) in registry.fields {
+ registry.field_getters.push((k, f))
+ }
+ }
+ }
+ }
+
let mut field_getters_index = None;
let field_getters_nrec = registry.field_getters.len();
if field_getters_nrec > 0 {
@@ -2552,7 +2581,16 @@ impl Lua {
#[cfg(feature = "async")]
let methods_nrec = methods_nrec + registry.async_methods.len();
if methods_nrec > 0 {
- push_table(state, 0, methods_nrec as c_int, true)?;
+ // If __index is a table then update it inplace
+ let index_type = ffi::lua_getfield(state, metatable_index, cstr!("__index"));
+ match index_type {
+ ffi::LUA_TTABLE => {} // Update the existing table
+ _ => {
+ // Create a new table
+ ffi::lua_pop(state, 1);
+ push_table(state, 0, methods_nrec as c_int, true)?;
+ }
+ }
for (k, m) in registry.methods {
self.push_value(Value::Function(self.create_callback(m)?))?;
rawset_field(state, -2, &k)?;
@@ -2562,8 +2600,18 @@ impl Lua {
self.push_value(Value::Function(self.create_async_callback(m)?))?;
rawset_field(state, -2, &k)?;
}
- methods_index = Some(ffi::lua_absindex(state, -1));
- extra_tables_count += 1;
+ match index_type {
+ ffi::LUA_TTABLE => {
+ ffi::lua_pop(state, 1); // All done
+ }
+ ffi::LUA_TNIL => {
+ rawset_field(state, metatable_index, "__index")?; // Set the new table as __index
+ }
+ _ => {
+ methods_index = Some(ffi::lua_absindex(state, -1));
+ extra_tables_count += 1;
+ }
+ }
}
init_userdata_metatable::<UserDataCell<T>>(
diff --git a/src/scope.rs b/src/scope.rs
index 7c46413..3d4cb94 100644
--- a/src/scope.rs
+++ b/src/scope.rs
@@ -14,6 +14,7 @@ use crate::types::{Callback, CallbackUpvalue, LuaRef, MaybeSend};
use crate::userdata::{
AnyUserData, MetaMethod, UserData, UserDataCell, UserDataFields, UserDataMethods,
};
+use crate::userdata_impl::UserDataRegistrar;
use crate::util::{
assert_stack, check_stack, get_userdata, init_userdata_metatable, push_table, rawset_field,
take_userdata, StackGuard,
@@ -32,7 +33,10 @@ use std::future::Future;
/// See [`Lua::scope`] for more details.
///
/// [`Lua::scope`]: crate::Lua.html::scope
-pub struct Scope<'lua, 'scope> {
+pub struct Scope<'lua, 'scope>
+where
+ 'lua: 'scope,
+{
lua: &'lua Lua,
destructors: RefCell<Vec<(LuaRef<'lua>, DestructorCallback<'lua>)>>,
_scope_invariant: PhantomData<Cell<&'scope ()>>,
@@ -393,7 +397,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
rawset_field(state, -2, MetaMethod::validate(&k)?)?;
}
for (k, f) in ud_fields.meta_fields {
- lua.push_value(f(mem::transmute(lua))?)?;
+ lua.push_value(f(lua, MultiValue::new())?.pop_front().unwrap())?;
rawset_field(state, -2, MetaMethod::validate(&k)?)?;
}
let metatable_index = ffi::lua_absindex(state, -1);
@@ -734,15 +738,16 @@ impl<'lua, T: UserData> UserDataMethods<'lua, T> for NonStaticUserDataMethods<'l
}
struct NonStaticUserDataFields<'lua, T: UserData> {
+ fields: Vec<(String, Callback<'lua, 'static>)>,
field_getters: Vec<(String, NonStaticMethod<'lua, T>)>,
field_setters: Vec<(String, NonStaticMethod<'lua, T>)>,
- #[allow(clippy::type_complexity)]
- meta_fields: Vec<(String, Box<dyn Fn(&'lua Lua) -> Result<Value<'lua>>>)>,
+ meta_fields: Vec<(String, Callback<'lua, 'static>)>,
}
impl<'lua, T: UserData> Default for NonStaticUserDataFields<'lua, T> {
fn default() -> NonStaticUserDataFields<'lua, T> {
NonStaticUserDataFields {
+ fields: Vec::new(),
field_getters: Vec::new(),
field_setters: Vec::new(),
meta_fields: Vec::new(),
@@ -751,6 +756,17 @@ impl<'lua, T: UserData> Default for NonStaticUserDataFields<'lua, T> {
}
impl<'lua, T: UserData> UserDataFields<'lua, T> for NonStaticUserDataFields<'lua, T> {
+ fn add_field<V>(&mut self, name: impl AsRef<str>, value: V)
+ where
+ V: IntoLua<'lua> + Clone + 'static,
+ {
+ let name = name.as_ref().to_string();
+ self.fields.push((
+ name,
+ Box::new(move |lua, _| value.clone().into_lua_multi(lua)),
+ ));
+ }
+
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,
@@ -796,30 +812,30 @@ impl<'lua, T: UserData> UserDataFields<'lua, T> for NonStaticUserDataFields<'lua
self.field_setters.push((name.as_ref().into(), func));
}
+ fn add_meta_field<V>(&mut self, name: impl AsRef<str>, value: V)
+ where
+ V: IntoLua<'lua> + Clone + 'static,
+ {
+ let name = name.as_ref().to_string();
+ let name2 = name.clone();
+ self.meta_fields.push((
+ name,
+ Box::new(move |lua, _| {
+ UserDataRegistrar::<()>::check_meta_field(lua, &name2, value.clone())
+ }),
+ ));
+ }
+
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>,
{
let name = name.as_ref().to_string();
+ let name2 = name.clone();
self.meta_fields.push((
- name.clone(),
- Box::new(move |lua| {
- let value = f(lua)?.into_lua(lua)?;
- if name == MetaMethod::Index || name == MetaMethod::NewIndex {
- match value {
- Value::Nil | Value::Table(_) | Value::Function(_) => {}
- _ => {
- return Err(Error::MetaMethodTypeError {
- method: name.clone(),
- type_name: value.type_name(),
- message: Some("expected nil, table or function".to_string()),
- })
- }
- }
- }
- Ok(value)
- }),
+ name,
+ Box::new(move |lua, _| UserDataRegistrar::<()>::check_meta_field(lua, &name2, f(lua)?)),
));
}
}
diff --git a/src/userdata.rs b/src/userdata.rs
index 68edf67..8215083 100644
--- a/src/userdata.rs
+++ b/src/userdata.rs
@@ -21,12 +21,10 @@ use crate::function::Function;
use crate::lua::Lua;
use crate::string::String;
use crate::table::{Table, TablePairs};
-use crate::types::{Callback, LuaRef, MaybeSend};
+use crate::types::{LuaRef, MaybeSend};
use crate::util::{check_stack, get_userdata, take_userdata, StackGuard};
use crate::value::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, Value};
-
-#[cfg(feature = "async")]
-use crate::types::AsyncCallback;
+use crate::UserDataRegistrar;
#[cfg(feature = "lua54")]
pub(crate) const USER_VALUE_MAXSLOT: usize = 8;
@@ -412,29 +410,26 @@ pub trait UserDataMethods<'lua, T> {
//
#[doc(hidden)]
- fn add_callback(&mut self, _name: StdString, _callback: Callback<'lua, 'static>) {}
-
- #[doc(hidden)]
- #[cfg(feature = "async")]
- fn add_async_callback(&mut self, _name: StdString, _callback: AsyncCallback<'lua, 'static>) {}
-
- #[doc(hidden)]
- fn add_meta_callback(&mut self, _name: StdString, _callback: Callback<'lua, 'static>) {}
-
- #[doc(hidden)]
- #[cfg(feature = "async")]
- fn add_async_meta_callback(
- &mut self,
- _name: StdString,
- _callback: AsyncCallback<'lua, 'static>,
- ) {
- }
+ fn append_methods_from<S>(&mut self, _other: UserDataRegistrar<'lua, S>) {}
}
/// Field registry for [`UserData`] implementors.
///
/// [`UserData`]: crate::UserData
pub trait UserDataFields<'lua, T> {
+ /// Add a static field to the `UserData`.
+ ///
+ /// Static fields are implemented by updating the `__index` metamethod and returning the
+ /// accessed field. This allows them to be used with the expected `userdata.field` syntax.
+ ///
+ /// Static fields are usually shared between all instances of the `UserData` of the same type.
+ ///
+ /// If `add_meta_method` is used to set the `__index` metamethod, it will
+ /// be used as a fall-back if no regular field or method are found.
+ fn add_field<V>(&mut self, name: impl AsRef<str>, value: V)
+ where
+ V: IntoLua<'lua> + Clone + 'static;
+
/// Add a regular field getter as a method which accepts a `&T` as the parameter.
///
/// Regular field getters are implemented by overriding the `__index` metamethod and returning the
@@ -483,9 +478,21 @@ pub trait UserDataFields<'lua, T> {
F: FnMut(&'lua Lua, AnyUserData<'lua>, A) -> Result<()> + MaybeSend + 'static,
A: FromLua<'lua>;
- /// Add a metamethod value computed from `f`.
+ /// Add a metatable field.
+ ///
+ /// This will initialize the metatable field with `value` on `UserData` creation.
+ ///
+ /// # Note
+ ///
+ /// `mlua` will trigger an error on an attempt to define a protected metamethod,
+ /// like `__gc` or `__metatable`.
+ fn add_meta_field<V>(&mut self, name: impl AsRef<str>, value: V)
+ where
+ V: IntoLua<'lua> + Clone + 'static;
+
+ /// Add a metatable field computed from `f`.
///
- /// This will initialize the metamethod value from `f` on `UserData` creation.
+ /// This will initialize the metatable field from `f` on `UserData` creation.
///
/// # Note
///
@@ -501,10 +508,7 @@ pub trait UserDataFields<'lua, T> {
//
#[doc(hidden)]
- fn add_field_getter(&mut self, _name: StdString, _callback: Callback<'lua, 'static>) {}
-
- #[doc(hidden)]
- fn add_field_setter(&mut self, _name: StdString, _callback: Callback<'lua, 'static>) {}
+ fn append_fields_from<S>(&mut self, _other: UserDataRegistrar<'lua, S>) {}
}
/// Trait for custom userdata types.
diff --git a/src/userdata_impl.rs b/src/userdata_impl.rs
index 7f140ac..363ef63 100644
--- a/src/userdata_impl.rs
+++ b/src/userdata_impl.rs
@@ -11,7 +11,7 @@ use crate::userdata::{
AnyUserData, MetaMethod, UserData, UserDataCell, UserDataFields, UserDataMethods,
};
use crate::util::{check_stack, get_userdata, short_type_name, StackGuard};
-use crate::value::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, Value};
+use crate::value::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, MultiValue, Value};
#[cfg(not(feature = "send"))]
use std::rc::Rc;
@@ -25,13 +25,10 @@ use {
pub struct UserDataRegistrar<'lua, T: 'static> {
// Fields
+ pub(crate) fields: Vec<(String, Callback<'lua, '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<(
- String,
- Box<dyn Fn(&'lua Lua) -> Result<Value<'lua>> + 'static>,
- )>,
+ pub(crate) meta_fields: Vec<(String, Callback<'lua, 'static>)>,
// Methods
pub(crate) methods: Vec<(String, Callback<'lua, 'static>)>,
@@ -47,6 +44,7 @@ pub struct UserDataRegistrar<'lua, T: 'static> {
impl<'lua, T: 'static> UserDataRegistrar<'lua, T> {
pub(crate) const fn new() -> Self {
UserDataRegistrar {
+ fields: Vec::new(),
field_getters: Vec::new(),
field_setters: Vec::new(),
meta_fields: Vec::new(),
@@ -360,6 +358,30 @@ impl<'lua, T: 'static> UserDataRegistrar<'lua, T> {
)
})
}
+
+ pub(crate) fn check_meta_field<V>(
+ lua: &'lua Lua,
+ name: &str,
+ value: V,
+ ) -> Result<MultiValue<'lua>>
+ where
+ V: IntoLua<'lua>,
+ {
+ let value = value.into_lua(lua)?;
+ if name == MetaMethod::Index || name == MetaMethod::NewIndex {
+ match value {
+ Value::Nil | Value::Table(_) | Value::Function(_) => {}
+ _ => {
+ return Err(Error::MetaMethodTypeError {
+ method: name.to_string(),
+ type_name: value.type_name(),
+ message: Some("expected nil, table or function".to_string()),
+ })
+ }
+ }
+ }
+ value.into_lua_multi(lua)
+ }
}
// Returns function name for the type `T`, without the module path
@@ -368,6 +390,17 @@ fn get_function_name<T>(name: &str) -> StdString {
}
impl<'lua, T: 'static> UserDataFields<'lua, T> for UserDataRegistrar<'lua, T> {
+ fn add_field<V>(&mut self, name: impl AsRef<str>, value: V)
+ where
+ V: IntoLua<'lua> + Clone + 'static,
+ {
+ let name = name.as_ref().to_string();
+ self.fields.push((
+ name,
+ Box::new(move |lua, _| value.clone().into_lua_multi(lua)),
+ ));
+ }
+
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,
@@ -408,41 +441,38 @@ impl<'lua, T: 'static> UserDataFields<'lua, T> for UserDataRegistrar<'lua, T> {
self.field_setters.push((name.into(), func));
}
+ fn add_meta_field<V>(&mut self, name: impl AsRef<str>, value: V)
+ where
+ V: IntoLua<'lua> + Clone + 'static,
+ {
+ let name = name.as_ref().to_string();
+ let name2 = name.clone();
+ self.meta_fields.push((
+ name,
+ Box::new(move |lua, _| Self::check_meta_field(lua, &name2, value.clone())),
+ ));
+ }
+
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>,
{
let name = name.as_ref().to_string();
+ let name2 = name.clone();
self.meta_fields.push((
- name.clone(),
- Box::new(move |lua| {
- let value = f(lua)?.into_lua(lua)?;
- if name == MetaMethod::Index || name == MetaMethod::NewIndex {
- match value {
- Value::Nil | Value::Table(_) | Value::Function(_) => {}
- _ => {
- return Err(Error::MetaMethodTypeError {
- method: name.clone(),
- type_name: value.type_name(),
- message: Some("expected nil, table or function".to_string()),
- })
- }
- }
- }
- Ok(value)
- }),
+ name,
+ Box::new(move |lua, _| Self::check_meta_field(lua, &name2, f(lua)?)),
));
}
// Below are internal methods
- fn add_field_getter(&mut self, name: String, callback: Callback<'lua, 'static>) {
- self.field_getters.push((name, callback));
- }
-
- fn add_field_setter(&mut self, name: String, callback: Callback<'lua, 'static>) {
- self.field_setters.push((name, callback));
+ fn append_fields_from<S>(&mut self, other: UserDataRegistrar<'lua, S>) {
+ self.fields.extend(other.fields);
+ self.field_getters.extend(other.field_getters);
+ self.field_setters.extend(other.field_setters);
+ self.meta_fields.extend(other.meta_fields);
}
}
@@ -591,22 +621,13 @@ impl<'lua, T: 'static> UserDataMethods<'lua, T> for UserDataRegistrar<'lua, T> {
// Below are internal methods used in generated code
- fn add_callback(&mut self, name: String, callback: Callback<'lua, 'static>) {
- self.methods.push((name, callback));
- }
-
- #[cfg(feature = "async")]
- fn add_async_callback(&mut self, name: String, callback: AsyncCallback<'lua, 'static>) {
- self.async_methods.push((name, 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: String, callback: AsyncCallback<'lua, 'static>) {
- self.async_meta_methods.push((meta, callback))
+ fn append_methods_from<S>(&mut self, other: UserDataRegistrar<'lua, S>) {
+ self.methods.extend(other.methods);
+ #[cfg(feature = "async")]
+ self.async_methods.extend(other.async_methods);
+ self.meta_methods.extend(other.meta_methods);
+ #[cfg(feature = "async")]
+ self.async_meta_methods.extend(other.async_meta_methods);
}
}
@@ -626,31 +647,13 @@ macro_rules! lua_userdata_impl {
fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) {
let mut orig_fields = UserDataRegistrar::new();
T::add_fields(&mut orig_fields);
- for (name, callback) in orig_fields.field_getters {
- fields.add_field_getter(name, callback);
- }
- for (name, callback) in orig_fields.field_setters {
- fields.add_field_setter(name, callback);
- }
+ fields.append_fields_from(orig_fields);
}
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
let mut orig_methods = UserDataRegistrar::new();
T::add_methods(&mut orig_methods);
- for (name, callback) in orig_methods.methods {
- methods.add_callback(name, callback);
- }
- #[cfg(feature = "async")]
- for (name, callback) in orig_methods.async_methods {
- methods.add_async_callback(name, callback);
- }
- for (meta, callback) in orig_methods.meta_methods {
- methods.add_meta_callback(meta, callback);
- }
- #[cfg(feature = "async")]
- for (meta, callback) in orig_methods.async_meta_methods {
- methods.add_async_meta_callback(meta, callback);
- }
+ methods.append_methods_from(orig_methods);
}
}
};
diff --git a/src/util/mod.rs b/src/util/mod.rs
index 394ce34..97681ab 100644
--- a/src/util/mod.rs
+++ b/src/util/mod.rs
@@ -402,9 +402,12 @@ unsafe extern "C" fn lua_error_impl(state: *mut ffi::lua_State) -> c_int {
}
unsafe extern "C" fn lua_isfunction_impl(state: *mut ffi::lua_State) -> c_int {
- let t = ffi::lua_type(state, -1);
- ffi::lua_pop(state, 1);
- ffi::lua_pushboolean(state, (t == ffi::LUA_TFUNCTION) as c_int);
+ ffi::lua_pushboolean(state, ffi::lua_isfunction(state, -1));
+ 1
+}
+
+unsafe extern "C" fn lua_istable_impl(state: *mut ffi::lua_State) -> c_int {
+ ffi::lua_pushboolean(state, ffi::lua_istable(state, -1));
1
}
@@ -418,14 +421,19 @@ unsafe fn init_userdata_metatable_index(state: *mut ffi::lua_State) -> Result<()
// Create and cache `__index` generator
let code = cstr!(
r#"
- local error, isfunction = ...
+ local error, isfunction, istable = ...
return function (__index, field_getters, methods)
- -- Fastpath to return methods table for index access
- if __index == nil and field_getters == nil then
- return methods
+ -- Common case: has field getters and index is a table
+ if field_getters ~= nil and methods == nil and istable(__index) then
+ return function (self, key)
+ local field_getter = field_getters[key]
+ if field_getter ~= nil then
+ return field_getter(self)
+ end
+ return __index[key]
+ end
end
- -- Alternatively return a function for index access
return function (self, key)
if field_getters ~= nil then
local field_getter = field_getters[key]
@@ -460,7 +468,8 @@ unsafe fn init_userdata_metatable_index(state: *mut ffi::lua_State) -> Result<()
}
ffi::lua_pushcfunction(state, lua_error_impl);
ffi::lua_pushcfunction(state, lua_isfunction_impl);
- ffi::lua_call(state, 2, 1);
+ ffi::lua_pushcfunction(state, lua_istable_impl);
+ ffi::lua_call(state, 3, 1);
#[cfg(feature = "luau-jit")]
if ffi::luau_codegen_supported() != 0 {
diff --git a/tests/userdata.rs b/tests/userdata.rs
index 5045f6e..c545586 100644
--- a/tests/userdata.rs
+++ b/tests/userdata.rs
@@ -1,3 +1,4 @@
+use std::collections::HashMap;
use std::string::String as StdString;
use std::sync::Arc;
#[cfg(not(feature = "parking_lot"))]
@@ -486,6 +487,7 @@ fn test_fields() -> Result<()> {
impl UserData for MyUserData {
fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) {
+ fields.add_field("static", "constant");
fields.add_field_method_get("val", |_, data| Ok(data.0));
fields.add_field_method_set("val", |_, data, val| {
data.0 = val;
@@ -497,11 +499,7 @@ fn test_fields() -> Result<()> {
fields
.add_field_function_set("uval", |_, ud, s| ud.set_user_value::<Option<String>>(s));
- fields.add_meta_field_with(MetaMethod::Index, |lua| {
- let index = lua.create_table()?;
- index.set("f", 321)?;
- Ok(index)
- });
+ fields.add_meta_field(MetaMethod::Index, HashMap::from([("f", 321)]));
fields.add_meta_field_with(MetaMethod::NewIndex, |lua| {
lua.create_function(|lua, (_, field, val): (AnyUserData, String, Value)| {
lua.globals().set(field, val)?;
@@ -516,6 +514,7 @@ fn test_fields() -> Result<()> {
globals.set("ud", MyUserData(7))?;
lua.load(
r#"
+ assert(ud.static == "constant")
assert(ud.val == 7)
ud.val = 10
assert(ud.val == 10)
@@ -614,6 +613,7 @@ fn test_userdata_wrapped() -> Result<()> {
impl UserData for MyUserData {
fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) {
+ fields.add_field("static", "constant");
fields.add_field_method_get("data", |_, this| Ok(this.0));
fields.add_field_method_set("data", |_, this, val| {
this.0 = val;
@@ -631,6 +631,7 @@ fn test_userdata_wrapped() -> Result<()> {
globals.set("rc_refcell_ud", ud1.clone())?;
lua.load(
r#"
+ assert(rc_refcell_ud.static == "constant")
rc_refcell_ud.data = rc_refcell_ud.data + 1
assert(rc_refcell_ud.data == 2)
"#,
@@ -646,6 +647,7 @@ fn test_userdata_wrapped() -> Result<()> {
globals.set("arc_mutex_ud", ud2.clone())?;
lua.load(
r#"
+ assert(arc_mutex_ud.static == "constant")
arc_mutex_ud.data = arc_mutex_ud.data + 1
assert(arc_mutex_ud.data == 3)
"#,
@@ -660,6 +662,7 @@ fn test_userdata_wrapped() -> Result<()> {
globals.set("arc_rwlock_ud", ud3.clone())?;
lua.load(
r#"
+ assert(arc_rwlock_ud.static == "constant")
arc_rwlock_ud.data = arc_rwlock_ud.data + 1
assert(arc_rwlock_ud.data == 4)
"#,
@@ -686,7 +689,7 @@ fn test_userdata_proxy() -> Result<()> {
impl UserData for MyUserData {
fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) {
- fields.add_field_function_get("static_field", |_, _| Ok(123));
+ fields.add_field("static_field", 123);
fields.add_field_method_get("n", |_, this| Ok(this.0));
}
@@ -780,10 +783,7 @@ fn test_userdata_ext() -> Result<()> {
assert_eq!(ud.get::<_, u32>("n")?, 123);
ud.set("n", 321)?;
assert_eq!(ud.get::<_, u32>("n")?, 321);
- match ud.get::<_, u32>("non-existent") {
- Err(Error::RuntimeError(_)) => {}
- r => panic!("expected RuntimeError, got {r:?}"),
- }
+ assert_eq!(ud.get::<_, Option<u32>>("non-existent")?, None);
match ud.set::<_, u32>("non-existent", 123) {
Err(Error::RuntimeError(_)) => {}
r => panic!("expected RuntimeError, got {r:?}"),