1use std::any::Any;
2use std::cell::{Cell, RefCell};
3use std::marker::PhantomData;
4use std::mem;
5use std::os::raw::c_int;
6
7#[cfg(feature = "serialize")]
8use serde::Serialize;
9
10use crate::error::{Error, Result};
11use crate::function::Function;
12use crate::lua::Lua;
13use crate::types::{Callback, CallbackUpvalue, LuaRef, MaybeSend, SubtypeId};
14use crate::userdata::{
15 AnyUserData, MetaMethod, UserData, UserDataCell, UserDataFields, UserDataMethods,
16};
17use crate::userdata_impl::UserDataRegistry;
18use crate::util::{
19 self, assert_stack, check_stack, init_userdata_metatable, push_string, push_table,
20 rawset_field, short_type_name, take_userdata, StackGuard,
21};
22use crate::value::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti};
23
24#[cfg(feature = "lua54")]
25use crate::userdata::USER_VALUE_MAXSLOT;
26
27#[cfg(feature = "async")]
28use std::future::Future;
29
30pub struct Scope<'lua, 'scope>
37where
38 'lua: 'scope,
39{
40 lua: &'lua Lua,
41 destructors: RefCell<Vec<(LuaRef<'lua>, DestructorCallback<'lua>)>>,
42 _scope_invariant: PhantomData<Cell<&'scope ()>>,
43}
44
45type DestructorCallback<'lua> = Box<dyn Fn(LuaRef<'lua>) -> Vec<Box<dyn Any>> + 'lua>;
46
47impl<'lua, 'scope> Scope<'lua, 'scope> {
48 pub(crate) fn new(lua: &'lua Lua) -> Scope<'lua, 'scope> {
49 Scope {
50 lua,
51 destructors: RefCell::new(Vec::new()),
52 _scope_invariant: PhantomData,
53 }
54 }
55
56 pub fn create_function<'callback, A, R, F>(&'callback self, func: F) -> Result<Function<'lua>>
64 where
65 A: FromLuaMulti<'callback>,
66 R: IntoLuaMulti<'callback>,
67 F: Fn(&'callback Lua, A) -> Result<R> + 'scope,
68 {
69 unsafe {
79 self.create_callback(Box::new(move |lua, nargs| {
80 let args = A::from_stack_args(nargs, 1, None, lua)?;
81 func(lua, args)?.push_into_stack_multi(lua)
82 }))
83 }
84 }
85
86 pub fn create_function_mut<'callback, A, R, F>(
95 &'callback self,
96 func: F,
97 ) -> Result<Function<'lua>>
98 where
99 A: FromLuaMulti<'callback>,
100 R: IntoLuaMulti<'callback>,
101 F: FnMut(&'callback Lua, A) -> Result<R> + 'scope,
102 {
103 let func = RefCell::new(func);
104 self.create_function(move |lua, args| {
105 (*func
106 .try_borrow_mut()
107 .map_err(|_| Error::RecursiveMutCallback)?)(lua, args)
108 })
109 }
110
111 pub fn create_userdata<T>(&self, data: T) -> Result<AnyUserData<'lua>>
121 where
122 T: UserData + 'static,
123 {
124 unsafe {
127 let ud = self.lua.make_userdata(UserDataCell::new(data))?;
128 self.seal_userdata::<T>(&ud)?;
129 Ok(ud)
130 }
131 }
132
133 #[cfg(feature = "serialize")]
145 #[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
146 pub fn create_ser_userdata<T>(&self, data: T) -> Result<AnyUserData<'lua>>
147 where
148 T: UserData + Serialize + 'static,
149 {
150 unsafe {
151 let ud = self.lua.make_userdata(UserDataCell::new_ser(data))?;
152 self.seal_userdata::<T>(&ud)?;
153 Ok(ud)
154 }
155 }
156
157 pub fn create_userdata_ref<T>(&self, data: &'scope T) -> Result<AnyUserData<'lua>>
165 where
166 T: UserData + 'static,
167 {
168 unsafe {
169 let ud = self.lua.make_userdata(UserDataCell::new_ref(data))?;
170 self.seal_userdata::<T>(&ud)?;
171 Ok(ud)
172 }
173 }
174
175 pub fn create_userdata_ref_mut<T>(&self, data: &'scope mut T) -> Result<AnyUserData<'lua>>
181 where
182 T: UserData + 'static,
183 {
184 unsafe {
185 let ud = self.lua.make_userdata(UserDataCell::new_ref_mut(data))?;
186 self.seal_userdata::<T>(&ud)?;
187 Ok(ud)
188 }
189 }
190
191 #[inline]
197 pub fn create_any_userdata<T>(&self, data: T) -> Result<AnyUserData<'lua>>
198 where
199 T: 'static,
200 {
201 unsafe {
202 let ud = self.lua.make_any_userdata(UserDataCell::new(data))?;
203 self.seal_userdata::<T>(&ud)?;
204 Ok(ud)
205 }
206 }
207
208 pub fn create_any_userdata_ref<T>(&self, data: &'scope T) -> Result<AnyUserData<'lua>>
216 where
217 T: 'static,
218 {
219 unsafe {
220 let ud = self.lua.make_any_userdata(UserDataCell::new_ref(data))?;
221 self.seal_userdata::<T>(&ud)?;
222 Ok(ud)
223 }
224 }
225
226 pub fn create_any_userdata_ref_mut<T>(&self, data: &'scope mut T) -> Result<AnyUserData<'lua>>
232 where
233 T: 'static,
234 {
235 let lua = self.lua;
236 unsafe {
237 let ud = lua.make_any_userdata(UserDataCell::new_ref_mut(data))?;
238 self.seal_userdata::<T>(&ud)?;
239 Ok(ud)
240 }
241 }
242
243 unsafe fn seal_userdata<T: 'static>(&self, ud: &AnyUserData<'lua>) -> Result<()> {
245 #[cfg(any(feature = "lua51", feature = "luajit"))]
246 let newtable = self.lua.create_table()?;
247 let destructor: DestructorCallback = Box::new(move |ud| {
248 let state = ud.lua.state();
249 let _sg = StackGuard::new(state);
250 assert_stack(state, 2);
251
252 if ud.lua.push_userdata_ref(&ud).is_err() {
254 return vec![];
255 }
256
257 #[cfg(feature = "lua54")]
259 for i in 1..=USER_VALUE_MAXSLOT {
260 ffi::lua_pushnil(state);
261 ffi::lua_setiuservalue(state, -2, i as _);
262 }
263 #[cfg(any(feature = "lua53", feature = "lua52", feature = "luau"))]
264 {
265 ffi::lua_pushnil(state);
266 ffi::lua_setuservalue(state, -2);
267 }
268 #[cfg(any(feature = "lua51", feature = "luajit"))]
269 {
270 ud.lua.push_ref(&newtable.0);
271 ffi::lua_setuservalue(state, -2);
272 }
273
274 vec![Box::new(take_userdata::<UserDataCell<T>>(state))]
275 });
276 self.destructors
277 .borrow_mut()
278 .push((ud.0.clone(), destructor));
279
280 Ok(())
281 }
282
283 pub fn create_nonstatic_userdata<T>(&self, data: T) -> Result<AnyUserData<'lua>>
307 where
308 T: UserData + 'scope,
309 {
310 unsafe fn wrap_method<'scope, 'lua, 'callback: 'scope, T: 'scope>(
316 scope: &Scope<'lua, 'scope>,
317 ud_ptr: *const UserDataCell<T>,
318 name: &str,
319 method: NonStaticMethod<'callback, T>,
320 ) -> Result<Function<'lua>> {
321 let func_name = format!("{}.{name}", short_type_name::<T>());
329 let check_self_type = move |lua: &Lua, nargs: c_int| -> Result<&UserDataCell<T>> {
330 let state = lua.state();
331 if nargs > 0 && ffi::lua_touserdata(state, -nargs) as *const _ == ud_ptr {
332 return Ok(&*ud_ptr);
333 }
334 Err(Error::bad_self_argument(
335 &func_name,
336 Error::UserDataTypeMismatch,
337 ))
338 };
339
340 match method {
341 NonStaticMethod::Method(method) => {
342 let f = Box::new(move |lua, nargs| {
343 let data = check_self_type(lua, nargs)?;
344 let data = data.try_borrow()?;
345 method(lua, &*data, nargs - 1)
346 });
347 scope.create_callback(f)
348 }
349 NonStaticMethod::MethodMut(method) => {
350 let method = RefCell::new(method);
351 let f = Box::new(move |lua, nargs| {
352 let data = check_self_type(lua, nargs)?;
353 let mut method = method
354 .try_borrow_mut()
355 .map_err(|_| Error::RecursiveMutCallback)?;
356 let mut data = data.try_borrow_mut()?;
357 (*method)(lua, &mut *data, nargs - 1)
358 });
359 scope.create_callback(f)
360 }
361 NonStaticMethod::Function(function) => scope.create_callback(function),
362 NonStaticMethod::FunctionMut(function) => {
363 let function = RefCell::new(function);
364 let f = Box::new(move |lua, nargs| {
365 let mut func = function
366 .try_borrow_mut()
367 .map_err(|_| Error::RecursiveMutCallback)?;
368 func(lua, nargs)
369 });
370 scope.create_callback(f)
371 }
372 }
373 }
374
375 let mut registry = NonStaticUserDataRegistry::new();
376 T::add_fields(&mut registry);
377 T::add_methods(&mut registry);
378
379 let lua = self.lua;
380 let state = lua.state();
381 unsafe {
382 let _sg = StackGuard::new(state);
383 check_stack(state, 13)?;
384
385 #[cfg(not(feature = "luau"))]
386 let ud_ptr = protect_lua!(state, 0, 1, |state| {
387 let ud = ffi::lua_newuserdata(state, mem::size_of::<UserDataCell<T>>());
388
389 #[cfg(any(feature = "lua51", feature = "luajit"))]
391 {
392 ffi::lua_newtable(state);
393 ffi::lua_setuservalue(state, -2);
394 }
395
396 ud as *const UserDataCell<T>
397 })?;
398 #[cfg(feature = "luau")]
399 let ud_ptr = {
400 util::push_userdata(state, UserDataCell::new(data), true)?;
401 ffi::lua_touserdata(state, -1) as *const UserDataCell<T>
402 };
403
404 let meta_methods_nrec = registry.meta_methods.len() + registry.meta_fields.len() + 1;
406 push_table(state, 0, meta_methods_nrec, true)?;
407 for (k, m) in registry.meta_methods {
408 lua.push(wrap_method(self, ud_ptr, &k, m)?)?;
409 rawset_field(state, -2, MetaMethod::validate(&k)?)?;
410 }
411 let mut has_name = false;
412 for (k, f) in registry.meta_fields {
413 has_name = has_name || k == MetaMethod::Type;
414 mlua_assert!(f(lua, 0)? == 1, "field function must return one value");
415 rawset_field(state, -2, MetaMethod::validate(&k)?)?;
416 }
417 if !has_name {
419 let type_name = short_type_name::<T>();
420 push_string(state, type_name.as_bytes(), !lua.unlikely_memory_error())?;
421 rawset_field(state, -2, MetaMethod::Type.name())?;
422 }
423 let metatable_index = ffi::lua_absindex(state, -1);
424
425 let fields_nrec = registry.fields.len();
426 if fields_nrec > 0 {
427 let index_type = ffi::lua_getfield(state, metatable_index, cstr!("__index"));
429 match index_type {
430 ffi::LUA_TNIL | ffi::LUA_TTABLE => {
431 if index_type == ffi::LUA_TNIL {
432 ffi::lua_pop(state, 1);
434 push_table(state, 0, fields_nrec, true)?;
435 }
436 for (k, f) in registry.fields {
437 #[rustfmt::skip]
438 let NonStaticMethod::Function(f) = f else { unreachable!() };
439 mlua_assert!(f(lua, 0)? == 1, "field function must return one value");
440 rawset_field(state, -2, &k)?;
441 }
442 rawset_field(state, metatable_index, "__index")?;
443 }
444 _ => {
445 for (k, f) in registry.fields {
447 registry.field_getters.push((k, f))
448 }
449 }
450 }
451 }
452
453 let mut field_getters_index = None;
454 let field_getters_nrec = registry.field_getters.len();
455 if field_getters_nrec > 0 {
456 push_table(state, 0, field_getters_nrec, true)?;
457 for (k, m) in registry.field_getters {
458 lua.push(wrap_method(self, ud_ptr, &k, m)?)?;
459 rawset_field(state, -2, &k)?;
460 }
461 field_getters_index = Some(ffi::lua_absindex(state, -1));
462 }
463
464 let mut field_setters_index = None;
465 let field_setters_nrec = registry.field_setters.len();
466 if field_setters_nrec > 0 {
467 push_table(state, 0, field_setters_nrec, true)?;
468 for (k, m) in registry.field_setters {
469 lua.push(wrap_method(self, ud_ptr, &k, m)?)?;
470 rawset_field(state, -2, &k)?;
471 }
472 field_setters_index = Some(ffi::lua_absindex(state, -1));
473 }
474
475 let mut methods_index = None;
476 let methods_nrec = registry.methods.len();
477 if methods_nrec > 0 {
478 push_table(state, 0, methods_nrec, true)?;
480 for (k, m) in registry.methods {
481 lua.push(wrap_method(self, ud_ptr, &k, m)?)?;
482 rawset_field(state, -2, &k)?;
483 }
484 methods_index = Some(ffi::lua_absindex(state, -1));
485 }
486
487 #[cfg(feature = "luau")]
488 let extra_init = None;
489 #[cfg(not(feature = "luau"))]
490 let extra_init: Option<fn(*mut ffi::lua_State) -> Result<()>> = Some(|state| {
491 ffi::lua_pushcfunction(state, util::userdata_destructor::<UserDataCell<T>>);
492 rawset_field(state, -2, "__gc")
493 });
494
495 init_userdata_metatable(
496 state,
497 metatable_index,
498 field_getters_index,
499 field_setters_index,
500 methods_index,
501 extra_init,
502 )?;
503
504 let count = field_getters_index.map(|_| 1).unwrap_or(0)
505 + field_setters_index.map(|_| 1).unwrap_or(0)
506 + methods_index.map(|_| 1).unwrap_or(0);
507 ffi::lua_pop(state, count);
508
509 let mt_ptr = ffi::lua_topointer(state, -1);
510 #[cfg(not(feature = "luau"))]
512 std::ptr::write(ud_ptr as _, UserDataCell::new(data));
513 ffi::lua_setmetatable(state, -2);
514 let ud = AnyUserData(lua.pop_ref(), SubtypeId::None);
515 lua.register_raw_userdata_metatable(mt_ptr, None);
516
517 #[cfg(any(feature = "lua51", feature = "luajit"))]
518 let newtable = lua.create_table()?;
519 let destructor: DestructorCallback = Box::new(move |ud| {
520 let state = ud.lua.state();
521 let _sg = StackGuard::new(state);
522 assert_stack(state, 2);
523
524 if ud.lua.push_userdata_ref(&ud).is_err() {
526 return vec![];
527 }
528
529 ffi::lua_getmetatable(state, -1);
531 let mt_ptr = ffi::lua_topointer(state, -1);
532 ffi::lua_pop(state, 1);
533 ud.lua.deregister_raw_userdata_metatable(mt_ptr);
534
535 #[cfg(feature = "lua54")]
537 for i in 1..=USER_VALUE_MAXSLOT {
538 ffi::lua_pushnil(state);
539 ffi::lua_setiuservalue(state, -2, i as _);
540 }
541 #[cfg(any(feature = "lua53", feature = "lua52", feature = "luau"))]
542 {
543 ffi::lua_pushnil(state);
544 ffi::lua_setuservalue(state, -2);
545 }
546 #[cfg(any(feature = "lua51", feature = "luajit"))]
547 {
548 ud.lua.push_ref(&newtable.0);
549 ffi::lua_setuservalue(state, -2);
550 }
551
552 unsafe fn seal<T>(t: T) -> Box<dyn FnOnce() + 'static> {
554 let f: Box<dyn FnOnce()> = Box::new(move || drop(t));
555 mem::transmute(f)
556 }
557
558 let ud = take_userdata::<UserDataCell<T>>(state);
559 vec![Box::new(seal(ud))]
560 });
561 self.destructors
562 .borrow_mut()
563 .push((ud.0.clone(), destructor));
564
565 Ok(ud)
566 }
567 }
568
569 unsafe fn create_callback<'callback>(
575 &self,
576 f: Callback<'callback, 'scope>,
577 ) -> Result<Function<'lua>> {
578 let f = mem::transmute::<Callback<'callback, 'scope>, Callback<'lua, 'static>>(f);
579 let f = self.lua.create_callback(f)?;
580
581 let destructor: DestructorCallback = Box::new(|f| {
582 let state = f.lua.state();
583 let _sg = StackGuard::new(state);
584 assert_stack(state, 3);
585
586 f.lua.push_ref(&f);
587
588 ffi::lua_getupvalue(state, -1, 1);
591 let ud = take_userdata::<CallbackUpvalue>(state);
592 ffi::lua_pushnil(state);
593 ffi::lua_setupvalue(state, -2, 1);
594
595 vec![Box::new(ud)]
596 });
597 self.destructors
598 .borrow_mut()
599 .push((f.0.clone(), destructor));
600
601 Ok(f)
602 }
603}
604
605impl<'lua, 'scope> Drop for Scope<'lua, 'scope> {
606 fn drop(&mut self) {
607 let to_drop = self
613 .destructors
614 .get_mut()
615 .drain(..)
616 .flat_map(|(r, dest)| dest(r))
617 .collect::<Vec<_>>();
618
619 drop(to_drop);
620 }
621}
622
623#[allow(clippy::type_complexity)]
624enum NonStaticMethod<'lua, T> {
625 Method(Box<dyn Fn(&'lua Lua, &T, c_int) -> Result<c_int>>),
626 MethodMut(Box<dyn FnMut(&'lua Lua, &mut T, c_int) -> Result<c_int>>),
627 Function(Box<dyn Fn(&'lua Lua, c_int) -> Result<c_int>>),
628 FunctionMut(Box<dyn FnMut(&'lua Lua, c_int) -> Result<c_int>>),
629}
630
631struct NonStaticUserDataRegistry<'lua, T> {
632 fields: Vec<(String, NonStaticMethod<'lua, T>)>,
634 field_getters: Vec<(String, NonStaticMethod<'lua, T>)>,
635 field_setters: Vec<(String, NonStaticMethod<'lua, T>)>,
636 meta_fields: Vec<(String, Callback<'lua, 'static>)>,
637
638 methods: Vec<(String, NonStaticMethod<'lua, T>)>,
640 meta_methods: Vec<(String, NonStaticMethod<'lua, T>)>,
641}
642
643impl<'lua, T> NonStaticUserDataRegistry<'lua, T> {
644 const fn new() -> NonStaticUserDataRegistry<'lua, T> {
645 NonStaticUserDataRegistry {
646 fields: Vec::new(),
647 field_getters: Vec::new(),
648 field_setters: Vec::new(),
649 meta_fields: Vec::new(),
650 methods: Vec::new(),
651 meta_methods: Vec::new(),
652 }
653 }
654}
655
656impl<'lua, T> UserDataFields<'lua, T> for NonStaticUserDataRegistry<'lua, T> {
657 fn add_field<V>(&mut self, name: impl AsRef<str>, value: V)
658 where
659 V: IntoLua<'lua> + Clone + 'static,
660 {
661 let name = name.as_ref().to_string();
662 self.fields.push((
663 name,
664 NonStaticMethod::Function(Box::new(move |lua, _| unsafe {
665 value.clone().push_into_stack_multi(lua)
666 })),
667 ));
668 }
669
670 fn add_field_method_get<M, R>(&mut self, name: impl AsRef<str>, method: M)
671 where
672 M: Fn(&'lua Lua, &T) -> Result<R> + MaybeSend + 'static,
673 R: IntoLua<'lua>,
674 {
675 let method = NonStaticMethod::Method(Box::new(move |lua, ud, _| unsafe {
676 method(lua, ud)?.push_into_stack_multi(lua)
677 }));
678 self.field_getters.push((name.as_ref().into(), method));
679 }
680
681 fn add_field_method_set<M, A>(&mut self, name: impl AsRef<str>, mut method: M)
682 where
683 M: FnMut(&'lua Lua, &mut T, A) -> Result<()> + MaybeSend + 'static,
684 A: FromLua<'lua>,
685 {
686 let func_name = format!("{}.{}", short_type_name::<T>(), name.as_ref());
687 let method = NonStaticMethod::MethodMut(Box::new(move |lua, ud, nargs| unsafe {
688 let val = A::from_stack_args(nargs, 2, Some(&func_name), lua)?;
689 method(lua, ud, val)?.push_into_stack_multi(lua)
690 }));
691 self.field_setters.push((name.as_ref().into(), method));
692 }
693
694 fn add_field_function_get<F, R>(&mut self, name: impl AsRef<str>, function: F)
695 where
696 F: Fn(&'lua Lua, AnyUserData<'lua>) -> Result<R> + MaybeSend + 'static,
697 R: IntoLua<'lua>,
698 {
699 let func_name = format!("{}.{}", short_type_name::<T>(), name.as_ref());
700 let func = NonStaticMethod::Function(Box::new(move |lua, nargs| unsafe {
701 let ud = AnyUserData::from_stack_args(nargs, 1, Some(&func_name), lua)?;
702 function(lua, ud)?.push_into_stack_multi(lua)
703 }));
704 self.field_getters.push((name.as_ref().into(), func));
705 }
706
707 fn add_field_function_set<F, A>(&mut self, name: impl AsRef<str>, mut function: F)
708 where
709 F: FnMut(&'lua Lua, AnyUserData<'lua>, A) -> Result<()> + MaybeSend + 'static,
710 A: FromLua<'lua>,
711 {
712 let func_name = format!("{}.{}", short_type_name::<T>(), name.as_ref());
713 let func = NonStaticMethod::FunctionMut(Box::new(move |lua, nargs| unsafe {
714 let (ud, val) = <_>::from_stack_args(nargs, 1, Some(&func_name), lua)?;
715 function(lua, ud, val)?.push_into_stack_multi(lua)
716 }));
717 self.field_setters.push((name.as_ref().into(), func));
718 }
719
720 fn add_meta_field<V>(&mut self, name: impl AsRef<str>, value: V)
721 where
722 V: IntoLua<'lua> + Clone + 'static,
723 {
724 let name = name.as_ref().to_string();
725 let name2 = name.clone();
726 self.meta_fields.push((
727 name,
728 Box::new(move |lua, _| unsafe {
729 UserDataRegistry::<()>::check_meta_field(lua, &name2, value.clone())?
730 .push_into_stack_multi(lua)
731 }),
732 ));
733 }
734
735 fn add_meta_field_with<F, R>(&mut self, name: impl AsRef<str>, f: F)
736 where
737 F: Fn(&'lua Lua) -> Result<R> + MaybeSend + 'static,
738 R: IntoLua<'lua>,
739 {
740 let name = name.as_ref().to_string();
741 let name2 = name.clone();
742 self.meta_fields.push((
743 name,
744 Box::new(move |lua, _| unsafe {
745 UserDataRegistry::<()>::check_meta_field(lua, &name2, f(lua)?)?
746 .push_into_stack_multi(lua)
747 }),
748 ));
749 }
750}
751
752impl<'lua, T> UserDataMethods<'lua, T> for NonStaticUserDataRegistry<'lua, T> {
753 fn add_method<M, A, R>(&mut self, name: impl AsRef<str>, method: M)
754 where
755 M: Fn(&'lua Lua, &T, A) -> Result<R> + MaybeSend + 'static,
756 A: FromLuaMulti<'lua>,
757 R: IntoLuaMulti<'lua>,
758 {
759 let func_name = format!("{}.{}", short_type_name::<T>(), name.as_ref());
760 let method = NonStaticMethod::Method(Box::new(move |lua, ud, nargs| unsafe {
761 let args = A::from_stack_args(nargs, 2, Some(&func_name), lua)?;
762 method(lua, ud, args)?.push_into_stack_multi(lua)
763 }));
764 self.methods.push((name.as_ref().into(), method));
765 }
766
767 fn add_method_mut<M, A, R>(&mut self, name: impl AsRef<str>, mut method: M)
768 where
769 M: FnMut(&'lua Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
770 A: FromLuaMulti<'lua>,
771 R: IntoLuaMulti<'lua>,
772 {
773 let func_name = format!("{}.{}", short_type_name::<T>(), name.as_ref());
774 let method = NonStaticMethod::MethodMut(Box::new(move |lua, ud, nargs| unsafe {
775 let args = A::from_stack_args(nargs, 2, Some(&func_name), lua)?;
776 method(lua, ud, args)?.push_into_stack_multi(lua)
777 }));
778 self.methods.push((name.as_ref().into(), method));
779 }
780
781 #[cfg(feature = "async")]
782 fn add_async_method<'s, M, A, MR, R>(&mut self, _name: impl AsRef<str>, _method: M)
783 where
784 'lua: 's,
785 T: 'static,
786 M: Fn(&'lua Lua, &'s T, A) -> MR + MaybeSend + 'static,
787 A: FromLuaMulti<'lua>,
788 MR: Future<Output = Result<R>> + 's,
789 R: IntoLuaMulti<'lua>,
790 {
791 panic!("asynchronous methods are not supported for non-static userdata")
794 }
795
796 #[cfg(feature = "async")]
797 fn add_async_method_mut<'s, M, A, MR, R>(&mut self, _name: impl AsRef<str>, _method: M)
798 where
799 'lua: 's,
800 T: 'static,
801 M: Fn(&'lua Lua, &'s mut T, A) -> MR + MaybeSend + 'static,
802 A: FromLuaMulti<'lua>,
803 MR: Future<Output = Result<R>> + 's,
804 R: IntoLuaMulti<'lua>,
805 {
806 panic!("asynchronous methods are not supported for non-static userdata")
809 }
810
811 fn add_function<F, A, R>(&mut self, name: impl AsRef<str>, function: F)
812 where
813 F: Fn(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
814 A: FromLuaMulti<'lua>,
815 R: IntoLuaMulti<'lua>,
816 {
817 let func_name = format!("{}.{}", short_type_name::<T>(), name.as_ref());
818 let func = NonStaticMethod::Function(Box::new(move |lua, nargs| unsafe {
819 let args = A::from_stack_args(nargs, 1, Some(&func_name), lua)?;
820 function(lua, args)?.push_into_stack_multi(lua)
821 }));
822 self.methods.push((name.as_ref().into(), func));
823 }
824
825 fn add_function_mut<F, A, R>(&mut self, name: impl AsRef<str>, mut function: F)
826 where
827 F: FnMut(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
828 A: FromLuaMulti<'lua>,
829 R: IntoLuaMulti<'lua>,
830 {
831 let func_name = format!("{}.{}", short_type_name::<T>(), name.as_ref());
832 let func = NonStaticMethod::FunctionMut(Box::new(move |lua, nargs| unsafe {
833 let args = A::from_stack_args(nargs, 1, Some(&func_name), lua)?;
834 function(lua, args)?.push_into_stack_multi(lua)
835 }));
836 self.methods.push((name.as_ref().into(), func));
837 }
838
839 #[cfg(feature = "async")]
840 fn add_async_function<F, A, FR, R>(&mut self, _name: impl AsRef<str>, _function: F)
841 where
842 F: Fn(&'lua Lua, A) -> FR + MaybeSend + 'static,
843 A: FromLuaMulti<'lua>,
844 FR: Future<Output = Result<R>> + 'lua,
845 R: IntoLuaMulti<'lua>,
846 {
847 panic!("asynchronous functions are not supported for non-static userdata")
850 }
851
852 fn add_meta_method<M, A, R>(&mut self, name: impl AsRef<str>, method: M)
853 where
854 M: Fn(&'lua Lua, &T, A) -> Result<R> + MaybeSend + 'static,
855 A: FromLuaMulti<'lua>,
856 R: IntoLuaMulti<'lua>,
857 {
858 let func_name = format!("{}.{}", short_type_name::<T>(), name.as_ref());
859 let method = NonStaticMethod::Method(Box::new(move |lua, ud, nargs| unsafe {
860 let args = A::from_stack_args(nargs, 2, Some(&func_name), lua)?;
861 method(lua, ud, args)?.push_into_stack_multi(lua)
862 }));
863 self.meta_methods.push((name.as_ref().into(), method));
864 }
865
866 fn add_meta_method_mut<M, A, R>(&mut self, name: impl AsRef<str>, mut method: M)
867 where
868 M: FnMut(&'lua Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
869 A: FromLuaMulti<'lua>,
870 R: IntoLuaMulti<'lua>,
871 {
872 let func_name = format!("{}.{}", short_type_name::<T>(), name.as_ref());
873 let method = NonStaticMethod::MethodMut(Box::new(move |lua, ud, nargs| unsafe {
874 let args = A::from_stack_args(nargs, 2, Some(&func_name), lua)?;
875 method(lua, ud, args)?.push_into_stack_multi(lua)
876 }));
877 self.meta_methods.push((name.as_ref().into(), method));
878 }
879
880 #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
881 fn add_async_meta_method<'s, M, A, MR, R>(&mut self, _name: impl AsRef<str>, _method: M)
882 where
883 'lua: 's,
884 T: 'static,
885 M: Fn(&'lua Lua, &'s T, A) -> MR + MaybeSend + 'static,
886 A: FromLuaMulti<'lua>,
887 MR: Future<Output = Result<R>> + 's,
888 R: IntoLuaMulti<'lua>,
889 {
890 panic!("asynchronous meta methods are not supported for non-static userdata")
893 }
894
895 #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
896 fn add_async_meta_method_mut<'s, M, A, MR, R>(&mut self, _name: impl AsRef<str>, _method: M)
897 where
898 'lua: 's,
899 T: 'static,
900 M: Fn(&'lua Lua, &'s mut T, A) -> MR + MaybeSend + 'static,
901 A: FromLuaMulti<'lua>,
902 MR: Future<Output = Result<R>> + 's,
903 R: IntoLuaMulti<'lua>,
904 {
905 panic!("asynchronous meta methods are not supported for non-static userdata")
908 }
909
910 fn add_meta_function<F, A, R>(&mut self, name: impl AsRef<str>, function: F)
911 where
912 F: Fn(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
913 A: FromLuaMulti<'lua>,
914 R: IntoLuaMulti<'lua>,
915 {
916 let func_name = format!("{}.{}", short_type_name::<T>(), name.as_ref());
917 let func = NonStaticMethod::Function(Box::new(move |lua, nargs| unsafe {
918 let args = A::from_stack_args(nargs, 1, Some(&func_name), lua)?;
919 function(lua, args)?.push_into_stack_multi(lua)
920 }));
921 self.meta_methods.push((name.as_ref().into(), func));
922 }
923
924 fn add_meta_function_mut<F, A, R>(&mut self, name: impl AsRef<str>, mut function: F)
925 where
926 F: FnMut(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
927 A: FromLuaMulti<'lua>,
928 R: IntoLuaMulti<'lua>,
929 {
930 let func_name = format!("{}.{}", short_type_name::<T>(), name.as_ref());
931 let func = NonStaticMethod::FunctionMut(Box::new(move |lua, nargs| unsafe {
932 let args = A::from_stack_args(nargs, 1, Some(&func_name), lua)?;
933 function(lua, args)?.push_into_stack_multi(lua)
934 }));
935 self.meta_methods.push((name.as_ref().into(), func));
936 }
937
938 #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
939 fn add_async_meta_function<F, A, FR, R>(&mut self, _name: impl AsRef<str>, _function: F)
940 where
941 F: Fn(&'lua Lua, A) -> FR + MaybeSend + 'static,
942 A: FromLuaMulti<'lua>,
943 FR: Future<Output = Result<R>> + 'lua,
944 R: IntoLuaMulti<'lua>,
945 {
946 panic!("asynchronous meta functions are not supported for non-static userdata")
949 }
950}