Skip to main content

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