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
33pub struct UserDataRegistry<T> {
35 lua: LuaGuard,
36 raw: RawUserDataRegistry,
37 r#type: UserDataType,
38 _phantom: PhantomData<T>,
39}
40
41pub(crate) struct RawUserDataRegistry {
42 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 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 let self_index = ffi::lua_absindex(state, -nargs);
135 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 let self_index = ffi::lua_absindex(state, -nargs);
184 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 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 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 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 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
362fn 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 (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
633pub(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}