mlua/
userdata_impl.rs

1#![allow(clippy::await_holding_refcell_ref, clippy::await_holding_lock)]
2
3use std::any::TypeId;
4use std::cell::{Ref, RefCell, RefMut};
5use std::marker::PhantomData;
6use std::os::raw::c_int;
7use std::string::String as StdString;
8use std::sync::{Arc, Mutex, RwLock};
9
10use crate::error::{Error, Result};
11use crate::lua::Lua;
12use crate::types::{Callback, MaybeSend};
13use crate::userdata::{
14    AnyUserData, MetaMethod, UserData, UserDataCell, UserDataFields, UserDataMethods,
15};
16use crate::util::{get_userdata, short_type_name};
17use crate::value::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, Value};
18
19#[cfg(not(feature = "send"))]
20use std::rc::Rc;
21
22#[cfg(feature = "async")]
23use {crate::types::AsyncCallback, futures_util::future, std::future::Future};
24
25/// Handle to registry for userdata methods and metamethods.
26pub struct UserDataRegistry<'lua, T: 'static> {
27    // Fields
28    pub(crate) fields: Vec<(String, Callback<'lua, 'static>)>,
29    pub(crate) field_getters: Vec<(String, Callback<'lua, 'static>)>,
30    pub(crate) field_setters: Vec<(String, Callback<'lua, 'static>)>,
31    pub(crate) meta_fields: Vec<(String, Callback<'lua, 'static>)>,
32
33    // Methods
34    pub(crate) methods: Vec<(String, Callback<'lua, 'static>)>,
35    #[cfg(feature = "async")]
36    pub(crate) async_methods: Vec<(String, AsyncCallback<'lua, 'static>)>,
37    pub(crate) meta_methods: Vec<(String, Callback<'lua, 'static>)>,
38    #[cfg(feature = "async")]
39    pub(crate) async_meta_methods: Vec<(String, AsyncCallback<'lua, 'static>)>,
40
41    _type: PhantomData<T>,
42}
43
44impl<'lua, T: 'static> UserDataRegistry<'lua, T> {
45    pub(crate) const fn new() -> Self {
46        UserDataRegistry {
47            fields: Vec::new(),
48            field_getters: Vec::new(),
49            field_setters: Vec::new(),
50            meta_fields: Vec::new(),
51            methods: Vec::new(),
52            #[cfg(feature = "async")]
53            async_methods: Vec::new(),
54            meta_methods: Vec::new(),
55            #[cfg(feature = "async")]
56            async_meta_methods: Vec::new(),
57            _type: PhantomData,
58        }
59    }
60
61    fn box_method<M, A, R>(name: &str, method: M) -> Callback<'lua, 'static>
62    where
63        M: Fn(&'lua Lua, &T, A) -> Result<R> + MaybeSend + 'static,
64        A: FromLuaMulti<'lua>,
65        R: IntoLuaMulti<'lua>,
66    {
67        let name = get_function_name::<T>(name);
68        macro_rules! try_self_arg {
69            ($res:expr) => {
70                $res.map_err(|err| Error::bad_self_argument(&name, err))?
71            };
72            ($res:expr, $err:expr) => {
73                $res.map_err(|_| Error::bad_self_argument(&name, $err))?
74            };
75        }
76
77        Box::new(move |lua, nargs| unsafe {
78            if nargs == 0 {
79                let err = Error::from_lua_conversion("missing argument", "userdata", None);
80                try_self_arg!(Err(err));
81            }
82            let state = lua.state();
83            // Find absolute "self" index before processing args
84            let index = ffi::lua_absindex(state, -nargs);
85            // Self was at position 1, so we pass 2 here
86            let args = A::from_stack_args(nargs - 1, 2, Some(&name), lua);
87
88            match try_self_arg!(lua.get_userdata_type_id(index)) {
89                Some(id) if id == TypeId::of::<T>() => {
90                    let ud = try_self_arg!(get_userdata_ref::<T>(state, index));
91                    method(lua, &ud, args?)?.push_into_stack_multi(lua)
92                }
93                #[cfg(not(feature = "send"))]
94                Some(id) if id == TypeId::of::<Rc<T>>() => {
95                    let ud = try_self_arg!(get_userdata_ref::<Rc<T>>(state, index));
96                    method(lua, &ud, args?)?.push_into_stack_multi(lua)
97                }
98                #[cfg(not(feature = "send"))]
99                Some(id) if id == TypeId::of::<Rc<RefCell<T>>>() => {
100                    let ud = try_self_arg!(get_userdata_ref::<Rc<RefCell<T>>>(state, index));
101                    let ud = try_self_arg!(ud.try_borrow(), Error::UserDataBorrowError);
102                    method(lua, &ud, args?)?.push_into_stack_multi(lua)
103                }
104                Some(id) if id == TypeId::of::<Arc<T>>() => {
105                    let ud = try_self_arg!(get_userdata_ref::<Arc<T>>(state, index));
106                    method(lua, &ud, args?)?.push_into_stack_multi(lua)
107                }
108                Some(id) if id == TypeId::of::<Arc<Mutex<T>>>() => {
109                    let ud = try_self_arg!(get_userdata_ref::<Arc<Mutex<T>>>(state, index));
110                    let ud = try_self_arg!(ud.try_lock(), Error::UserDataBorrowError);
111                    method(lua, &ud, args?)?.push_into_stack_multi(lua)
112                }
113                #[cfg(feature = "parking_lot")]
114                Some(id) if id == TypeId::of::<Arc<parking_lot::Mutex<T>>>() => {
115                    let ud = get_userdata_ref::<Arc<parking_lot::Mutex<T>>>(state, index);
116                    let ud = try_self_arg!(ud);
117                    let ud = try_self_arg!(ud.try_lock().ok_or(Error::UserDataBorrowError));
118                    method(lua, &ud, args?)?.push_into_stack_multi(lua)
119                }
120                Some(id) if id == TypeId::of::<Arc<RwLock<T>>>() => {
121                    let ud = try_self_arg!(get_userdata_ref::<Arc<RwLock<T>>>(state, index));
122                    let ud = try_self_arg!(ud.try_read(), Error::UserDataBorrowError);
123                    method(lua, &ud, args?)?.push_into_stack_multi(lua)
124                }
125                #[cfg(feature = "parking_lot")]
126                Some(id) if id == TypeId::of::<Arc<parking_lot::RwLock<T>>>() => {
127                    let ud = get_userdata_ref::<Arc<parking_lot::RwLock<T>>>(state, index);
128                    let ud = try_self_arg!(ud);
129                    let ud = try_self_arg!(ud.try_read().ok_or(Error::UserDataBorrowError));
130                    method(lua, &ud, args?)?.push_into_stack_multi(lua)
131                }
132                _ => Err(Error::bad_self_argument(&name, Error::UserDataTypeMismatch)),
133            }
134        })
135    }
136
137    fn box_method_mut<M, A, R>(name: &str, method: M) -> Callback<'lua, 'static>
138    where
139        M: FnMut(&'lua Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
140        A: FromLuaMulti<'lua>,
141        R: IntoLuaMulti<'lua>,
142    {
143        let name = get_function_name::<T>(name);
144        macro_rules! try_self_arg {
145            ($res:expr) => {
146                $res.map_err(|err| Error::bad_self_argument(&name, err))?
147            };
148            ($res:expr, $err:expr) => {
149                $res.map_err(|_| Error::bad_self_argument(&name, $err))?
150            };
151        }
152
153        let method = RefCell::new(method);
154        Box::new(move |lua, nargs| unsafe {
155            let mut method = method
156                .try_borrow_mut()
157                .map_err(|_| Error::RecursiveMutCallback)?;
158            if nargs == 0 {
159                let err = Error::from_lua_conversion("missing argument", "userdata", None);
160                try_self_arg!(Err(err));
161            }
162            let state = lua.state();
163            // Find absolute "self" index before processing args
164            let index = ffi::lua_absindex(state, -nargs);
165            // Self was at position 1, so we pass 2 here
166            let args = A::from_stack_args(nargs - 1, 2, Some(&name), lua);
167
168            match try_self_arg!(lua.get_userdata_type_id(index)) {
169                Some(id) if id == TypeId::of::<T>() => {
170                    let mut ud = try_self_arg!(get_userdata_mut::<T>(state, index));
171                    method(lua, &mut ud, args?)?.push_into_stack_multi(lua)
172                }
173                #[cfg(not(feature = "send"))]
174                Some(id) if id == TypeId::of::<Rc<T>>() => Err(Error::UserDataBorrowMutError),
175                #[cfg(not(feature = "send"))]
176                Some(id) if id == TypeId::of::<Rc<RefCell<T>>>() => {
177                    let ud = try_self_arg!(get_userdata_mut::<Rc<RefCell<T>>>(state, index));
178                    let mut ud = try_self_arg!(ud.try_borrow_mut(), Error::UserDataBorrowMutError);
179                    method(lua, &mut ud, args?)?.push_into_stack_multi(lua)
180                }
181                Some(id) if id == TypeId::of::<Arc<T>>() => Err(Error::UserDataBorrowMutError),
182                Some(id) if id == TypeId::of::<Arc<Mutex<T>>>() => {
183                    let ud = try_self_arg!(get_userdata_mut::<Arc<Mutex<T>>>(state, index));
184                    let mut ud = try_self_arg!(ud.try_lock(), Error::UserDataBorrowMutError);
185                    method(lua, &mut ud, args?)?.push_into_stack_multi(lua)
186                }
187                #[cfg(feature = "parking_lot")]
188                Some(id) if id == TypeId::of::<Arc<parking_lot::Mutex<T>>>() => {
189                    let ud = get_userdata_mut::<Arc<parking_lot::Mutex<T>>>(state, index);
190                    let ud = try_self_arg!(ud);
191                    let mut ud = try_self_arg!(ud.try_lock().ok_or(Error::UserDataBorrowMutError));
192                    method(lua, &mut ud, args?)?.push_into_stack_multi(lua)
193                }
194                Some(id) if id == TypeId::of::<Arc<RwLock<T>>>() => {
195                    let ud = try_self_arg!(get_userdata_mut::<Arc<RwLock<T>>>(state, index));
196                    let mut ud = try_self_arg!(ud.try_write(), Error::UserDataBorrowMutError);
197                    method(lua, &mut ud, args?)?.push_into_stack_multi(lua)
198                }
199                #[cfg(feature = "parking_lot")]
200                Some(id) if id == TypeId::of::<Arc<parking_lot::RwLock<T>>>() => {
201                    let ud = get_userdata_mut::<Arc<parking_lot::RwLock<T>>>(state, index);
202                    let ud = try_self_arg!(ud);
203                    let mut ud = try_self_arg!(ud.try_write().ok_or(Error::UserDataBorrowMutError));
204                    method(lua, &mut ud, args?)?.push_into_stack_multi(lua)
205                }
206                _ => Err(Error::bad_self_argument(&name, Error::UserDataTypeMismatch)),
207            }
208        })
209    }
210
211    #[cfg(feature = "async")]
212    fn box_async_method<'s, M, A, MR, R>(name: &str, method: M) -> AsyncCallback<'lua, 'static>
213    where
214        'lua: 's,
215        T: 'static,
216        M: Fn(&'lua Lua, &'s T, A) -> MR + MaybeSend + 'static,
217        A: FromLuaMulti<'lua>,
218        MR: Future<Output = Result<R>> + 's,
219        R: IntoLuaMulti<'lua>,
220    {
221        let name = Arc::new(get_function_name::<T>(name));
222        let method = Arc::new(method);
223
224        Box::new(move |lua, mut args| unsafe {
225            let name = name.clone();
226            let method = method.clone();
227            macro_rules! try_self_arg {
228                ($res:expr) => {
229                    $res.map_err(|err| Error::bad_self_argument(&name, err))?
230                };
231                ($res:expr, $err:expr) => {
232                    $res.map_err(|_| Error::bad_self_argument(&name, $err))?
233                };
234            }
235
236            Box::pin(async move {
237                let this = args.pop_front().ok_or_else(|| {
238                    Error::from_lua_conversion("missing argument", "userdata", None)
239                });
240                let this = try_self_arg!(AnyUserData::from_lua(try_self_arg!(this), lua));
241                let args = A::from_lua_args(args, 2, Some(&name), lua);
242
243                let (ref_thread, index) = (lua.ref_thread(), this.0.index);
244                match try_self_arg!(this.type_id()) {
245                    Some(id) if id == TypeId::of::<T>() => {
246                        let ud = try_self_arg!(get_userdata_ref::<T>(ref_thread, index));
247                        let ud = std::mem::transmute::<&T, &T>(&ud);
248                        method(lua, ud, args?).await?.push_into_stack_multi(lua)
249                    }
250                    #[cfg(not(feature = "send"))]
251                    Some(id) if id == TypeId::of::<Rc<T>>() => {
252                        let ud = try_self_arg!(get_userdata_ref::<Rc<T>>(ref_thread, index));
253                        let ud = std::mem::transmute::<&T, &T>(&ud);
254                        method(lua, ud, args?).await?.push_into_stack_multi(lua)
255                    }
256                    #[cfg(not(feature = "send"))]
257                    Some(id) if id == TypeId::of::<Rc<RefCell<T>>>() => {
258                        let ud =
259                            try_self_arg!(get_userdata_ref::<Rc<RefCell<T>>>(ref_thread, index));
260                        let ud = try_self_arg!(ud.try_borrow(), Error::UserDataBorrowError);
261                        let ud = std::mem::transmute::<&T, &T>(&ud);
262                        method(lua, ud, args?).await?.push_into_stack_multi(lua)
263                    }
264                    Some(id) if id == TypeId::of::<Arc<T>>() => {
265                        let ud = try_self_arg!(get_userdata_ref::<Arc<T>>(ref_thread, index));
266                        let ud = std::mem::transmute::<&T, &T>(&ud);
267                        method(lua, ud, args?).await?.push_into_stack_multi(lua)
268                    }
269                    Some(id) if id == TypeId::of::<Arc<Mutex<T>>>() => {
270                        let ud =
271                            try_self_arg!(get_userdata_ref::<Arc<Mutex<T>>>(ref_thread, index));
272                        let ud = try_self_arg!(ud.try_lock(), Error::UserDataBorrowError);
273                        let ud = std::mem::transmute::<&T, &T>(&ud);
274                        method(lua, ud, args?).await?.push_into_stack_multi(lua)
275                    }
276                    #[cfg(feature = "parking_lot")]
277                    Some(id) if id == TypeId::of::<Arc<parking_lot::Mutex<T>>>() => {
278                        let ud = get_userdata_ref::<Arc<parking_lot::Mutex<T>>>(ref_thread, index);
279                        let ud = try_self_arg!(ud);
280                        let ud = try_self_arg!(ud.try_lock().ok_or(Error::UserDataBorrowError));
281                        let ud = std::mem::transmute::<&T, &T>(&ud);
282                        method(lua, ud, args?).await?.push_into_stack_multi(lua)
283                    }
284                    Some(id) if id == TypeId::of::<Arc<RwLock<T>>>() => {
285                        let ud =
286                            try_self_arg!(get_userdata_ref::<Arc<RwLock<T>>>(ref_thread, index));
287                        let ud = try_self_arg!(ud.try_read(), Error::UserDataBorrowError);
288                        let ud = std::mem::transmute::<&T, &T>(&ud);
289                        method(lua, ud, args?).await?.push_into_stack_multi(lua)
290                    }
291                    #[cfg(feature = "parking_lot")]
292                    Some(id) if id == TypeId::of::<Arc<parking_lot::RwLock<T>>>() => {
293                        let ud = get_userdata_ref::<Arc<parking_lot::RwLock<T>>>(ref_thread, index);
294                        let ud = try_self_arg!(ud);
295                        let ud = try_self_arg!(ud.try_read().ok_or(Error::UserDataBorrowError));
296                        let ud = std::mem::transmute::<&T, &T>(&ud);
297                        method(lua, ud, args?).await?.push_into_stack_multi(lua)
298                    }
299                    _ => Err(Error::bad_self_argument(&name, Error::UserDataTypeMismatch)),
300                }
301            })
302        })
303    }
304
305    #[cfg(feature = "async")]
306    fn box_async_method_mut<'s, M, A, MR, R>(name: &str, method: M) -> AsyncCallback<'lua, 'static>
307    where
308        'lua: 's,
309        T: 'static,
310        M: Fn(&'lua Lua, &'s mut T, A) -> MR + MaybeSend + 'static,
311        A: FromLuaMulti<'lua>,
312        MR: Future<Output = Result<R>> + 's,
313        R: IntoLuaMulti<'lua>,
314    {
315        let name = Arc::new(get_function_name::<T>(name));
316        let method = Arc::new(method);
317
318        Box::new(move |lua, mut args| unsafe {
319            let name = name.clone();
320            let method = method.clone();
321            macro_rules! try_self_arg {
322                ($res:expr) => {
323                    $res.map_err(|err| Error::bad_self_argument(&name, err))?
324                };
325                ($res:expr, $err:expr) => {
326                    $res.map_err(|_| Error::bad_self_argument(&name, $err))?
327                };
328            }
329
330            Box::pin(async move {
331                let this = args.pop_front().ok_or_else(|| {
332                    Error::from_lua_conversion("missing argument", "userdata", None)
333                });
334                let this = try_self_arg!(AnyUserData::from_lua(try_self_arg!(this), lua));
335                let args = A::from_lua_args(args, 2, Some(&name), lua);
336
337                let (ref_thread, index) = (lua.ref_thread(), this.0.index);
338                match try_self_arg!(this.type_id()) {
339                    Some(id) if id == TypeId::of::<T>() => {
340                        let mut ud = try_self_arg!(get_userdata_mut::<T>(ref_thread, index));
341                        let ud = std::mem::transmute::<&mut T, &mut T>(&mut ud);
342                        method(lua, ud, args?).await?.push_into_stack_multi(lua)
343                    }
344                    #[cfg(not(feature = "send"))]
345                    Some(id) if id == TypeId::of::<Rc<RefCell<T>>>() => {
346                        Err(Error::UserDataBorrowMutError)
347                    }
348                    #[cfg(not(feature = "send"))]
349                    Some(id) if id == TypeId::of::<Rc<RefCell<T>>>() => {
350                        let ud =
351                            try_self_arg!(get_userdata_mut::<Rc<RefCell<T>>>(ref_thread, index));
352                        let mut ud =
353                            try_self_arg!(ud.try_borrow_mut(), Error::UserDataBorrowMutError);
354                        let ud = std::mem::transmute::<&mut T, &mut T>(&mut ud);
355                        method(lua, ud, args?).await?.push_into_stack_multi(lua)
356                    }
357                    #[cfg(not(feature = "send"))]
358                    Some(id) if id == TypeId::of::<Arc<T>>() => Err(Error::UserDataBorrowMutError),
359                    Some(id) if id == TypeId::of::<Arc<Mutex<T>>>() => {
360                        let ud =
361                            try_self_arg!(get_userdata_mut::<Arc<Mutex<T>>>(ref_thread, index));
362                        let mut ud = try_self_arg!(ud.try_lock(), Error::UserDataBorrowMutError);
363                        let ud = std::mem::transmute::<&mut T, &mut T>(&mut ud);
364                        method(lua, ud, args?).await?.push_into_stack_multi(lua)
365                    }
366                    #[cfg(feature = "parking_lot")]
367                    Some(id) if id == TypeId::of::<Arc<parking_lot::Mutex<T>>>() => {
368                        let ud = get_userdata_mut::<Arc<parking_lot::Mutex<T>>>(ref_thread, index);
369                        let ud = try_self_arg!(ud);
370                        let mut ud =
371                            try_self_arg!(ud.try_lock().ok_or(Error::UserDataBorrowMutError));
372                        let ud = std::mem::transmute::<&mut T, &mut T>(&mut ud);
373                        method(lua, ud, args?).await?.push_into_stack_multi(lua)
374                    }
375                    Some(id) if id == TypeId::of::<Arc<RwLock<T>>>() => {
376                        let ud =
377                            try_self_arg!(get_userdata_mut::<Arc<RwLock<T>>>(ref_thread, index));
378                        let mut ud = try_self_arg!(ud.try_write(), Error::UserDataBorrowMutError);
379                        let ud = std::mem::transmute::<&mut T, &mut T>(&mut ud);
380                        method(lua, ud, args?).await?.push_into_stack_multi(lua)
381                    }
382                    #[cfg(feature = "parking_lot")]
383                    Some(id) if id == TypeId::of::<Arc<parking_lot::RwLock<T>>>() => {
384                        let ud = get_userdata_mut::<Arc<parking_lot::RwLock<T>>>(ref_thread, index);
385                        let ud = try_self_arg!(ud);
386                        let mut ud =
387                            try_self_arg!(ud.try_write().ok_or(Error::UserDataBorrowMutError));
388                        let ud = std::mem::transmute::<&mut T, &mut T>(&mut ud);
389                        method(lua, ud, args?).await?.push_into_stack_multi(lua)
390                    }
391                    _ => Err(Error::bad_self_argument(&name, Error::UserDataTypeMismatch)),
392                }
393            })
394        })
395    }
396
397    fn box_function<F, A, R>(name: &str, function: F) -> Callback<'lua, 'static>
398    where
399        F: Fn(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
400        A: FromLuaMulti<'lua>,
401        R: IntoLuaMulti<'lua>,
402    {
403        let name = get_function_name::<T>(name);
404        Box::new(move |lua, nargs| unsafe {
405            let args = A::from_stack_args(nargs, 1, Some(&name), lua)?;
406            function(lua, args)?.push_into_stack_multi(lua)
407        })
408    }
409
410    fn box_function_mut<F, A, R>(name: &str, function: F) -> Callback<'lua, 'static>
411    where
412        F: FnMut(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
413        A: FromLuaMulti<'lua>,
414        R: IntoLuaMulti<'lua>,
415    {
416        let name = get_function_name::<T>(name);
417        let function = RefCell::new(function);
418        Box::new(move |lua, nargs| unsafe {
419            let function = &mut *function
420                .try_borrow_mut()
421                .map_err(|_| Error::RecursiveMutCallback)?;
422            let args = A::from_stack_args(nargs, 1, Some(&name), lua)?;
423            function(lua, args)?.push_into_stack_multi(lua)
424        })
425    }
426
427    #[cfg(feature = "async")]
428    fn box_async_function<F, A, FR, R>(name: &str, function: F) -> AsyncCallback<'lua, 'static>
429    where
430        F: Fn(&'lua Lua, A) -> FR + MaybeSend + 'static,
431        A: FromLuaMulti<'lua>,
432        FR: Future<Output = Result<R>> + 'lua,
433        R: IntoLuaMulti<'lua>,
434    {
435        let name = get_function_name::<T>(name);
436        Box::new(move |lua, args| unsafe {
437            let args = match A::from_lua_args(args, 1, Some(&name), lua) {
438                Ok(args) => args,
439                Err(e) => return Box::pin(future::err(e)),
440            };
441            let fut = function(lua, args);
442            Box::pin(async move { fut.await?.push_into_stack_multi(lua) })
443        })
444    }
445
446    pub(crate) fn check_meta_field<V>(lua: &'lua Lua, name: &str, value: V) -> Result<Value<'lua>>
447    where
448        V: IntoLua<'lua>,
449    {
450        let value = value.into_lua(lua)?;
451        if name == MetaMethod::Index || name == MetaMethod::NewIndex {
452            match value {
453                Value::Nil | Value::Table(_) | Value::Function(_) => {}
454                _ => {
455                    return Err(Error::MetaMethodTypeError {
456                        method: name.to_string(),
457                        type_name: value.type_name(),
458                        message: Some("expected nil, table or function".to_string()),
459                    })
460                }
461            }
462        }
463        value.into_lua(lua)
464    }
465}
466
467// Returns function name for the type `T`, without the module path
468fn get_function_name<T>(name: &str) -> StdString {
469    format!("{}.{name}", short_type_name::<T>())
470}
471
472impl<'lua, T: 'static> UserDataFields<'lua, T> for UserDataRegistry<'lua, T> {
473    fn add_field<V>(&mut self, name: impl AsRef<str>, value: V)
474    where
475        V: IntoLua<'lua> + Clone + 'static,
476    {
477        let name = name.as_ref().to_string();
478        self.fields.push((
479            name,
480            Box::new(move |lua, _| unsafe { value.clone().push_into_stack_multi(lua) }),
481        ));
482    }
483
484    fn add_field_method_get<M, R>(&mut self, name: impl AsRef<str>, method: M)
485    where
486        M: Fn(&'lua Lua, &T) -> Result<R> + MaybeSend + 'static,
487        R: IntoLua<'lua>,
488    {
489        let name = name.as_ref();
490        let method = Self::box_method(name, move |lua, data, ()| method(lua, data));
491        self.field_getters.push((name.into(), method));
492    }
493
494    fn add_field_method_set<M, A>(&mut self, name: impl AsRef<str>, method: M)
495    where
496        M: FnMut(&'lua Lua, &mut T, A) -> Result<()> + MaybeSend + 'static,
497        A: FromLua<'lua>,
498    {
499        let name = name.as_ref();
500        let method = Self::box_method_mut(name, method);
501        self.field_setters.push((name.into(), method));
502    }
503
504    fn add_field_function_get<F, R>(&mut self, name: impl AsRef<str>, function: F)
505    where
506        F: Fn(&'lua Lua, AnyUserData<'lua>) -> Result<R> + MaybeSend + 'static,
507        R: IntoLua<'lua>,
508    {
509        let name = name.as_ref();
510        let func = Self::box_function(name, function);
511        self.field_getters.push((name.into(), func));
512    }
513
514    fn add_field_function_set<F, A>(&mut self, name: impl AsRef<str>, mut function: F)
515    where
516        F: FnMut(&'lua Lua, AnyUserData<'lua>, A) -> Result<()> + MaybeSend + 'static,
517        A: FromLua<'lua>,
518    {
519        let name = name.as_ref();
520        let func = Self::box_function_mut(name, move |lua, (data, val)| function(lua, data, val));
521        self.field_setters.push((name.into(), func));
522    }
523
524    fn add_meta_field<V>(&mut self, name: impl AsRef<str>, value: V)
525    where
526        V: IntoLua<'lua> + Clone + 'static,
527    {
528        let name = name.as_ref().to_string();
529        let name2 = name.clone();
530        self.meta_fields.push((
531            name,
532            Box::new(move |lua, _| unsafe {
533                Self::check_meta_field(lua, &name2, value.clone())?.push_into_stack_multi(lua)
534            }),
535        ));
536    }
537
538    fn add_meta_field_with<F, R>(&mut self, name: impl AsRef<str>, f: F)
539    where
540        F: Fn(&'lua Lua) -> Result<R> + MaybeSend + 'static,
541        R: IntoLua<'lua>,
542    {
543        let name = name.as_ref().to_string();
544        let name2 = name.clone();
545        self.meta_fields.push((
546            name,
547            Box::new(move |lua, _| unsafe {
548                Self::check_meta_field(lua, &name2, f(lua)?)?.push_into_stack_multi(lua)
549            }),
550        ));
551    }
552
553    // Below are internal methods
554
555    fn append_fields_from<S>(&mut self, other: UserDataRegistry<'lua, S>) {
556        self.fields.extend(other.fields);
557        self.field_getters.extend(other.field_getters);
558        self.field_setters.extend(other.field_setters);
559        self.meta_fields.extend(other.meta_fields);
560    }
561}
562
563impl<'lua, T: 'static> UserDataMethods<'lua, T> for UserDataRegistry<'lua, T> {
564    fn add_method<M, A, R>(&mut self, name: impl AsRef<str>, method: M)
565    where
566        M: Fn(&'lua Lua, &T, A) -> Result<R> + MaybeSend + 'static,
567        A: FromLuaMulti<'lua>,
568        R: IntoLuaMulti<'lua>,
569    {
570        let name = name.as_ref();
571        self.methods
572            .push((name.into(), Self::box_method(name, method)));
573    }
574
575    fn add_method_mut<M, A, R>(&mut self, name: impl AsRef<str>, method: M)
576    where
577        M: FnMut(&'lua Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
578        A: FromLuaMulti<'lua>,
579        R: IntoLuaMulti<'lua>,
580    {
581        let name = name.as_ref();
582        self.methods
583            .push((name.into(), Self::box_method_mut(name, method)));
584    }
585
586    #[cfg(feature = "async")]
587    fn add_async_method<'s, M, A, MR, R>(&mut self, name: impl AsRef<str>, method: M)
588    where
589        'lua: 's,
590        T: 'static,
591        M: Fn(&'lua Lua, &'s T, A) -> MR + MaybeSend + 'static,
592        A: FromLuaMulti<'lua>,
593        MR: Future<Output = Result<R>> + 's,
594        R: IntoLuaMulti<'lua>,
595    {
596        let name = name.as_ref();
597        self.async_methods
598            .push((name.into(), Self::box_async_method(name, method)));
599    }
600
601    #[cfg(feature = "async")]
602    fn add_async_method_mut<'s, M, A, MR, R>(&mut self, name: impl AsRef<str>, method: M)
603    where
604        'lua: 's,
605        T: 'static,
606        M: Fn(&'lua Lua, &'s mut T, A) -> MR + MaybeSend + 'static,
607        A: FromLuaMulti<'lua>,
608        MR: Future<Output = Result<R>> + 's,
609        R: IntoLuaMulti<'lua>,
610    {
611        let name = name.as_ref();
612        self.async_methods
613            .push((name.into(), Self::box_async_method_mut(name, method)));
614    }
615
616    fn add_function<F, A, R>(&mut self, name: impl AsRef<str>, function: F)
617    where
618        F: Fn(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
619        A: FromLuaMulti<'lua>,
620        R: IntoLuaMulti<'lua>,
621    {
622        let name = name.as_ref();
623        self.methods
624            .push((name.into(), Self::box_function(name, function)));
625    }
626
627    fn add_function_mut<F, A, R>(&mut self, name: impl AsRef<str>, function: F)
628    where
629        F: FnMut(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
630        A: FromLuaMulti<'lua>,
631        R: IntoLuaMulti<'lua>,
632    {
633        let name = name.as_ref();
634        self.methods
635            .push((name.into(), Self::box_function_mut(name, function)));
636    }
637
638    #[cfg(feature = "async")]
639    fn add_async_function<F, A, FR, R>(&mut self, name: impl AsRef<str>, function: F)
640    where
641        F: Fn(&'lua Lua, A) -> FR + MaybeSend + 'static,
642        A: FromLuaMulti<'lua>,
643        FR: Future<Output = Result<R>> + 'lua,
644        R: IntoLuaMulti<'lua>,
645    {
646        let name = name.as_ref();
647        self.async_methods
648            .push((name.into(), Self::box_async_function(name, function)));
649    }
650
651    fn add_meta_method<M, A, R>(&mut self, name: impl AsRef<str>, method: M)
652    where
653        M: Fn(&'lua Lua, &T, A) -> Result<R> + MaybeSend + 'static,
654        A: FromLuaMulti<'lua>,
655        R: IntoLuaMulti<'lua>,
656    {
657        let name = name.as_ref();
658        self.meta_methods
659            .push((name.into(), Self::box_method(name, method)));
660    }
661
662    fn add_meta_method_mut<M, A, R>(&mut self, name: impl AsRef<str>, method: M)
663    where
664        M: FnMut(&'lua Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
665        A: FromLuaMulti<'lua>,
666        R: IntoLuaMulti<'lua>,
667    {
668        let name = name.as_ref();
669        self.meta_methods
670            .push((name.into(), Self::box_method_mut(name, method)));
671    }
672
673    #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
674    fn add_async_meta_method<'s, M, A, MR, R>(&mut self, name: impl AsRef<str>, method: M)
675    where
676        'lua: 's,
677        T: 'static,
678        M: Fn(&'lua Lua, &'s T, A) -> MR + MaybeSend + 'static,
679        A: FromLuaMulti<'lua>,
680        MR: Future<Output = Result<R>> + 's,
681        R: IntoLuaMulti<'lua>,
682    {
683        let name = name.as_ref();
684        self.async_meta_methods
685            .push((name.into(), Self::box_async_method(name, method)));
686    }
687
688    #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
689    fn add_async_meta_method_mut<'s, M, A, MR, R>(&mut self, name: impl AsRef<str>, method: M)
690    where
691        'lua: 's,
692        T: 'static,
693        M: Fn(&'lua Lua, &'s mut T, A) -> MR + MaybeSend + 'static,
694        A: FromLuaMulti<'lua>,
695        MR: Future<Output = Result<R>> + 's,
696        R: IntoLuaMulti<'lua>,
697    {
698        let name = name.as_ref();
699        self.async_meta_methods
700            .push((name.into(), Self::box_async_method_mut(name, method)));
701    }
702
703    fn add_meta_function<F, A, R>(&mut self, name: impl AsRef<str>, function: F)
704    where
705        F: Fn(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
706        A: FromLuaMulti<'lua>,
707        R: IntoLuaMulti<'lua>,
708    {
709        let name = name.as_ref();
710        self.meta_methods
711            .push((name.into(), Self::box_function(name, function)));
712    }
713
714    fn add_meta_function_mut<F, A, R>(&mut self, name: impl AsRef<str>, function: F)
715    where
716        F: FnMut(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
717        A: FromLuaMulti<'lua>,
718        R: IntoLuaMulti<'lua>,
719    {
720        let name = name.as_ref();
721        self.meta_methods
722            .push((name.into(), Self::box_function_mut(name, function)));
723    }
724
725    #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
726    fn add_async_meta_function<F, A, FR, R>(&mut self, name: impl AsRef<str>, function: F)
727    where
728        F: Fn(&'lua Lua, A) -> FR + MaybeSend + 'static,
729        A: FromLuaMulti<'lua>,
730        FR: Future<Output = Result<R>> + 'lua,
731        R: IntoLuaMulti<'lua>,
732    {
733        let name = name.as_ref();
734        self.async_meta_methods
735            .push((name.into(), Self::box_async_function(name, function)));
736    }
737
738    // Below are internal methods used in generated code
739
740    fn append_methods_from<S>(&mut self, other: UserDataRegistry<'lua, S>) {
741        self.methods.extend(other.methods);
742        #[cfg(feature = "async")]
743        self.async_methods.extend(other.async_methods);
744        self.meta_methods.extend(other.meta_methods);
745        #[cfg(feature = "async")]
746        self.async_meta_methods.extend(other.async_meta_methods);
747    }
748}
749
750#[inline]
751unsafe fn get_userdata_ref<'a, T>(state: *mut ffi::lua_State, index: c_int) -> Result<Ref<'a, T>> {
752    (*get_userdata::<UserDataCell<T>>(state, index)).try_borrow()
753}
754
755#[inline]
756unsafe fn get_userdata_mut<'a, T>(
757    state: *mut ffi::lua_State,
758    index: c_int,
759) -> Result<RefMut<'a, T>> {
760    (*get_userdata::<UserDataCell<T>>(state, index)).try_borrow_mut()
761}
762
763macro_rules! lua_userdata_impl {
764    ($type:ty) => {
765        impl<T: UserData + 'static> UserData for $type {
766            fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) {
767                let mut orig_fields = UserDataRegistry::new();
768                T::add_fields(&mut orig_fields);
769                fields.append_fields_from(orig_fields);
770            }
771
772            fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
773                let mut orig_methods = UserDataRegistry::new();
774                T::add_methods(&mut orig_methods);
775                methods.append_methods_from(orig_methods);
776            }
777        }
778    };
779}
780
781#[cfg(not(feature = "send"))]
782lua_userdata_impl!(Rc<T>);
783#[cfg(not(feature = "send"))]
784lua_userdata_impl!(Rc<RefCell<T>>);
785
786lua_userdata_impl!(Arc<T>);
787lua_userdata_impl!(Arc<Mutex<T>>);
788lua_userdata_impl!(Arc<RwLock<T>>);
789#[cfg(feature = "parking_lot")]
790lua_userdata_impl!(Arc<parking_lot::Mutex<T>>);
791#[cfg(feature = "parking_lot")]
792lua_userdata_impl!(Arc<parking_lot::RwLock<T>>);
793
794// A special proxy object for UserData
795pub(crate) struct UserDataProxy<T>(pub(crate) PhantomData<T>);
796
797lua_userdata_impl!(UserDataProxy<T>);