From 89b68e2a24976815e2e10e5936f3f0acaa6f087e Mon Sep 17 00:00:00 2001 From: Alex Orlenko Date: Sat, 16 Nov 2024 01:44:17 +0000 Subject: [PATCH] Remove generic from `RawLua::push_userdata_metatable`. This should help to reduce amount of generated code. --- src/scope.rs | 4 +- src/state.rs | 2 +- src/state/raw.rs | 34 +++------ src/userdata.rs | 2 +- src/userdata/registry.rs | 151 ++++++++++++++++++++++----------------- src/userdata/util.rs | 15 ++++ 6 files changed, 115 insertions(+), 93 deletions(-) diff --git a/src/scope.rs b/src/scope.rs index 1c31750..498cf74 100644 --- a/src/scope.rs +++ b/src/scope.rs @@ -176,7 +176,7 @@ impl<'scope, 'env: 'scope> Scope<'scope, 'env> { // Push the metatable and register it with no TypeId let mut registry = UserDataRegistry::new_unique(ud_ptr as *mut _); T::register(&mut registry); - self.lua.push_userdata_metatable(registry)?; + self.lua.push_userdata_metatable(registry.into_raw())?; let mt_ptr = ffi::lua_topointer(state, -1); self.lua.register_userdata_metatable(mt_ptr, None); @@ -224,7 +224,7 @@ impl<'scope, 'env: 'scope> Scope<'scope, 'env> { // Push the metatable and register it with no TypeId let mut registry = UserDataRegistry::new_unique(ud_ptr as *mut _); register(&mut registry); - self.lua.push_userdata_metatable(registry)?; + self.lua.push_userdata_metatable(registry.into_raw())?; let mt_ptr = ffi::lua_topointer(state, -1); self.lua.register_userdata_metatable(mt_ptr, None); diff --git a/src/state.rs b/src/state.rs index bd2e52a..9993714 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1317,7 +1317,7 @@ impl Lua { } // Register the type - lua.create_userdata_metatable(registry)?; + lua.create_userdata_metatable(registry.into_raw())?; } Ok(()) } diff --git a/src/state/raw.rs b/src/state/raw.rs index 53aca04..5d56eac 100644 --- a/src/state/raw.rs +++ b/src/state/raw.rs @@ -22,12 +22,14 @@ use crate::types::{ AppDataRef, AppDataRefMut, Callback, CallbackUpvalue, DestructedUserdata, Integer, LightUserData, MaybeSend, ReentrantMutex, RegistryKey, ValueRef, XRc, }; -use crate::userdata::{AnyUserData, MetaMethod, UserData, UserDataRegistry, UserDataStorage}; +use crate::userdata::{ + AnyUserData, MetaMethod, RawUserDataRegistry, UserData, UserDataRegistry, UserDataStorage, +}; use crate::util::{ assert_stack, check_stack, get_destructed_userdata_metatable, get_internal_userdata, get_main_state, get_metatable_ptr, get_userdata, init_error_registry, init_internal_metatable, init_userdata_metatable, pop_error, push_internal_userdata, push_string, push_table, rawset_field, safe_pcall, safe_xpcall, - short_type_name, take_userdata, StackGuard, WrappedFailure, + short_type_name, StackGuard, WrappedFailure, }; use crate::value::{Nil, Value}; @@ -757,7 +759,7 @@ impl RawLua { let mut registry = UserDataRegistry::new(type_id); T::register(&mut registry); - self.create_userdata_metatable(registry) + self.create_userdata_metatable(registry.into_raw()) }) } @@ -774,7 +776,7 @@ impl RawLua { // Create an empty metatable let registry = UserDataRegistry::::new(type_id); - self.create_userdata_metatable(registry) + self.create_userdata_metatable(registry.into_raw()) }) } @@ -810,12 +812,9 @@ impl RawLua { Ok(AnyUserData(self.pop_ref())) } - pub(crate) unsafe fn create_userdata_metatable( - &self, - registry: UserDataRegistry, - ) -> Result { + pub(crate) unsafe fn create_userdata_metatable(&self, registry: RawUserDataRegistry) -> Result { let state = self.state(); - let type_id = registry.type_id(); + let type_id = registry.type_id; self.push_userdata_metatable(registry)?; @@ -832,7 +831,7 @@ impl RawLua { Ok(id as Integer) } - pub(crate) unsafe fn push_userdata_metatable(&self, mut registry: UserDataRegistry) -> Result<()> { + pub(crate) unsafe fn push_userdata_metatable(&self, mut registry: RawUserDataRegistry) -> Result<()> { let state = self.state(); let mut stack_guard = StackGuard::new(state); check_stack(state, 13)?; @@ -859,7 +858,7 @@ impl RawLua { } // Set `__name/__type` if not provided if !has_name { - let type_name = short_type_name::(); + let type_name = registry.type_name; push_string(state, type_name.as_bytes(), !self.unlikely_memory_error())?; rawset_field(state, -2, MetaMethod::Type.name())?; } @@ -960,18 +959,7 @@ impl RawLua { } } - unsafe extern "C-unwind" fn userdata_destructor(state: *mut ffi::lua_State) -> c_int { - let ud = get_userdata::>(state, -1); - if !(*ud).is_borrowed() { - take_userdata::>(state); - ffi::lua_pushboolean(state, 1); - } else { - ffi::lua_pushboolean(state, 0); - } - 1 - } - - ffi::lua_pushcfunction(state, userdata_destructor::); + ffi::lua_pushcfunction(state, registry.destructor); rawset_field(state, metatable_index, "__gc")?; init_userdata_metatable( diff --git a/src/userdata.rs b/src/userdata.rs index 50f925d..7db8896 100644 --- a/src/userdata.rs +++ b/src/userdata.rs @@ -27,8 +27,8 @@ use { // Re-export for convenience pub(crate) use cell::UserDataStorage; pub use cell::{UserDataRef, UserDataRefMut}; -pub(crate) use registry::UserDataProxy; pub use registry::UserDataRegistry; +pub(crate) use registry::{RawUserDataRegistry, UserDataProxy}; /// Kinds of metamethods that can be overridden. /// diff --git a/src/userdata/registry.rs b/src/userdata/registry.rs index 54ec819..d720915 100644 --- a/src/userdata/registry.rs +++ b/src/userdata/registry.rs @@ -51,6 +51,12 @@ enum UserDataTypeId { /// Handle to registry for userdata methods and metamethods. pub struct UserDataRegistry { + raw: RawUserDataRegistry, + ud_type_id: UserDataTypeId, + _type: PhantomData, +} + +pub(crate) struct RawUserDataRegistry { // Fields pub(crate) fields: Vec<(String, StaticFieldCallback)>, pub(crate) field_getters: Vec<(String, Callback)>, @@ -65,42 +71,15 @@ pub struct UserDataRegistry { #[cfg(feature = "async")] pub(crate) async_meta_methods: Vec<(String, AsyncCallback)>, - type_id: UserDataTypeId, - _type: PhantomData, + pub(crate) destructor: ffi::lua_CFunction, + pub(crate) type_id: Option, + pub(crate) type_name: StdString, } -impl UserDataRegistry { - #[inline(always)] - pub(crate) fn new(type_id: TypeId) -> Self { - Self::with_type_id(UserDataTypeId::Shared(type_id)) - } - - #[inline(always)] - pub(crate) fn new_unique(ud_ptr: *mut c_void) -> Self { - Self::with_type_id(UserDataTypeId::Unique(ud_ptr)) - } - - #[inline(always)] - fn with_type_id(type_id: UserDataTypeId) -> Self { - UserDataRegistry { - fields: Vec::new(), - field_getters: Vec::new(), - field_setters: Vec::new(), - meta_fields: Vec::new(), - methods: Vec::new(), - #[cfg(feature = "async")] - async_methods: Vec::new(), - meta_methods: Vec::new(), - #[cfg(feature = "async")] - async_meta_methods: Vec::new(), - type_id, - _type: PhantomData, - } - } - +impl UserDataTypeId { #[inline] - pub(crate) fn type_id(&self) -> Option { - match self.type_id { + pub(crate) fn type_id(self) -> Option { + match self { UserDataTypeId::Shared(type_id) => Some(type_id), UserDataTypeId::Unique(_) => None, #[cfg(all(feature = "userdata-wrappers", not(feature = "send")))] @@ -119,6 +98,43 @@ impl UserDataRegistry { UserDataTypeId::ArcParkingLotRwLock(type_id) => Some(type_id), } } +} + +impl UserDataRegistry { + #[inline(always)] + pub(crate) fn new(type_id: TypeId) -> Self { + Self::with_type_id(UserDataTypeId::Shared(type_id)) + } + + #[inline(always)] + pub(crate) fn new_unique(ud_ptr: *mut c_void) -> Self { + Self::with_type_id(UserDataTypeId::Unique(ud_ptr)) + } + + #[inline(always)] + fn with_type_id(ud_type_id: UserDataTypeId) -> Self { + let raw = RawUserDataRegistry { + fields: Vec::new(), + field_getters: Vec::new(), + field_setters: Vec::new(), + meta_fields: Vec::new(), + methods: Vec::new(), + #[cfg(feature = "async")] + async_methods: Vec::new(), + meta_methods: Vec::new(), + #[cfg(feature = "async")] + async_meta_methods: Vec::new(), + destructor: super::util::userdata_destructor::, + type_id: ud_type_id.type_id(), + type_name: short_type_name::(), + }; + + UserDataRegistry { + raw, + ud_type_id, + _type: PhantomData, + } + } fn box_method(&self, name: &str, method: M) -> Callback where @@ -133,7 +149,7 @@ impl UserDataRegistry { }; } - let target_type_id = self.type_id; + let target_type_id = self.ud_type_id; Box::new(move |rawlua, nargs| unsafe { if nargs == 0 { let err = Error::from_lua_conversion("missing argument", "userdata", None); @@ -260,7 +276,7 @@ impl UserDataRegistry { } let method = RefCell::new(method); - let target_type_id = self.type_id; + let target_type_id = self.ud_type_id; Box::new(move |rawlua, nargs| unsafe { let mut method = method.try_borrow_mut().map_err(|_| Error::RecursiveMutCallback)?; if nargs == 0 { @@ -514,6 +530,11 @@ impl UserDataRegistry { } value.into_lua(lua) } + + #[inline(always)] + pub(crate) fn into_raw(self) -> RawUserDataRegistry { + self.raw + } } // Returns function name for the type `T`, without the module path @@ -527,7 +548,7 @@ impl UserDataFields for UserDataRegistry { V: IntoLua + 'static, { let name = name.to_string(); - self.fields.push(( + self.raw.fields.push(( name, Box::new(move |rawlua| unsafe { value.push_into_stack(rawlua) }), )); @@ -540,7 +561,7 @@ impl UserDataFields for UserDataRegistry { { let name = name.to_string(); let callback = self.box_method(&name, move |lua, data, ()| method(lua, data)); - self.field_getters.push((name, callback)); + self.raw.field_getters.push((name, callback)); } fn add_field_method_set(&mut self, name: impl ToString, method: M) @@ -550,7 +571,7 @@ impl UserDataFields for UserDataRegistry { { let name = name.to_string(); let callback = self.box_method_mut(&name, method); - self.field_setters.push((name, callback)); + self.raw.field_setters.push((name, callback)); } fn add_field_function_get(&mut self, name: impl ToString, function: F) @@ -560,7 +581,7 @@ impl UserDataFields for UserDataRegistry { { let name = name.to_string(); let callback = self.box_function(&name, function); - self.field_getters.push((name, callback)); + self.raw.field_getters.push((name, callback)); } fn add_field_function_set(&mut self, name: impl ToString, mut function: F) @@ -570,7 +591,7 @@ impl UserDataFields for UserDataRegistry { { let name = name.to_string(); let callback = self.box_function_mut(&name, move |lua, (data, val)| function(lua, data, val)); - self.field_setters.push((name, callback)); + self.raw.field_setters.push((name, callback)); } fn add_meta_field(&mut self, name: impl ToString, value: V) @@ -578,7 +599,7 @@ impl UserDataFields for UserDataRegistry { V: IntoLua + 'static, { let name = name.to_string(); - self.meta_fields.push(( + self.raw.meta_fields.push(( name.clone(), Box::new(move |rawlua| unsafe { Self::check_meta_field(rawlua.lua(), &name, value)?.push_into_stack(rawlua) @@ -592,7 +613,7 @@ impl UserDataFields for UserDataRegistry { R: IntoLua, { let name = name.to_string(); - self.meta_fields.push(( + self.raw.meta_fields.push(( name.clone(), Box::new(move |rawlua| unsafe { let lua = rawlua.lua(); @@ -611,7 +632,7 @@ impl UserDataMethods for UserDataRegistry { { let name = name.to_string(); let callback = self.box_method(&name, method); - self.methods.push((name, callback)); + self.raw.methods.push((name, callback)); } fn add_method_mut(&mut self, name: impl ToString, method: M) @@ -622,7 +643,7 @@ impl UserDataMethods for UserDataRegistry { { let name = name.to_string(); let callback = self.box_method_mut(&name, method); - self.methods.push((name, callback)); + self.raw.methods.push((name, callback)); } #[cfg(feature = "async")] @@ -636,7 +657,7 @@ impl UserDataMethods for UserDataRegistry { { let name = name.to_string(); let callback = self.box_async_method(&name, method); - self.async_methods.push((name, callback)); + self.raw.async_methods.push((name, callback)); } #[cfg(feature = "async")] @@ -650,7 +671,7 @@ impl UserDataMethods for UserDataRegistry { { let name = name.to_string(); let callback = self.box_async_method_mut(&name, method); - self.async_methods.push((name, callback)); + self.raw.async_methods.push((name, callback)); } fn add_function(&mut self, name: impl ToString, function: F) @@ -661,7 +682,7 @@ impl UserDataMethods for UserDataRegistry { { let name = name.to_string(); let callback = self.box_function(&name, function); - self.methods.push((name, callback)); + self.raw.methods.push((name, callback)); } fn add_function_mut(&mut self, name: impl ToString, function: F) @@ -672,7 +693,7 @@ impl UserDataMethods for UserDataRegistry { { let name = name.to_string(); let callback = self.box_function_mut(&name, function); - self.methods.push((name, callback)); + self.raw.methods.push((name, callback)); } #[cfg(feature = "async")] @@ -685,7 +706,7 @@ impl UserDataMethods for UserDataRegistry { { let name = name.to_string(); let callback = self.box_async_function(&name, function); - self.async_methods.push((name, callback)); + self.raw.async_methods.push((name, callback)); } fn add_meta_method(&mut self, name: impl ToString, method: M) @@ -696,7 +717,7 @@ impl UserDataMethods for UserDataRegistry { { let name = name.to_string(); let callback = self.box_method(&name, method); - self.meta_methods.push((name, callback)); + self.raw.meta_methods.push((name, callback)); } fn add_meta_method_mut(&mut self, name: impl ToString, method: M) @@ -707,7 +728,7 @@ impl UserDataMethods for UserDataRegistry { { let name = name.to_string(); let callback = self.box_method_mut(&name, method); - self.meta_methods.push((name, callback)); + self.raw.meta_methods.push((name, callback)); } #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))] @@ -721,7 +742,7 @@ impl UserDataMethods for UserDataRegistry { { let name = name.to_string(); let callback = self.box_async_method(&name, method); - self.async_meta_methods.push((name, callback)); + self.raw.async_meta_methods.push((name, callback)); } #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))] @@ -735,7 +756,7 @@ impl UserDataMethods for UserDataRegistry { { let name = name.to_string(); let callback = self.box_async_method_mut(&name, method); - self.async_meta_methods.push((name, callback)); + self.raw.async_meta_methods.push((name, callback)); } fn add_meta_function(&mut self, name: impl ToString, function: F) @@ -746,7 +767,7 @@ impl UserDataMethods for UserDataRegistry { { let name = name.to_string(); let callback = self.box_function(&name, function); - self.meta_methods.push((name, callback)); + self.raw.meta_methods.push((name, callback)); } fn add_meta_function_mut(&mut self, name: impl ToString, function: F) @@ -757,7 +778,7 @@ impl UserDataMethods for UserDataRegistry { { let name = name.to_string(); let callback = self.box_function_mut(&name, function); - self.meta_methods.push((name, callback)); + self.raw.meta_methods.push((name, callback)); } #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))] @@ -770,7 +791,7 @@ impl UserDataMethods for UserDataRegistry { { let name = name.to_string(); let callback = self.box_async_function(&name, function); - self.async_meta_methods.push((name, callback)); + self.raw.async_meta_methods.push((name, callback)); } } @@ -786,18 +807,16 @@ macro_rules! lua_userdata_impl { T::register(&mut orig_registry); // Copy all fields, methods, etc. from the original registry - registry.fields.extend(orig_registry.fields); - registry.field_getters.extend(orig_registry.field_getters); - registry.field_setters.extend(orig_registry.field_setters); - registry.meta_fields.extend(orig_registry.meta_fields); - registry.methods.extend(orig_registry.methods); + (registry.raw.fields).extend(orig_registry.raw.fields); + (registry.raw.field_getters).extend(orig_registry.raw.field_getters); + (registry.raw.field_setters).extend(orig_registry.raw.field_setters); + (registry.raw.meta_fields).extend(orig_registry.raw.meta_fields); + (registry.raw.methods).extend(orig_registry.raw.methods); #[cfg(feature = "async")] - registry.async_methods.extend(orig_registry.async_methods); - registry.meta_methods.extend(orig_registry.meta_methods); + (registry.raw.async_methods).extend(orig_registry.raw.async_methods); + (registry.raw.meta_methods).extend(orig_registry.raw.meta_methods); #[cfg(feature = "async")] - registry - .async_meta_methods - .extend(orig_registry.async_meta_methods); + (registry.raw.async_meta_methods).extend(orig_registry.raw.async_meta_methods); } } }; diff --git a/src/userdata/util.rs b/src/userdata/util.rs index 5d403c5..02c5ea4 100644 --- a/src/userdata/util.rs +++ b/src/userdata/util.rs @@ -1,5 +1,9 @@ use std::cell::Cell; use std::marker::PhantomData; +use std::os::raw::c_int; + +use super::UserDataStorage; +use crate::util::{get_userdata, take_userdata}; // This is a trick to check if a type is `Sync` or not. // It uses leaked specialization feature from stdlib. @@ -29,3 +33,14 @@ pub(crate) fn is_sync() -> bool { .clone(); is_sync.get() } + +pub(super) unsafe extern "C-unwind" fn userdata_destructor(state: *mut ffi::lua_State) -> c_int { + let ud = get_userdata::>(state, -1); + if !(*ud).is_borrowed() { + take_userdata::>(state); + ffi::lua_pushboolean(state, 1); + } else { + ffi::lua_pushboolean(state, 0); + } + 1 +}