mlua/userdata/
registry.rs

1#![allow(clippy::await_holding_refcell_ref, clippy::await_holding_lock)]
2
3use std::any::TypeId;
4use std::cell::RefCell;
5use std::marker::PhantomData;
6use std::os::raw::c_void;
7use std::string::String as StdString;
8
9use crate::error::{Error, Result};
10use crate::state::{Lua, LuaGuard};
11use crate::traits::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti};
12use crate::types::{Callback, MaybeSend};
13use crate::userdata::{
14    borrow_userdata_scoped, borrow_userdata_scoped_mut, AnyUserData, MetaMethod, TypeIdHints, UserData,
15    UserDataFields, UserDataMethods, UserDataStorage,
16};
17use crate::util::short_type_name;
18use crate::value::Value;
19
20#[cfg(feature = "async")]
21use {
22    crate::types::AsyncCallback,
23    crate::userdata::{UserDataRef, UserDataRefMut},
24    std::future::{self, Future},
25};
26
27#[derive(Clone, Copy)]
28enum UserDataType {
29    Shared(TypeIdHints),
30    Unique(*mut c_void),
31}
32
33/// Handle to registry for userdata methods and metamethods.
34pub struct UserDataRegistry<T> {
35    lua: LuaGuard,
36    raw: RawUserDataRegistry,
37    r#type: UserDataType,
38    _phantom: PhantomData<T>,
39}
40
41pub(crate) struct RawUserDataRegistry {
42    // Fields
43    pub(crate) fields: Vec<(String, Result<Value>)>,
44    pub(crate) field_getters: Vec<(String, Callback)>,
45    pub(crate) field_setters: Vec<(String, Callback)>,
46    pub(crate) meta_fields: Vec<(String, Result<Value>)>,
47
48    // Methods
49    pub(crate) methods: Vec<(String, Callback)>,
50    #[cfg(feature = "async")]
51    pub(crate) async_methods: Vec<(String, AsyncCallback)>,
52    pub(crate) meta_methods: Vec<(String, Callback)>,
53    #[cfg(feature = "async")]
54    pub(crate) async_meta_methods: Vec<(String, AsyncCallback)>,
55
56    pub(crate) destructor: ffi::lua_CFunction,
57    pub(crate) type_id: Option<TypeId>,
58    pub(crate) type_name: StdString,
59}
60
61impl UserDataType {
62    #[inline]
63    pub(crate) fn type_id(&self) -> Option<TypeId> {
64        match self {
65            UserDataType::Shared(hints) => Some(hints.type_id()),
66            UserDataType::Unique(_) => None,
67        }
68    }
69}
70
71#[cfg(feature = "send")]
72unsafe impl Send for UserDataType {}
73
74impl<T: 'static> UserDataRegistry<T> {
75    #[inline(always)]
76    pub(crate) fn new(lua: &Lua) -> Self {
77        Self::with_type(lua, UserDataType::Shared(TypeIdHints::new::<T>()))
78    }
79}
80
81impl<T> UserDataRegistry<T> {
82    #[inline(always)]
83    pub(crate) fn new_unique(lua: &Lua, ud_ptr: *mut c_void) -> Self {
84        Self::with_type(lua, UserDataType::Unique(ud_ptr))
85    }
86
87    #[inline(always)]
88    fn with_type(lua: &Lua, r#type: UserDataType) -> Self {
89        let raw = RawUserDataRegistry {
90            fields: Vec::new(),
91            field_getters: Vec::new(),
92            field_setters: Vec::new(),
93            meta_fields: Vec::new(),
94            methods: Vec::new(),
95            #[cfg(feature = "async")]
96            async_methods: Vec::new(),
97            meta_methods: Vec::new(),
98            #[cfg(feature = "async")]
99            async_meta_methods: Vec::new(),
100            destructor: super::util::destroy_userdata_storage::<T>,
101            type_id: r#type.type_id(),
102            type_name: short_type_name::<T>(),
103        };
104
105        UserDataRegistry {
106            lua: lua.lock_arc(),
107            raw,
108            r#type,
109            _phantom: PhantomData,
110        }
111    }
112
113    fn box_method<M, A, R>(&self, name: &str, method: M) -> Callback
114    where
115        M: Fn(&Lua, &T, A) -> Result<R> + MaybeSend + 'static,
116        A: FromLuaMulti,
117        R: IntoLuaMulti,
118    {
119        let name = get_function_name::<T>(name);
120        macro_rules! try_self_arg {
121            ($res:expr) => {
122                $res.map_err(|err| Error::bad_self_argument(&name, err))?
123            };
124        }
125
126        let target_type = self.r#type;
127        Box::new(move |rawlua, nargs| unsafe {
128            if nargs == 0 {
129                let err = Error::from_lua_conversion("missing argument", "userdata", None);
130                try_self_arg!(Err(err));
131            }
132            let state = rawlua.state();
133            // Find absolute "self" index before processing args
134            let self_index = ffi::lua_absindex(state, -nargs);
135            // Self was at position 1, so we pass 2 here
136            let args = A::from_stack_args(nargs - 1, 2, Some(&name), rawlua);
137
138            match target_type {
139                #[rustfmt::skip]
140                UserDataType::Shared(type_hints) => {
141                    let type_id = try_self_arg!(rawlua.get_userdata_type_id::<T>(state, self_index));
142                    try_self_arg!(borrow_userdata_scoped(state, self_index, type_id, type_hints, |ud| {
143                        method(rawlua.lua(), ud, args?)?.push_into_stack_multi(rawlua)
144                    }))
145                }
146                UserDataType::Unique(target_ptr) if ffi::lua_touserdata(state, self_index) == target_ptr => {
147                    let ud = target_ptr as *mut UserDataStorage<T>;
148                    try_self_arg!((*ud).try_borrow_scoped(|ud| {
149                        method(rawlua.lua(), ud, args?)?.push_into_stack_multi(rawlua)
150                    }))
151                }
152                UserDataType::Unique(_) => {
153                    try_self_arg!(rawlua.get_userdata_type_id::<T>(state, self_index));
154                    Err(Error::bad_self_argument(&name, Error::UserDataTypeMismatch))
155                }
156            }
157        })
158    }
159
160    fn box_method_mut<M, A, R>(&self, name: &str, method: M) -> Callback
161    where
162        M: FnMut(&Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
163        A: FromLuaMulti,
164        R: IntoLuaMulti,
165    {
166        let name = get_function_name::<T>(name);
167        macro_rules! try_self_arg {
168            ($res:expr) => {
169                $res.map_err(|err| Error::bad_self_argument(&name, err))?
170            };
171        }
172
173        let method = RefCell::new(method);
174        let target_type = self.r#type;
175        Box::new(move |rawlua, nargs| unsafe {
176            let mut method = method.try_borrow_mut().map_err(|_| Error::RecursiveMutCallback)?;
177            if nargs == 0 {
178                let err = Error::from_lua_conversion("missing argument", "userdata", None);
179                try_self_arg!(Err(err));
180            }
181            let state = rawlua.state();
182            // Find absolute "self" index before processing args
183            let self_index = ffi::lua_absindex(state, -nargs);
184            // Self was at position 1, so we pass 2 here
185            let args = A::from_stack_args(nargs - 1, 2, Some(&name), rawlua);
186
187            match target_type {
188                #[rustfmt::skip]
189                UserDataType::Shared(type_hints) => {
190                    let type_id = try_self_arg!(rawlua.get_userdata_type_id::<T>(state, self_index));
191                    try_self_arg!(borrow_userdata_scoped_mut(state, self_index, type_id, type_hints, |ud| {
192                        method(rawlua.lua(), ud, args?)?.push_into_stack_multi(rawlua)
193                    }))
194                }
195                UserDataType::Unique(target_ptr) if ffi::lua_touserdata(state, self_index) == target_ptr => {
196                    let ud = target_ptr as *mut UserDataStorage<T>;
197                    try_self_arg!((*ud).try_borrow_scoped_mut(|ud| {
198                        method(rawlua.lua(), ud, args?)?.push_into_stack_multi(rawlua)
199                    }))
200                }
201                UserDataType::Unique(_) => {
202                    try_self_arg!(rawlua.get_userdata_type_id::<T>(state, self_index));
203                    Err(Error::bad_self_argument(&name, Error::UserDataTypeMismatch))
204                }
205            }
206        })
207    }
208
209    #[cfg(feature = "async")]
210    fn box_async_method<M, A, MR, R>(&self, name: &str, method: M) -> AsyncCallback
211    where
212        T: 'static,
213        M: Fn(Lua, UserDataRef<T>, A) -> MR + MaybeSend + 'static,
214        A: FromLuaMulti,
215        MR: Future<Output = Result<R>> + MaybeSend + 'static,
216        R: IntoLuaMulti,
217    {
218        let name = get_function_name::<T>(name);
219        macro_rules! try_self_arg {
220            ($res:expr) => {
221                match $res {
222                    Ok(res) => res,
223                    Err(err) => return Box::pin(future::ready(Err(Error::bad_self_argument(&name, err)))),
224                }
225            };
226        }
227
228        Box::new(move |rawlua, nargs| unsafe {
229            if nargs == 0 {
230                let err = Error::from_lua_conversion("missing argument", "userdata", None);
231                try_self_arg!(Err(err));
232            }
233            // Stack will be empty when polling the future, keep `self` on the ref thread
234            let self_ud = try_self_arg!(AnyUserData::from_stack(-nargs, rawlua));
235            let args = A::from_stack_args(nargs - 1, 2, Some(&name), rawlua);
236
237            let self_ud = try_self_arg!(self_ud.borrow());
238            let args = match args {
239                Ok(args) => args,
240                Err(e) => return Box::pin(future::ready(Err(e))),
241            };
242            let lua = rawlua.lua();
243            let fut = method(lua.clone(), self_ud, args);
244            // Lua is locked when the future is polled
245            Box::pin(async move { fut.await?.push_into_stack_multi(lua.raw_lua()) })
246        })
247    }
248
249    #[cfg(feature = "async")]
250    fn box_async_method_mut<M, A, MR, R>(&self, name: &str, method: M) -> AsyncCallback
251    where
252        T: 'static,
253        M: Fn(Lua, UserDataRefMut<T>, A) -> MR + MaybeSend + 'static,
254        A: FromLuaMulti,
255        MR: Future<Output = Result<R>> + MaybeSend + 'static,
256        R: IntoLuaMulti,
257    {
258        let name = get_function_name::<T>(name);
259        macro_rules! try_self_arg {
260            ($res:expr) => {
261                match $res {
262                    Ok(res) => res,
263                    Err(err) => return Box::pin(future::ready(Err(Error::bad_self_argument(&name, err)))),
264                }
265            };
266        }
267
268        Box::new(move |rawlua, nargs| unsafe {
269            if nargs == 0 {
270                let err = Error::from_lua_conversion("missing argument", "userdata", None);
271                try_self_arg!(Err(err));
272            }
273            // Stack will be empty when polling the future, keep `self` on the ref thread
274            let self_ud = try_self_arg!(AnyUserData::from_stack(-nargs, rawlua));
275            let args = A::from_stack_args(nargs - 1, 2, Some(&name), rawlua);
276
277            let self_ud = try_self_arg!(self_ud.borrow_mut());
278            let args = match args {
279                Ok(args) => args,
280                Err(e) => return Box::pin(future::ready(Err(e))),
281            };
282            let lua = rawlua.lua();
283            let fut = method(lua.clone(), self_ud, args);
284            // Lua is locked when the future is polled
285            Box::pin(async move { fut.await?.push_into_stack_multi(lua.raw_lua()) })
286        })
287    }
288
289    fn box_function<F, A, R>(&self, name: &str, function: F) -> Callback
290    where
291        F: Fn(&Lua, A) -> Result<R> + MaybeSend + 'static,
292        A: FromLuaMulti,
293        R: IntoLuaMulti,
294    {
295        let name = get_function_name::<T>(name);
296        Box::new(move |lua, nargs| unsafe {
297            let args = A::from_stack_args(nargs, 1, Some(&name), lua)?;
298            function(lua.lua(), args)?.push_into_stack_multi(lua)
299        })
300    }
301
302    fn box_function_mut<F, A, R>(&self, name: &str, function: F) -> Callback
303    where
304        F: FnMut(&Lua, A) -> Result<R> + MaybeSend + 'static,
305        A: FromLuaMulti,
306        R: IntoLuaMulti,
307    {
308        let name = get_function_name::<T>(name);
309        let function = RefCell::new(function);
310        Box::new(move |lua, nargs| unsafe {
311            let function = &mut *function
312                .try_borrow_mut()
313                .map_err(|_| Error::RecursiveMutCallback)?;
314            let args = A::from_stack_args(nargs, 1, Some(&name), lua)?;
315            function(lua.lua(), args)?.push_into_stack_multi(lua)
316        })
317    }
318
319    #[cfg(feature = "async")]
320    fn box_async_function<F, A, FR, R>(&self, name: &str, function: F) -> AsyncCallback
321    where
322        F: Fn(Lua, A) -> FR + MaybeSend + 'static,
323        A: FromLuaMulti,
324        FR: Future<Output = Result<R>> + MaybeSend + 'static,
325        R: IntoLuaMulti,
326    {
327        let name = get_function_name::<T>(name);
328        Box::new(move |rawlua, nargs| unsafe {
329            let args = match A::from_stack_args(nargs, 1, Some(&name), rawlua) {
330                Ok(args) => args,
331                Err(e) => return Box::pin(future::ready(Err(e))),
332            };
333            let lua = rawlua.lua();
334            let fut = function(lua.clone(), args);
335            Box::pin(async move { fut.await?.push_into_stack_multi(lua.raw_lua()) })
336        })
337    }
338
339    pub(crate) fn check_meta_field(lua: &Lua, name: &str, value: impl IntoLua) -> Result<Value> {
340        let value = value.into_lua(lua)?;
341        if name == MetaMethod::Index || name == MetaMethod::NewIndex {
342            match value {
343                Value::Nil | Value::Table(_) | Value::Function(_) => {}
344                _ => {
345                    return Err(Error::MetaMethodTypeError {
346                        method: name.to_string(),
347                        type_name: value.type_name(),
348                        message: Some("expected nil, table or function".to_string()),
349                    })
350                }
351            }
352        }
353        value.into_lua(lua)
354    }
355
356    #[inline(always)]
357    pub(crate) fn into_raw(self) -> RawUserDataRegistry {
358        self.raw
359    }
360}
361
362// Returns function name for the type `T`, without the module path
363fn get_function_name<T>(name: &str) -> StdString {
364    format!("{}.{name}", short_type_name::<T>())
365}
366
367impl<T> UserDataFields<T> for UserDataRegistry<T> {
368    fn add_field<V>(&mut self, name: impl Into<StdString>, value: V)
369    where
370        V: IntoLua + 'static,
371    {
372        let name = name.into();
373        self.raw.fields.push((name, value.into_lua(self.lua.lua())));
374    }
375
376    fn add_field_method_get<M, R>(&mut self, name: impl Into<StdString>, method: M)
377    where
378        M: Fn(&Lua, &T) -> Result<R> + MaybeSend + 'static,
379        R: IntoLua,
380    {
381        let name = name.into();
382        let callback = self.box_method(&name, move |lua, data, ()| method(lua, data));
383        self.raw.field_getters.push((name, callback));
384    }
385
386    fn add_field_method_set<M, A>(&mut self, name: impl Into<StdString>, method: M)
387    where
388        M: FnMut(&Lua, &mut T, A) -> Result<()> + MaybeSend + 'static,
389        A: FromLua,
390    {
391        let name = name.into();
392        let callback = self.box_method_mut(&name, method);
393        self.raw.field_setters.push((name, callback));
394    }
395
396    fn add_field_function_get<F, R>(&mut self, name: impl Into<StdString>, function: F)
397    where
398        F: Fn(&Lua, AnyUserData) -> Result<R> + MaybeSend + 'static,
399        R: IntoLua,
400    {
401        let name = name.into();
402        let callback = self.box_function(&name, function);
403        self.raw.field_getters.push((name, callback));
404    }
405
406    fn add_field_function_set<F, A>(&mut self, name: impl Into<StdString>, mut function: F)
407    where
408        F: FnMut(&Lua, AnyUserData, A) -> Result<()> + MaybeSend + 'static,
409        A: FromLua,
410    {
411        let name = name.into();
412        let callback = self.box_function_mut(&name, move |lua, (data, val)| function(lua, data, val));
413        self.raw.field_setters.push((name, callback));
414    }
415
416    fn add_meta_field<V>(&mut self, name: impl Into<StdString>, value: V)
417    where
418        V: IntoLua + 'static,
419    {
420        let lua = self.lua.lua();
421        let name = name.into();
422        let field = Self::check_meta_field(lua, &name, value).and_then(|v| v.into_lua(lua));
423        self.raw.meta_fields.push((name, field));
424    }
425
426    fn add_meta_field_with<F, R>(&mut self, name: impl Into<StdString>, f: F)
427    where
428        F: FnOnce(&Lua) -> Result<R> + 'static,
429        R: IntoLua,
430    {
431        let lua = self.lua.lua();
432        let name = name.into();
433        let field = f(lua).and_then(|v| Self::check_meta_field(lua, &name, v).and_then(|v| v.into_lua(lua)));
434        self.raw.meta_fields.push((name, field));
435    }
436}
437
438impl<T> UserDataMethods<T> for UserDataRegistry<T> {
439    fn add_method<M, A, R>(&mut self, name: impl Into<StdString>, method: M)
440    where
441        M: Fn(&Lua, &T, A) -> Result<R> + MaybeSend + 'static,
442        A: FromLuaMulti,
443        R: IntoLuaMulti,
444    {
445        let name = name.into();
446        let callback = self.box_method(&name, method);
447        self.raw.methods.push((name, callback));
448    }
449
450    fn add_method_mut<M, A, R>(&mut self, name: impl Into<StdString>, method: M)
451    where
452        M: FnMut(&Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
453        A: FromLuaMulti,
454        R: IntoLuaMulti,
455    {
456        let name = name.into();
457        let callback = self.box_method_mut(&name, method);
458        self.raw.methods.push((name, callback));
459    }
460
461    #[cfg(feature = "async")]
462    fn add_async_method<M, A, MR, R>(&mut self, name: impl Into<StdString>, method: M)
463    where
464        T: 'static,
465        M: Fn(Lua, UserDataRef<T>, A) -> MR + MaybeSend + 'static,
466        A: FromLuaMulti,
467        MR: Future<Output = Result<R>> + MaybeSend + 'static,
468        R: IntoLuaMulti,
469    {
470        let name = name.into();
471        let callback = self.box_async_method(&name, method);
472        self.raw.async_methods.push((name, callback));
473    }
474
475    #[cfg(feature = "async")]
476    fn add_async_method_mut<M, A, MR, R>(&mut self, name: impl Into<StdString>, method: M)
477    where
478        T: 'static,
479        M: Fn(Lua, UserDataRefMut<T>, A) -> MR + MaybeSend + 'static,
480        A: FromLuaMulti,
481        MR: Future<Output = Result<R>> + MaybeSend + 'static,
482        R: IntoLuaMulti,
483    {
484        let name = name.into();
485        let callback = self.box_async_method_mut(&name, method);
486        self.raw.async_methods.push((name, callback));
487    }
488
489    fn add_function<F, A, R>(&mut self, name: impl Into<StdString>, function: F)
490    where
491        F: Fn(&Lua, A) -> Result<R> + MaybeSend + 'static,
492        A: FromLuaMulti,
493        R: IntoLuaMulti,
494    {
495        let name = name.into();
496        let callback = self.box_function(&name, function);
497        self.raw.methods.push((name, callback));
498    }
499
500    fn add_function_mut<F, A, R>(&mut self, name: impl Into<StdString>, function: F)
501    where
502        F: FnMut(&Lua, A) -> Result<R> + MaybeSend + 'static,
503        A: FromLuaMulti,
504        R: IntoLuaMulti,
505    {
506        let name = name.into();
507        let callback = self.box_function_mut(&name, function);
508        self.raw.methods.push((name, callback));
509    }
510
511    #[cfg(feature = "async")]
512    fn add_async_function<F, A, FR, R>(&mut self, name: impl Into<StdString>, function: F)
513    where
514        F: Fn(Lua, A) -> FR + MaybeSend + 'static,
515        A: FromLuaMulti,
516        FR: Future<Output = Result<R>> + MaybeSend + 'static,
517        R: IntoLuaMulti,
518    {
519        let name = name.into();
520        let callback = self.box_async_function(&name, function);
521        self.raw.async_methods.push((name, callback));
522    }
523
524    fn add_meta_method<M, A, R>(&mut self, name: impl Into<StdString>, method: M)
525    where
526        M: Fn(&Lua, &T, A) -> Result<R> + MaybeSend + 'static,
527        A: FromLuaMulti,
528        R: IntoLuaMulti,
529    {
530        let name = name.into();
531        let callback = self.box_method(&name, method);
532        self.raw.meta_methods.push((name, callback));
533    }
534
535    fn add_meta_method_mut<M, A, R>(&mut self, name: impl Into<StdString>, method: M)
536    where
537        M: FnMut(&Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
538        A: FromLuaMulti,
539        R: IntoLuaMulti,
540    {
541        let name = name.into();
542        let callback = self.box_method_mut(&name, method);
543        self.raw.meta_methods.push((name, callback));
544    }
545
546    #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
547    fn add_async_meta_method<M, A, MR, R>(&mut self, name: impl Into<StdString>, method: M)
548    where
549        T: 'static,
550        M: Fn(Lua, UserDataRef<T>, A) -> MR + MaybeSend + 'static,
551        A: FromLuaMulti,
552        MR: Future<Output = Result<R>> + MaybeSend + 'static,
553        R: IntoLuaMulti,
554    {
555        let name = name.into();
556        let callback = self.box_async_method(&name, method);
557        self.raw.async_meta_methods.push((name, callback));
558    }
559
560    #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
561    fn add_async_meta_method_mut<M, A, MR, R>(&mut self, name: impl Into<StdString>, method: M)
562    where
563        T: 'static,
564        M: Fn(Lua, UserDataRefMut<T>, A) -> MR + MaybeSend + 'static,
565        A: FromLuaMulti,
566        MR: Future<Output = Result<R>> + MaybeSend + 'static,
567        R: IntoLuaMulti,
568    {
569        let name = name.into();
570        let callback = self.box_async_method_mut(&name, method);
571        self.raw.async_meta_methods.push((name, callback));
572    }
573
574    fn add_meta_function<F, A, R>(&mut self, name: impl Into<StdString>, function: F)
575    where
576        F: Fn(&Lua, A) -> Result<R> + MaybeSend + 'static,
577        A: FromLuaMulti,
578        R: IntoLuaMulti,
579    {
580        let name = name.into();
581        let callback = self.box_function(&name, function);
582        self.raw.meta_methods.push((name, callback));
583    }
584
585    fn add_meta_function_mut<F, A, R>(&mut self, name: impl Into<StdString>, function: F)
586    where
587        F: FnMut(&Lua, A) -> Result<R> + MaybeSend + 'static,
588        A: FromLuaMulti,
589        R: IntoLuaMulti,
590    {
591        let name = name.into();
592        let callback = self.box_function_mut(&name, function);
593        self.raw.meta_methods.push((name, callback));
594    }
595
596    #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
597    fn add_async_meta_function<F, A, FR, R>(&mut self, name: impl Into<StdString>, function: F)
598    where
599        F: Fn(Lua, A) -> FR + MaybeSend + 'static,
600        A: FromLuaMulti,
601        FR: Future<Output = Result<R>> + MaybeSend + 'static,
602        R: IntoLuaMulti,
603    {
604        let name = name.into();
605        let callback = self.box_async_function(&name, function);
606        self.raw.async_meta_methods.push((name, callback));
607    }
608}
609
610macro_rules! lua_userdata_impl {
611    ($type:ty) => {
612        impl<T: UserData + 'static> UserData for $type {
613            fn register(registry: &mut UserDataRegistry<Self>) {
614                let mut orig_registry = UserDataRegistry::new(registry.lua.lua());
615                T::register(&mut orig_registry);
616
617                // Copy all fields, methods, etc. from the original registry
618                (registry.raw.fields).extend(orig_registry.raw.fields);
619                (registry.raw.field_getters).extend(orig_registry.raw.field_getters);
620                (registry.raw.field_setters).extend(orig_registry.raw.field_setters);
621                (registry.raw.meta_fields).extend(orig_registry.raw.meta_fields);
622                (registry.raw.methods).extend(orig_registry.raw.methods);
623                #[cfg(feature = "async")]
624                (registry.raw.async_methods).extend(orig_registry.raw.async_methods);
625                (registry.raw.meta_methods).extend(orig_registry.raw.meta_methods);
626                #[cfg(feature = "async")]
627                (registry.raw.async_meta_methods).extend(orig_registry.raw.async_meta_methods);
628            }
629        }
630    };
631}
632
633// A special proxy object for UserData
634pub(crate) struct UserDataProxy<T>(pub(crate) PhantomData<T>);
635
636lua_userdata_impl!(UserDataProxy<T>);
637
638#[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]
639lua_userdata_impl!(std::rc::Rc<T>);
640#[cfg(all(feature = "userdata-wrappers", not(feature = "send")))]
641lua_userdata_impl!(std::rc::Rc<std::cell::RefCell<T>>);
642#[cfg(feature = "userdata-wrappers")]
643lua_userdata_impl!(std::sync::Arc<T>);
644#[cfg(feature = "userdata-wrappers")]
645lua_userdata_impl!(std::sync::Arc<std::sync::Mutex<T>>);
646#[cfg(feature = "userdata-wrappers")]
647lua_userdata_impl!(std::sync::Arc<std::sync::RwLock<T>>);
648#[cfg(feature = "userdata-wrappers")]
649lua_userdata_impl!(std::sync::Arc<parking_lot::Mutex<T>>);
650#[cfg(feature = "userdata-wrappers")]
651lua_userdata_impl!(std::sync::Arc<parking_lot::RwLock<T>>);
652
653#[cfg(test)]
654mod assertions {
655    #[cfg(feature = "send")]
656    static_assertions::assert_impl_all!(super::RawUserDataRegistry: Send);
657}