1use std::any::TypeId;
2use std::cell::{Ref, RefCell, RefMut};
3use std::marker::PhantomData;
4use std::sync::{Arc, Mutex, RwLock};
5
6use crate::error::{Error, Result};
7use crate::ffi;
8use crate::lua::Lua;
9use crate::types::{Callback, MaybeSend};
10use crate::userdata::{
11 AnyUserData, MetaMethod, UserData, UserDataCell, UserDataFields, UserDataMethods,
12};
13use crate::util::{check_stack, get_userdata, StackGuard};
14use crate::value::{FromLua, FromLuaMulti, ToLua, ToLuaMulti, Value};
15
16#[cfg(not(feature = "send"))]
17use std::rc::Rc;
18
19#[cfg(feature = "async")]
20use {
21 crate::types::AsyncCallback,
22 futures_core::future::Future,
23 futures_util::future::{self, TryFutureExt},
24};
25
26pub(crate) struct StaticUserDataMethods<'lua, T: 'static + UserData> {
27 pub(crate) methods: Vec<(Vec<u8>, Callback<'lua, 'static>)>,
28 #[cfg(feature = "async")]
29 pub(crate) async_methods: Vec<(Vec<u8>, AsyncCallback<'lua, 'static>)>,
30 pub(crate) meta_methods: Vec<(MetaMethod, Callback<'lua, 'static>)>,
31 #[cfg(feature = "async")]
32 pub(crate) async_meta_methods: Vec<(MetaMethod, AsyncCallback<'lua, 'static>)>,
33 _type: PhantomData<T>,
34}
35
36impl<'lua, T: 'static + UserData> Default for StaticUserDataMethods<'lua, T> {
37 fn default() -> StaticUserDataMethods<'lua, T> {
38 StaticUserDataMethods {
39 methods: Vec::new(),
40 #[cfg(feature = "async")]
41 async_methods: Vec::new(),
42 meta_methods: Vec::new(),
43 #[cfg(feature = "async")]
44 async_meta_methods: Vec::new(),
45 _type: PhantomData,
46 }
47 }
48}
49
50impl<'lua, T: 'static + UserData> UserDataMethods<'lua, T> for StaticUserDataMethods<'lua, T> {
51 fn add_method<S, A, R, M>(&mut self, name: &S, method: M)
52 where
53 S: AsRef<[u8]> + ?Sized,
54 A: FromLuaMulti<'lua>,
55 R: ToLuaMulti<'lua>,
56 M: 'static + MaybeSend + Fn(&'lua Lua, &T, A) -> Result<R>,
57 {
58 self.methods
59 .push((name.as_ref().to_vec(), Self::box_method(method)));
60 }
61
62 fn add_method_mut<S, A, R, M>(&mut self, name: &S, method: M)
63 where
64 S: AsRef<[u8]> + ?Sized,
65 A: FromLuaMulti<'lua>,
66 R: ToLuaMulti<'lua>,
67 M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<R>,
68 {
69 self.methods
70 .push((name.as_ref().to_vec(), Self::box_method_mut(method)));
71 }
72
73 #[cfg(feature = "async")]
74 fn add_async_method<S, A, R, M, MR>(&mut self, name: &S, method: M)
75 where
76 T: Clone,
77 S: AsRef<[u8]> + ?Sized,
78 A: FromLuaMulti<'lua>,
79 R: ToLuaMulti<'lua>,
80 M: 'static + MaybeSend + Fn(&'lua Lua, T, A) -> MR,
81 MR: 'lua + Future<Output = Result<R>>,
82 {
83 self.async_methods
84 .push((name.as_ref().to_vec(), Self::box_async_method(method)));
85 }
86
87 fn add_function<S, A, R, F>(&mut self, name: &S, function: F)
88 where
89 S: AsRef<[u8]> + ?Sized,
90 A: FromLuaMulti<'lua>,
91 R: ToLuaMulti<'lua>,
92 F: 'static + MaybeSend + Fn(&'lua Lua, A) -> Result<R>,
93 {
94 self.methods
95 .push((name.as_ref().to_vec(), Self::box_function(function)));
96 }
97
98 fn add_function_mut<S, A, R, F>(&mut self, name: &S, function: F)
99 where
100 S: AsRef<[u8]> + ?Sized,
101 A: FromLuaMulti<'lua>,
102 R: ToLuaMulti<'lua>,
103 F: 'static + MaybeSend + FnMut(&'lua Lua, A) -> Result<R>,
104 {
105 self.methods
106 .push((name.as_ref().to_vec(), Self::box_function_mut(function)));
107 }
108
109 #[cfg(feature = "async")]
110 fn add_async_function<S, A, R, F, FR>(&mut self, name: &S, function: F)
111 where
112 S: AsRef<[u8]> + ?Sized,
113 A: FromLuaMulti<'lua>,
114 R: ToLuaMulti<'lua>,
115 F: 'static + MaybeSend + Fn(&'lua Lua, A) -> FR,
116 FR: 'lua + Future<Output = Result<R>>,
117 {
118 self.async_methods
119 .push((name.as_ref().to_vec(), Self::box_async_function(function)));
120 }
121
122 fn add_meta_method<S, A, R, M>(&mut self, meta: S, method: M)
123 where
124 S: Into<MetaMethod>,
125 A: FromLuaMulti<'lua>,
126 R: ToLuaMulti<'lua>,
127 M: 'static + MaybeSend + Fn(&'lua Lua, &T, A) -> Result<R>,
128 {
129 self.meta_methods
130 .push((meta.into(), Self::box_method(method)));
131 }
132
133 fn add_meta_method_mut<S, A, R, M>(&mut self, meta: S, method: M)
134 where
135 S: Into<MetaMethod>,
136 A: FromLuaMulti<'lua>,
137 R: ToLuaMulti<'lua>,
138 M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<R>,
139 {
140 self.meta_methods
141 .push((meta.into(), Self::box_method_mut(method)));
142 }
143
144 #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
145 fn add_async_meta_method<S, A, R, M, MR>(&mut self, meta: S, method: M)
146 where
147 T: Clone,
148 S: Into<MetaMethod>,
149 A: FromLuaMulti<'lua>,
150 R: ToLuaMulti<'lua>,
151 M: 'static + MaybeSend + Fn(&'lua Lua, T, A) -> MR,
152 MR: 'lua + Future<Output = Result<R>>,
153 {
154 self.async_meta_methods
155 .push((meta.into(), Self::box_async_method(method)));
156 }
157
158 fn add_meta_function<S, A, R, F>(&mut self, meta: S, function: F)
159 where
160 S: Into<MetaMethod>,
161 A: FromLuaMulti<'lua>,
162 R: ToLuaMulti<'lua>,
163 F: 'static + MaybeSend + Fn(&'lua Lua, A) -> Result<R>,
164 {
165 self.meta_methods
166 .push((meta.into(), Self::box_function(function)));
167 }
168
169 fn add_meta_function_mut<S, A, R, F>(&mut self, meta: S, function: F)
170 where
171 S: Into<MetaMethod>,
172 A: FromLuaMulti<'lua>,
173 R: ToLuaMulti<'lua>,
174 F: 'static + MaybeSend + FnMut(&'lua Lua, A) -> Result<R>,
175 {
176 self.meta_methods
177 .push((meta.into(), Self::box_function_mut(function)));
178 }
179
180 #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
181 fn add_async_meta_function<S, A, R, F, FR>(&mut self, meta: S, function: F)
182 where
183 S: Into<MetaMethod>,
184 A: FromLuaMulti<'lua>,
185 R: ToLuaMulti<'lua>,
186 F: 'static + MaybeSend + Fn(&'lua Lua, A) -> FR,
187 FR: 'lua + Future<Output = Result<R>>,
188 {
189 self.async_meta_methods
190 .push((meta.into(), Self::box_async_function(function)));
191 }
192
193 fn add_callback(&mut self, name: Vec<u8>, callback: Callback<'lua, 'static>) {
196 self.methods.push((name, callback));
197 }
198
199 #[cfg(feature = "async")]
200 fn add_async_callback(&mut self, name: Vec<u8>, callback: AsyncCallback<'lua, 'static>) {
201 self.async_methods.push((name, callback));
202 }
203
204 fn add_meta_callback(&mut self, meta: MetaMethod, callback: Callback<'lua, 'static>) {
205 self.meta_methods.push((meta, callback));
206 }
207
208 #[cfg(feature = "async")]
209 fn add_async_meta_callback(
210 &mut self,
211 meta: MetaMethod,
212 callback: AsyncCallback<'lua, 'static>,
213 ) {
214 self.async_meta_methods.push((meta, callback))
215 }
216}
217
218impl<'lua, T: 'static + UserData> StaticUserDataMethods<'lua, T> {
219 fn box_method<A, R, M>(method: M) -> Callback<'lua, 'static>
220 where
221 A: FromLuaMulti<'lua>,
222 R: ToLuaMulti<'lua>,
223 M: 'static + MaybeSend + Fn(&'lua Lua, &T, A) -> Result<R>,
224 {
225 Box::new(move |lua, mut args| {
226 if let Some(front) = args.pop_front() {
227 let userdata = AnyUserData::from_lua(front, lua)?;
228 unsafe {
229 let _sg = StackGuard::new(lua.state);
230 check_stack(lua.state, 2)?;
231
232 let type_id = lua.push_userdata_ref(&userdata.0)?;
233 match type_id {
234 Some(id) if id == TypeId::of::<T>() => {
235 let ud = get_userdata_ref::<T>(lua.state)?;
236 method(lua, &ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
237 }
238 #[cfg(not(feature = "send"))]
239 Some(id) if id == TypeId::of::<Rc<RefCell<T>>>() => {
240 let ud = get_userdata_ref::<Rc<RefCell<T>>>(lua.state)?;
241 let ud = ud.try_borrow().map_err(|_| Error::UserDataBorrowError)?;
242 method(lua, &ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
243 }
244 Some(id) if id == TypeId::of::<Arc<Mutex<T>>>() => {
245 let ud = get_userdata_ref::<Arc<Mutex<T>>>(lua.state)?;
246 let ud = ud.try_lock().map_err(|_| Error::UserDataBorrowError)?;
247 method(lua, &ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
248 }
249 #[cfg(feature = "parking_lot")]
250 Some(id) if id == TypeId::of::<Arc<parking_lot::Mutex<T>>>() => {
251 let ud = get_userdata_ref::<Arc<parking_lot::Mutex<T>>>(lua.state)?;
252 let ud = ud.try_lock().ok_or(Error::UserDataBorrowError)?;
253 method(lua, &ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
254 }
255 Some(id) if id == TypeId::of::<Arc<RwLock<T>>>() => {
256 let ud = get_userdata_ref::<Arc<RwLock<T>>>(lua.state)?;
257 let ud = ud.try_read().map_err(|_| Error::UserDataBorrowError)?;
258 method(lua, &ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
259 }
260 #[cfg(feature = "parking_lot")]
261 Some(id) if id == TypeId::of::<Arc<parking_lot::RwLock<T>>>() => {
262 let ud = get_userdata_ref::<Arc<parking_lot::RwLock<T>>>(lua.state)?;
263 let ud = ud.try_read().ok_or(Error::UserDataBorrowError)?;
264 method(lua, &ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
265 }
266 _ => Err(Error::UserDataTypeMismatch),
267 }
268 }
269 } else {
270 Err(Error::FromLuaConversionError {
271 from: "missing argument",
272 to: "userdata",
273 message: None,
274 })
275 }
276 })
277 }
278
279 fn box_method_mut<A, R, M>(method: M) -> Callback<'lua, 'static>
280 where
281 A: FromLuaMulti<'lua>,
282 R: ToLuaMulti<'lua>,
283 M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<R>,
284 {
285 let method = RefCell::new(method);
286 Box::new(move |lua, mut args| {
287 if let Some(front) = args.pop_front() {
288 let userdata = AnyUserData::from_lua(front, lua)?;
289 let mut method = method
290 .try_borrow_mut()
291 .map_err(|_| Error::RecursiveMutCallback)?;
292 unsafe {
293 let _sg = StackGuard::new(lua.state);
294 check_stack(lua.state, 2)?;
295
296 let type_id = lua.push_userdata_ref(&userdata.0)?;
297 match type_id {
298 Some(id) if id == TypeId::of::<T>() => {
299 let mut ud = get_userdata_mut::<T>(lua.state)?;
300 method(lua, &mut ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
301 }
302 #[cfg(not(feature = "send"))]
303 Some(id) if id == TypeId::of::<Rc<RefCell<T>>>() => {
304 let ud = get_userdata_mut::<Rc<RefCell<T>>>(lua.state)?;
305 let mut ud = ud
306 .try_borrow_mut()
307 .map_err(|_| Error::UserDataBorrowMutError)?;
308 method(lua, &mut ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
309 }
310 Some(id) if id == TypeId::of::<Arc<Mutex<T>>>() => {
311 let ud = get_userdata_mut::<Arc<Mutex<T>>>(lua.state)?;
312 let mut ud =
313 ud.try_lock().map_err(|_| Error::UserDataBorrowMutError)?;
314 method(lua, &mut ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
315 }
316 #[cfg(feature = "parking_lot")]
317 Some(id) if id == TypeId::of::<Arc<parking_lot::Mutex<T>>>() => {
318 let ud = get_userdata_mut::<Arc<parking_lot::Mutex<T>>>(lua.state)?;
319 let mut ud = ud.try_lock().ok_or(Error::UserDataBorrowMutError)?;
320 method(lua, &mut ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
321 }
322 Some(id) if id == TypeId::of::<Arc<RwLock<T>>>() => {
323 let ud = get_userdata_mut::<Arc<RwLock<T>>>(lua.state)?;
324 let mut ud =
325 ud.try_write().map_err(|_| Error::UserDataBorrowMutError)?;
326 method(lua, &mut ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
327 }
328 #[cfg(feature = "parking_lot")]
329 Some(id) if id == TypeId::of::<Arc<parking_lot::RwLock<T>>>() => {
330 let ud = get_userdata_mut::<Arc<parking_lot::RwLock<T>>>(lua.state)?;
331 let mut ud = ud.try_write().ok_or(Error::UserDataBorrowMutError)?;
332 method(lua, &mut ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
333 }
334 _ => Err(Error::UserDataTypeMismatch),
335 }
336 }
337 } else {
338 Err(Error::FromLuaConversionError {
339 from: "missing argument",
340 to: "userdata",
341 message: None,
342 })
343 }
344 })
345 }
346
347 #[cfg(feature = "async")]
348 fn box_async_method<A, R, M, MR>(method: M) -> AsyncCallback<'lua, 'static>
349 where
350 T: Clone,
351 A: FromLuaMulti<'lua>,
352 R: ToLuaMulti<'lua>,
353 M: 'static + MaybeSend + Fn(&'lua Lua, T, A) -> MR,
354 MR: 'lua + Future<Output = Result<R>>,
355 {
356 Box::new(move |lua, mut args| {
357 let fut_res = || {
358 if let Some(front) = args.pop_front() {
359 let userdata = AnyUserData::from_lua(front, lua)?;
360 unsafe {
361 let _sg = StackGuard::new(lua.state);
362 check_stack(lua.state, 2)?;
363
364 let type_id = lua.push_userdata_ref(&userdata.0)?;
365 match type_id {
366 Some(id) if id == TypeId::of::<T>() => {
367 let ud = get_userdata_ref::<T>(lua.state)?;
368 Ok(method(lua, ud.clone(), A::from_lua_multi(args, lua)?))
369 }
370 #[cfg(not(feature = "send"))]
371 Some(id) if id == TypeId::of::<Rc<RefCell<T>>>() => {
372 let ud = get_userdata_ref::<Rc<RefCell<T>>>(lua.state)?;
373 let ud = ud.try_borrow().map_err(|_| Error::UserDataBorrowError)?;
374 Ok(method(lua, ud.clone(), A::from_lua_multi(args, lua)?))
375 }
376 Some(id) if id == TypeId::of::<Arc<Mutex<T>>>() => {
377 let ud = get_userdata_ref::<Arc<Mutex<T>>>(lua.state)?;
378 let ud = ud.try_lock().map_err(|_| Error::UserDataBorrowError)?;
379 Ok(method(lua, ud.clone(), A::from_lua_multi(args, lua)?))
380 }
381 #[cfg(feature = "parking_lot")]
382 Some(id) if id == TypeId::of::<Arc<parking_lot::Mutex<T>>>() => {
383 let ud = get_userdata_ref::<Arc<parking_lot::Mutex<T>>>(lua.state)?;
384 let ud = ud.try_lock().ok_or(Error::UserDataBorrowError)?;
385 Ok(method(lua, ud.clone(), A::from_lua_multi(args, lua)?))
386 }
387 Some(id) if id == TypeId::of::<Arc<RwLock<T>>>() => {
388 let ud = get_userdata_ref::<Arc<RwLock<T>>>(lua.state)?;
389 let ud = ud.try_read().map_err(|_| Error::UserDataBorrowError)?;
390 Ok(method(lua, ud.clone(), A::from_lua_multi(args, lua)?))
391 }
392 #[cfg(feature = "parking_lot")]
393 Some(id) if id == TypeId::of::<Arc<parking_lot::RwLock<T>>>() => {
394 let ud =
395 get_userdata_ref::<Arc<parking_lot::RwLock<T>>>(lua.state)?;
396 let ud = ud.try_read().ok_or(Error::UserDataBorrowError)?;
397 Ok(method(lua, ud.clone(), A::from_lua_multi(args, lua)?))
398 }
399 _ => Err(Error::UserDataTypeMismatch),
400 }
401 }
402 } else {
403 Err(Error::FromLuaConversionError {
404 from: "missing argument",
405 to: "userdata",
406 message: None,
407 })
408 }
409 };
410 match fut_res() {
411 Ok(fut) => Box::pin(fut.and_then(move |ret| future::ready(ret.to_lua_multi(lua)))),
412 Err(e) => Box::pin(future::err(e)),
413 }
414 })
415 }
416
417 fn box_function<A, R, F>(function: F) -> Callback<'lua, 'static>
418 where
419 A: FromLuaMulti<'lua>,
420 R: ToLuaMulti<'lua>,
421 F: 'static + MaybeSend + Fn(&'lua Lua, A) -> Result<R>,
422 {
423 Box::new(move |lua, args| function(lua, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua))
424 }
425
426 fn box_function_mut<A, R, F>(function: F) -> Callback<'lua, 'static>
427 where
428 A: FromLuaMulti<'lua>,
429 R: ToLuaMulti<'lua>,
430 F: 'static + MaybeSend + FnMut(&'lua Lua, A) -> Result<R>,
431 {
432 let function = RefCell::new(function);
433 Box::new(move |lua, args| {
434 let function = &mut *function
435 .try_borrow_mut()
436 .map_err(|_| Error::RecursiveMutCallback)?;
437 function(lua, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
438 })
439 }
440
441 #[cfg(feature = "async")]
442 fn box_async_function<A, R, F, FR>(function: F) -> AsyncCallback<'lua, 'static>
443 where
444 A: FromLuaMulti<'lua>,
445 R: ToLuaMulti<'lua>,
446 F: 'static + MaybeSend + Fn(&'lua Lua, A) -> FR,
447 FR: 'lua + Future<Output = Result<R>>,
448 {
449 Box::new(move |lua, args| {
450 let args = match A::from_lua_multi(args, lua) {
451 Ok(args) => args,
452 Err(e) => return Box::pin(future::err(e)),
453 };
454 Box::pin(function(lua, args).and_then(move |ret| future::ready(ret.to_lua_multi(lua))))
455 })
456 }
457}
458
459pub(crate) struct StaticUserDataFields<'lua, T: 'static + UserData> {
460 pub(crate) field_getters: Vec<(Vec<u8>, Callback<'lua, 'static>)>,
461 pub(crate) field_setters: Vec<(Vec<u8>, Callback<'lua, 'static>)>,
462 #[allow(clippy::type_complexity)]
463 pub(crate) meta_fields: Vec<(
464 MetaMethod,
465 Box<dyn Fn(&'lua Lua) -> Result<Value<'lua>> + 'static>,
466 )>,
467 _type: PhantomData<T>,
468}
469
470impl<'lua, T: 'static + UserData> Default for StaticUserDataFields<'lua, T> {
471 fn default() -> StaticUserDataFields<'lua, T> {
472 StaticUserDataFields {
473 field_getters: Vec::new(),
474 field_setters: Vec::new(),
475 meta_fields: Vec::new(),
476 _type: PhantomData,
477 }
478 }
479}
480
481impl<'lua, T: 'static + UserData> UserDataFields<'lua, T> for StaticUserDataFields<'lua, T> {
482 fn add_field_method_get<S, R, M>(&mut self, name: &S, method: M)
483 where
484 S: AsRef<[u8]> + ?Sized,
485 R: ToLua<'lua>,
486 M: 'static + MaybeSend + Fn(&'lua Lua, &T) -> Result<R>,
487 {
488 self.field_getters.push((
489 name.as_ref().to_vec(),
490 StaticUserDataMethods::box_method(move |lua, data, ()| method(lua, data)),
491 ));
492 }
493
494 fn add_field_method_set<S, A, M>(&mut self, name: &S, method: M)
495 where
496 S: AsRef<[u8]> + ?Sized,
497 A: FromLua<'lua>,
498 M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<()>,
499 {
500 self.field_setters.push((
501 name.as_ref().to_vec(),
502 StaticUserDataMethods::box_method_mut(method),
503 ));
504 }
505
506 fn add_field_function_get<S, R, F>(&mut self, name: &S, function: F)
507 where
508 S: AsRef<[u8]> + ?Sized,
509 R: ToLua<'lua>,
510 F: 'static + MaybeSend + Fn(&'lua Lua, AnyUserData<'lua>) -> Result<R>,
511 {
512 self.field_getters.push((
513 name.as_ref().to_vec(),
514 StaticUserDataMethods::<T>::box_function(function),
515 ));
516 }
517
518 fn add_field_function_set<S, A, F>(&mut self, name: &S, mut function: F)
519 where
520 S: AsRef<[u8]> + ?Sized,
521 A: FromLua<'lua>,
522 F: 'static + MaybeSend + FnMut(&'lua Lua, AnyUserData<'lua>, A) -> Result<()>,
523 {
524 self.field_setters.push((
525 name.as_ref().to_vec(),
526 StaticUserDataMethods::<T>::box_function_mut(move |lua, (data, val)| {
527 function(lua, data, val)
528 }),
529 ));
530 }
531
532 fn add_meta_field_with<S, R, F>(&mut self, meta: S, f: F)
533 where
534 S: Into<MetaMethod>,
535 R: ToLua<'lua>,
536 F: 'static + MaybeSend + Fn(&'lua Lua) -> Result<R>,
537 {
538 let meta = meta.into();
539 self.meta_fields.push((
540 meta.clone(),
541 Box::new(move |lua| {
542 let value = f(lua)?.to_lua(lua)?;
543 if meta == MetaMethod::Index || meta == MetaMethod::NewIndex {
544 match value {
545 Value::Nil | Value::Table(_) | Value::Function(_) => {}
546 _ => {
547 return Err(Error::MetaMethodTypeError {
548 method: meta.to_string(),
549 type_name: value.type_name(),
550 message: Some("expected nil, table or function".to_string()),
551 })
552 }
553 }
554 }
555 Ok(value)
556 }),
557 ));
558 }
559
560 fn add_field_getter(&mut self, name: Vec<u8>, callback: Callback<'lua, 'static>) {
563 self.field_getters.push((name, callback));
564 }
565
566 fn add_field_setter(&mut self, name: Vec<u8>, callback: Callback<'lua, 'static>) {
567 self.field_setters.push((name, callback));
568 }
569}
570
571#[inline]
572unsafe fn get_userdata_ref<'a, T>(state: *mut ffi::lua_State) -> Result<Ref<'a, T>> {
573 (*get_userdata::<UserDataCell<T>>(state, -1)).try_borrow()
574}
575
576#[inline]
577unsafe fn get_userdata_mut<'a, T>(state: *mut ffi::lua_State) -> Result<RefMut<'a, T>> {
578 (*get_userdata::<UserDataCell<T>>(state, -1)).try_borrow_mut()
579}
580
581macro_rules! lua_userdata_impl {
582 ($type:ty) => {
583 impl<T: 'static + UserData> UserData for $type {
584 fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) {
585 let mut orig_fields = StaticUserDataFields::default();
586 T::add_fields(&mut orig_fields);
587 for (name, callback) in orig_fields.field_getters {
588 fields.add_field_getter(name, callback);
589 }
590 for (name, callback) in orig_fields.field_setters {
591 fields.add_field_setter(name, callback);
592 }
593 }
594
595 fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
596 let mut orig_methods = StaticUserDataMethods::default();
597 T::add_methods(&mut orig_methods);
598 for (name, callback) in orig_methods.methods {
599 methods.add_callback(name, callback);
600 }
601 #[cfg(feature = "async")]
602 for (name, callback) in orig_methods.async_methods {
603 methods.add_async_callback(name, callback);
604 }
605 for (meta, callback) in orig_methods.meta_methods {
606 methods.add_meta_callback(meta, callback);
607 }
608 #[cfg(feature = "async")]
609 for (meta, callback) in orig_methods.async_meta_methods {
610 methods.add_async_meta_callback(meta, callback);
611 }
612 }
613 }
614 };
615}
616
617#[cfg(not(feature = "send"))]
618lua_userdata_impl!(Rc<RefCell<T>>);
619lua_userdata_impl!(Arc<Mutex<T>>);
620lua_userdata_impl!(Arc<RwLock<T>>);
621#[cfg(feature = "parking_lot")]
622lua_userdata_impl!(Arc<parking_lot::Mutex<T>>);
623#[cfg(feature = "parking_lot")]
624lua_userdata_impl!(Arc<parking_lot::RwLock<T>>);