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
25pub struct UserDataRegistry<'lua, T: 'static> {
27 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 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 let index = ffi::lua_absindex(state, -nargs);
85 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 let index = ffi::lua_absindex(state, -nargs);
165 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
467fn 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 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 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
794pub(crate) struct UserDataProxy<T>(pub(crate) PhantomData<T>);
796
797lua_userdata_impl!(UserDataProxy<T>);