1use std::any::{type_name, TypeId};
2use std::cell::{Ref, RefCell, RefMut};
3use std::ffi::CStr;
4use std::fmt;
5use std::hash::Hash;
6use std::mem;
7use std::ops::{Deref, DerefMut};
8use std::os::raw::{c_char, c_int, c_void};
9use std::string::String as StdString;
10
11#[cfg(feature = "async")]
12use std::future::Future;
13
14#[cfg(feature = "serialize")]
15use {
16 serde::ser::{self, Serialize, Serializer},
17 std::result::Result as StdResult,
18};
19
20use crate::error::{Error, Result};
21use crate::function::Function;
22use crate::lua::Lua;
23use crate::string::String;
24use crate::table::{Table, TablePairs};
25use crate::types::{LuaRef, MaybeSend, SubtypeId};
26use crate::util::{check_stack, get_userdata, take_userdata, StackGuard};
27use crate::value::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, Value};
28use crate::UserDataRegistry;
29
30#[cfg(feature = "lua54")]
31pub(crate) const USER_VALUE_MAXSLOT: usize = 8;
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
40#[non_exhaustive]
41pub enum MetaMethod {
42 Add,
44 Sub,
46 Mul,
48 Div,
50 Mod,
52 Pow,
54 Unm,
56 #[cfg(any(feature = "lua54", feature = "lua53", feature = "luau"))]
59 IDiv,
60 #[cfg(any(feature = "lua54", feature = "lua53"))]
63 BAnd,
64 #[cfg(any(feature = "lua54", feature = "lua53"))]
67 BOr,
68 #[cfg(any(feature = "lua54", feature = "lua53"))]
71 BXor,
72 #[cfg(any(feature = "lua54", feature = "lua53"))]
75 BNot,
76 #[cfg(any(feature = "lua54", feature = "lua53"))]
78 Shl,
79 #[cfg(any(feature = "lua54", feature = "lua53"))]
81 Shr,
82 Concat,
84 Len,
86 Eq,
88 Lt,
90 Le,
92 Index,
94 NewIndex,
96 Call,
98 ToString,
102 #[cfg(any(
108 feature = "lua54",
109 feature = "lua53",
110 feature = "lua52",
111 feature = "luajit52",
112 ))]
113 Pairs,
114 #[cfg(any(feature = "lua52", feature = "luajit52", doc))]
122 #[cfg_attr(docsrs, doc(cfg(any(feature = "lua52", feature = "luajit52"))))]
123 IPairs,
124 #[cfg(any(feature = "luau", doc))]
131 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
132 Iter,
133 #[cfg(feature = "lua54")]
144 #[cfg_attr(docsrs, doc(cfg(feature = "lua54")))]
145 Close,
146 #[doc(hidden)]
150 Type,
151}
152
153impl PartialEq<MetaMethod> for &str {
154 fn eq(&self, other: &MetaMethod) -> bool {
155 *self == other.name()
156 }
157}
158
159impl PartialEq<MetaMethod> for StdString {
160 fn eq(&self, other: &MetaMethod) -> bool {
161 self == other.name()
162 }
163}
164
165impl fmt::Display for MetaMethod {
166 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
167 write!(fmt, "{}", self.name())
168 }
169}
170
171impl MetaMethod {
172 pub const fn name(self) -> &'static str {
174 match self {
175 MetaMethod::Add => "__add",
176 MetaMethod::Sub => "__sub",
177 MetaMethod::Mul => "__mul",
178 MetaMethod::Div => "__div",
179 MetaMethod::Mod => "__mod",
180 MetaMethod::Pow => "__pow",
181 MetaMethod::Unm => "__unm",
182
183 #[cfg(any(feature = "lua54", feature = "lua53", feature = "luau"))]
184 MetaMethod::IDiv => "__idiv",
185 #[cfg(any(feature = "lua54", feature = "lua53"))]
186 MetaMethod::BAnd => "__band",
187 #[cfg(any(feature = "lua54", feature = "lua53"))]
188 MetaMethod::BOr => "__bor",
189 #[cfg(any(feature = "lua54", feature = "lua53"))]
190 MetaMethod::BXor => "__bxor",
191 #[cfg(any(feature = "lua54", feature = "lua53"))]
192 MetaMethod::BNot => "__bnot",
193 #[cfg(any(feature = "lua54", feature = "lua53"))]
194 MetaMethod::Shl => "__shl",
195 #[cfg(any(feature = "lua54", feature = "lua53"))]
196 MetaMethod::Shr => "__shr",
197
198 MetaMethod::Concat => "__concat",
199 MetaMethod::Len => "__len",
200 MetaMethod::Eq => "__eq",
201 MetaMethod::Lt => "__lt",
202 MetaMethod::Le => "__le",
203 MetaMethod::Index => "__index",
204 MetaMethod::NewIndex => "__newindex",
205 MetaMethod::Call => "__call",
206 MetaMethod::ToString => "__tostring",
207
208 #[cfg(any(
209 feature = "lua54",
210 feature = "lua53",
211 feature = "lua52",
212 feature = "luajit52"
213 ))]
214 MetaMethod::Pairs => "__pairs",
215 #[cfg(any(feature = "lua52", feature = "luajit52"))]
216 MetaMethod::IPairs => "__ipairs",
217 #[cfg(feature = "luau")]
218 MetaMethod::Iter => "__iter",
219
220 #[cfg(feature = "lua54")]
221 MetaMethod::Close => "__close",
222
223 #[rustfmt::skip]
224 MetaMethod::Type => if cfg!(feature = "luau") { "__type" } else { "__name" },
225 }
226 }
227
228 pub(crate) const fn as_cstr(self) -> &'static CStr {
229 match self {
230 #[rustfmt::skip]
231 MetaMethod::Type => unsafe {
232 CStr::from_bytes_with_nul_unchecked(if cfg!(feature = "luau") { b"__type\0" } else { b"__name\0" })
233 },
234 _ => unreachable!(),
235 }
236 }
237
238 pub(crate) fn validate(name: &str) -> Result<&str> {
239 match name {
240 "__gc" => Err(Error::MetaMethodRestricted(name.to_string())),
241 "__metatable" => Err(Error::MetaMethodRestricted(name.to_string())),
242 _ if name.starts_with("__mlua") => Err(Error::MetaMethodRestricted(name.to_string())),
243 name => Ok(name),
244 }
245 }
246}
247
248impl AsRef<str> for MetaMethod {
249 fn as_ref(&self) -> &str {
250 self.name()
251 }
252}
253
254pub trait UserDataMethods<'lua, T> {
258 fn add_method<M, A, R>(&mut self, name: impl AsRef<str>, method: M)
266 where
267 M: Fn(&'lua Lua, &T, A) -> Result<R> + MaybeSend + 'static,
268 A: FromLuaMulti<'lua>,
269 R: IntoLuaMulti<'lua>;
270
271 fn add_method_mut<M, A, R>(&mut self, name: impl AsRef<str>, method: M)
277 where
278 M: FnMut(&'lua Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
279 A: FromLuaMulti<'lua>,
280 R: IntoLuaMulti<'lua>;
281
282 #[cfg(feature = "async")]
290 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
291 fn add_async_method<'s, M, A, MR, R>(&mut self, name: impl AsRef<str>, method: M)
292 where
293 'lua: 's,
294 T: 'static,
295 M: Fn(&'lua Lua, &'s T, A) -> MR + MaybeSend + 'static,
296 A: FromLuaMulti<'lua>,
297 MR: Future<Output = Result<R>> + 's,
298 R: IntoLuaMulti<'lua>;
299
300 #[cfg(feature = "async")]
308 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
309 fn add_async_method_mut<'s, M, A, MR, R>(&mut self, name: impl AsRef<str>, method: M)
310 where
311 'lua: 's,
312 T: 'static,
313 M: Fn(&'lua Lua, &'s mut T, A) -> MR + MaybeSend + 'static,
314 A: FromLuaMulti<'lua>,
315 MR: Future<Output = Result<R>> + 's,
316 R: IntoLuaMulti<'lua>;
317
318 fn add_function<F, A, R>(&mut self, name: impl AsRef<str>, function: F)
329 where
330 F: Fn(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
331 A: FromLuaMulti<'lua>,
332 R: IntoLuaMulti<'lua>;
333
334 fn add_function_mut<F, A, R>(&mut self, name: impl AsRef<str>, function: F)
340 where
341 F: FnMut(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
342 A: FromLuaMulti<'lua>,
343 R: IntoLuaMulti<'lua>;
344
345 #[cfg(feature = "async")]
354 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
355 fn add_async_function<F, A, FR, R>(&mut self, name: impl AsRef<str>, function: F)
356 where
357 F: Fn(&'lua Lua, A) -> FR + MaybeSend + 'static,
358 A: FromLuaMulti<'lua>,
359 FR: Future<Output = Result<R>> + 'lua,
360 R: IntoLuaMulti<'lua>;
361
362 fn add_meta_method<M, A, R>(&mut self, name: impl AsRef<str>, method: M)
371 where
372 M: Fn(&'lua Lua, &T, A) -> Result<R> + MaybeSend + 'static,
373 A: FromLuaMulti<'lua>,
374 R: IntoLuaMulti<'lua>;
375
376 fn add_meta_method_mut<M, A, R>(&mut self, name: impl AsRef<str>, method: M)
385 where
386 M: FnMut(&'lua Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
387 A: FromLuaMulti<'lua>,
388 R: IntoLuaMulti<'lua>;
389
390 #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
398 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
399 fn add_async_meta_method<'s, M, A, MR, R>(&mut self, name: impl AsRef<str>, method: M)
400 where
401 'lua: 's,
402 T: 'static,
403 M: Fn(&'lua Lua, &'s T, A) -> MR + MaybeSend + 'static,
404 A: FromLuaMulti<'lua>,
405 MR: Future<Output = Result<R>> + 's,
406 R: IntoLuaMulti<'lua>;
407
408 #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
416 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
417 fn add_async_meta_method_mut<'s, M, A, MR, R>(&mut self, name: impl AsRef<str>, method: M)
418 where
419 'lua: 's,
420 T: 'static,
421 M: Fn(&'lua Lua, &'s mut T, A) -> MR + MaybeSend + 'static,
422 A: FromLuaMulti<'lua>,
423 MR: Future<Output = Result<R>> + 's,
424 R: IntoLuaMulti<'lua>;
425
426 fn add_meta_function<F, A, R>(&mut self, name: impl AsRef<str>, function: F)
432 where
433 F: Fn(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
434 A: FromLuaMulti<'lua>,
435 R: IntoLuaMulti<'lua>;
436
437 fn add_meta_function_mut<F, A, R>(&mut self, name: impl AsRef<str>, function: F)
443 where
444 F: FnMut(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
445 A: FromLuaMulti<'lua>,
446 R: IntoLuaMulti<'lua>;
447
448 #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
456 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
457 fn add_async_meta_function<F, A, FR, R>(&mut self, name: impl AsRef<str>, function: F)
458 where
459 F: Fn(&'lua Lua, A) -> FR + MaybeSend + 'static,
460 A: FromLuaMulti<'lua>,
461 FR: Future<Output = Result<R>> + 'lua,
462 R: IntoLuaMulti<'lua>;
463
464 #[doc(hidden)]
469 fn append_methods_from<S>(&mut self, _other: UserDataRegistry<'lua, S>) {}
470}
471
472pub trait UserDataFields<'lua, T> {
476 fn add_field<V>(&mut self, name: impl AsRef<str>, value: V)
486 where
487 V: IntoLua<'lua> + Clone + 'static;
488
489 fn add_field_method_get<M, R>(&mut self, name: impl AsRef<str>, method: M)
497 where
498 M: Fn(&'lua Lua, &T) -> Result<R> + MaybeSend + 'static,
499 R: IntoLua<'lua>;
500
501 fn add_field_method_set<M, A>(&mut self, name: impl AsRef<str>, method: M)
509 where
510 M: FnMut(&'lua Lua, &mut T, A) -> Result<()> + MaybeSend + 'static,
511 A: FromLua<'lua>;
512
513 fn add_field_function_get<F, R>(&mut self, name: impl AsRef<str>, function: F)
521 where
522 F: Fn(&'lua Lua, AnyUserData<'lua>) -> Result<R> + MaybeSend + 'static,
523 R: IntoLua<'lua>;
524
525 fn add_field_function_set<F, A>(&mut self, name: impl AsRef<str>, function: F)
533 where
534 F: FnMut(&'lua Lua, AnyUserData<'lua>, A) -> Result<()> + MaybeSend + 'static,
535 A: FromLua<'lua>;
536
537 fn add_meta_field<V>(&mut self, name: impl AsRef<str>, value: V)
546 where
547 V: IntoLua<'lua> + Clone + 'static;
548
549 fn add_meta_field_with<F, R>(&mut self, name: impl AsRef<str>, f: F)
558 where
559 F: Fn(&'lua Lua) -> Result<R> + MaybeSend + 'static,
560 R: IntoLua<'lua>;
561
562 #[doc(hidden)]
567 fn append_fields_from<S>(&mut self, _other: UserDataRegistry<'lua, S>) {}
568}
569
570pub trait UserData: Sized {
638 #[allow(unused_variables)]
640 fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) {}
641
642 #[allow(unused_variables)]
644 fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {}
645}
646
647pub(crate) struct UserDataCell<T>(RefCell<UserDataVariant<T>>);
649
650impl<T> UserDataCell<T> {
651 #[inline]
652 pub(crate) fn new(data: T) -> Self {
653 UserDataCell(RefCell::new(UserDataVariant::new(data)))
654 }
655
656 #[inline]
657 pub(crate) fn new_ref(data: &T) -> Self {
658 UserDataCell(RefCell::new(UserDataVariant::new_ref(data)))
659 }
660
661 #[inline]
662 pub(crate) fn new_ref_mut(data: &mut T) -> Self {
663 UserDataCell(RefCell::new(UserDataVariant::new_ref_mut(data)))
664 }
665
666 #[cfg(feature = "serialize")]
667 #[inline]
668 pub(crate) fn new_ser(data: T) -> Self
669 where
670 T: Serialize + 'static,
671 {
672 UserDataCell(RefCell::new(UserDataVariant::new_ser(data)))
673 }
674
675 #[inline]
677 pub(crate) fn try_borrow(&self) -> Result<Ref<T>> {
678 self.0
679 .try_borrow()
680 .map(|r| Ref::map(r, |r| r.deref()))
681 .map_err(|_| Error::UserDataBorrowError)
682 }
683
684 #[inline]
686 pub(crate) fn try_borrow_mut(&self) -> Result<RefMut<T>> {
687 self.0
688 .try_borrow_mut()
689 .map_err(|_| Error::UserDataBorrowMutError)
690 .and_then(|r| {
691 RefMut::filter_map(r, |r| r.try_deref_mut().ok())
692 .map_err(|_| Error::UserDataBorrowMutError)
693 })
694 }
695
696 #[inline]
698 fn into_inner(self) -> Result<T> {
699 self.0.into_inner().into_inner()
700 }
701}
702
703pub(crate) enum UserDataVariant<T> {
704 Default(Box<T>),
705 Ref(*const T),
706 RefMut(*mut T),
707 #[cfg(feature = "serialize")]
708 Serializable(Box<dyn erased_serde::Serialize>),
709}
710
711impl<T> UserDataVariant<T> {
712 #[inline]
713 fn new(data: T) -> Self {
714 UserDataVariant::Default(Box::new(data))
715 }
716
717 #[inline]
718 fn new_ref(data: &T) -> Self {
719 UserDataVariant::Ref(data)
720 }
721
722 #[inline]
723 fn new_ref_mut(data: &mut T) -> Self {
724 UserDataVariant::RefMut(data)
725 }
726
727 #[cfg(feature = "serialize")]
728 #[inline]
729 fn new_ser(data: T) -> Self
730 where
731 T: Serialize + 'static,
732 {
733 UserDataVariant::Serializable(Box::new(data))
734 }
735
736 #[inline]
737 fn try_deref_mut(&mut self) -> Result<&mut T> {
738 match self {
739 Self::Default(data) => Ok(data.deref_mut()),
740 Self::Ref(_) => Err(Error::UserDataBorrowMutError),
741 Self::RefMut(data) => unsafe { Ok(&mut **data) },
742 #[cfg(feature = "serialize")]
743 Self::Serializable(data) => unsafe { Ok(&mut *(data.as_mut() as *mut _ as *mut T)) },
744 }
745 }
746
747 #[inline]
748 fn into_inner(self) -> Result<T> {
749 match self {
750 Self::Default(data) => Ok(*data),
751 Self::Ref(_) | Self::RefMut(_) => Err(Error::UserDataTypeMismatch),
752 #[cfg(feature = "serialize")]
753 Self::Serializable(data) => unsafe {
754 Ok(*Box::from_raw(Box::into_raw(data) as *mut T))
755 },
756 }
757 }
758}
759
760impl<T> Deref for UserDataVariant<T> {
761 type Target = T;
762
763 #[inline]
764 fn deref(&self) -> &Self::Target {
765 match self {
766 Self::Default(data) => data,
767 Self::Ref(data) => unsafe { &**data },
768 Self::RefMut(data) => unsafe { &**data },
769 #[cfg(feature = "serialize")]
770 Self::Serializable(data) => unsafe {
771 &*(data.as_ref() as *const _ as *const Self::Target)
772 },
773 }
774 }
775}
776
777#[derive(Clone, Debug)]
794pub struct AnyUserData<'lua>(pub(crate) LuaRef<'lua>, pub(crate) SubtypeId);
795
796#[cfg(feature = "unstable")]
802#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
803#[derive(Clone, Debug)]
804pub struct OwnedAnyUserData(pub(crate) crate::types::LuaOwnedRef, pub(crate) SubtypeId);
805
806#[cfg(feature = "unstable")]
807impl OwnedAnyUserData {
808 #[cfg_attr(feature = "send", allow(unused))]
810 pub const fn to_ref(&self) -> AnyUserData {
811 AnyUserData(self.0.to_ref(), self.1)
812 }
813}
814
815impl<'lua> AnyUserData<'lua> {
816 pub fn is<T: 'static>(&self) -> bool {
818 self.inspect(|_: &UserDataCell<T>| Ok(())).is_ok()
819 }
820
821 #[inline]
828 pub fn borrow<T: 'static>(&self) -> Result<Ref<T>> {
829 self.inspect(|cell| cell.try_borrow())
830 }
831
832 #[inline]
839 pub fn borrow_mut<T: 'static>(&self) -> Result<RefMut<T>> {
840 self.inspect(|cell| cell.try_borrow_mut())
841 }
842
843 pub fn take<T: 'static>(&self) -> Result<T> {
848 let lua = self.0.lua;
849 let state = lua.state();
850 unsafe {
851 let _sg = StackGuard::new(state);
852 check_stack(state, 2)?;
853
854 let type_id = lua.push_userdata_ref(&self.0)?;
855 match type_id {
856 Some(type_id) if type_id == TypeId::of::<T>() => {
857 let _ = (*get_userdata::<UserDataCell<T>>(state, -1)).try_borrow_mut()?;
859 take_userdata::<UserDataCell<T>>(state).into_inner()
860 }
861 _ => Err(Error::UserDataTypeMismatch),
862 }
863 }
864 }
865
866 #[inline]
875 pub fn set_user_value<V: IntoLua<'lua>>(&self, v: V) -> Result<()> {
876 self.set_nth_user_value(1, v)
877 }
878
879 #[inline]
886 pub fn user_value<V: FromLua<'lua>>(&self) -> Result<V> {
887 self.nth_user_value(1)
888 }
889
890 #[doc(hidden)]
891 #[deprecated(since = "0.9.0", note = "please use `user_value` instead")]
892 pub fn get_user_value<V: FromLua<'lua>>(&self) -> Result<V> {
893 self.nth_user_value(1)
894 }
895
896 pub fn set_nth_user_value<V: IntoLua<'lua>>(&self, n: usize, v: V) -> Result<()> {
907 if n < 1 || n > u16::MAX as usize {
908 return Err(Error::runtime("user value index out of bounds"));
909 }
910
911 let lua = self.0.lua;
912 let state = lua.state();
913 unsafe {
914 let _sg = StackGuard::new(state);
915 check_stack(state, 5)?;
916
917 lua.push_userdata_ref(&self.0)?;
918 lua.push(v)?;
919
920 #[cfg(feature = "lua54")]
921 if n < USER_VALUE_MAXSLOT {
922 ffi::lua_setiuservalue(state, -2, n as c_int);
923 return Ok(());
924 }
925
926 protect_lua!(state, 2, 0, |state| {
928 if getuservalue_table(state, -2) != ffi::LUA_TTABLE {
929 ffi::lua_pop(state, 1);
931 ffi::lua_newtable(state);
932 ffi::lua_pushvalue(state, -1);
933
934 #[cfg(feature = "lua54")]
935 ffi::lua_setiuservalue(state, -4, USER_VALUE_MAXSLOT as c_int);
936 #[cfg(not(feature = "lua54"))]
937 ffi::lua_setuservalue(state, -4);
938 }
939 ffi::lua_pushvalue(state, -2);
940 #[cfg(feature = "lua54")]
941 ffi::lua_rawseti(state, -2, (n - USER_VALUE_MAXSLOT + 1) as ffi::lua_Integer);
942 #[cfg(not(feature = "lua54"))]
943 ffi::lua_rawseti(state, -2, n as ffi::lua_Integer);
944 })?;
945
946 Ok(())
947 }
948 }
949
950 pub fn nth_user_value<V: FromLua<'lua>>(&self, n: usize) -> Result<V> {
960 if n < 1 || n > u16::MAX as usize {
961 return Err(Error::runtime("user value index out of bounds"));
962 }
963
964 let lua = self.0.lua;
965 let state = lua.state();
966 unsafe {
967 let _sg = StackGuard::new(state);
968 check_stack(state, 4)?;
969
970 lua.push_userdata_ref(&self.0)?;
971
972 #[cfg(feature = "lua54")]
973 if n < USER_VALUE_MAXSLOT {
974 ffi::lua_getiuservalue(state, -1, n as c_int);
975 return V::from_lua(lua.pop_value(), lua);
976 }
977
978 protect_lua!(state, 1, 1, |state| {
980 if getuservalue_table(state, -1) != ffi::LUA_TTABLE {
981 ffi::lua_pushnil(state);
982 return;
983 }
984 #[cfg(feature = "lua54")]
985 ffi::lua_rawgeti(state, -1, (n - USER_VALUE_MAXSLOT + 1) as ffi::lua_Integer);
986 #[cfg(not(feature = "lua54"))]
987 ffi::lua_rawgeti(state, -1, n as ffi::lua_Integer);
988 })?;
989
990 V::from_lua(lua.pop_value(), lua)
991 }
992 }
993
994 #[doc(hidden)]
995 #[deprecated(since = "0.9.0", note = "please use `nth_user_value` instead")]
996 pub fn get_nth_user_value<V: FromLua<'lua>>(&self, n: usize) -> Result<V> {
997 self.nth_user_value(n)
998 }
999
1000 pub fn set_named_user_value<V: IntoLua<'lua>>(&self, name: &str, v: V) -> Result<()> {
1006 let lua = self.0.lua;
1007 let state = lua.state();
1008 unsafe {
1009 let _sg = StackGuard::new(state);
1010 check_stack(state, 5)?;
1011
1012 lua.push_userdata_ref(&self.0)?;
1013 lua.push(v)?;
1014
1015 protect_lua!(state, 2, 0, |state| {
1017 if getuservalue_table(state, -2) != ffi::LUA_TTABLE {
1018 ffi::lua_pop(state, 1);
1020 ffi::lua_newtable(state);
1021 ffi::lua_pushvalue(state, -1);
1022
1023 #[cfg(feature = "lua54")]
1024 ffi::lua_setiuservalue(state, -4, USER_VALUE_MAXSLOT as c_int);
1025 #[cfg(not(feature = "lua54"))]
1026 ffi::lua_setuservalue(state, -4);
1027 }
1028 ffi::lua_pushlstring(state, name.as_ptr() as *const c_char, name.len());
1029 ffi::lua_pushvalue(state, -3);
1030 ffi::lua_rawset(state, -3);
1031 })?;
1032
1033 Ok(())
1034 }
1035 }
1036
1037 pub fn named_user_value<V: FromLua<'lua>>(&self, name: &str) -> Result<V> {
1041 let lua = self.0.lua;
1042 let state = lua.state();
1043 unsafe {
1044 let _sg = StackGuard::new(state);
1045 check_stack(state, 4)?;
1046
1047 lua.push_userdata_ref(&self.0)?;
1048
1049 protect_lua!(state, 1, 1, |state| {
1051 if getuservalue_table(state, -1) != ffi::LUA_TTABLE {
1052 ffi::lua_pushnil(state);
1053 return;
1054 }
1055 ffi::lua_pushlstring(state, name.as_ptr() as *const c_char, name.len());
1056 ffi::lua_rawget(state, -2);
1057 })?;
1058
1059 V::from_lua(lua.pop_value(), lua)
1060 }
1061 }
1062
1063 #[doc(hidden)]
1064 #[deprecated(since = "0.9.0", note = "please use `named_user_value` instead")]
1065 pub fn get_named_user_value<V: FromLua<'lua>>(&self, name: &str) -> Result<V> {
1066 self.named_user_value(name)
1067 }
1068
1069 #[inline]
1078 pub fn get_metatable(&self) -> Result<UserDataMetatable<'lua>> {
1079 self.get_raw_metatable().map(UserDataMetatable)
1080 }
1081
1082 fn get_raw_metatable(&self) -> Result<Table<'lua>> {
1083 let lua = self.0.lua;
1084 let state = lua.state();
1085 unsafe {
1086 let _sg = StackGuard::new(state);
1087 check_stack(state, 3)?;
1088
1089 lua.push_userdata_ref(&self.0)?;
1090 ffi::lua_getmetatable(state, -1); Ok(Table(lua.pop_ref()))
1092 }
1093 }
1094
1095 #[inline]
1101 pub fn to_pointer(&self) -> *const c_void {
1102 self.0.to_pointer()
1103 }
1104
1105 #[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
1107 #[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
1108 #[inline]
1109 pub fn into_owned(self) -> OwnedAnyUserData {
1110 OwnedAnyUserData(self.0.into_owned(), self.1)
1111 }
1112
1113 #[cfg(feature = "async")]
1114 #[inline]
1115 pub(crate) fn type_id(&self) -> Result<Option<TypeId>> {
1116 unsafe { self.0.lua.get_userdata_ref_type_id(&self.0) }
1117 }
1118
1119 pub(crate) fn type_name(&self) -> Result<Option<StdString>> {
1121 match self.1 {
1122 SubtypeId::None => {}
1123 #[cfg(feature = "luau")]
1124 SubtypeId::Buffer => return Ok(Some("buffer".to_owned())),
1125 #[cfg(feature = "luajit")]
1126 SubtypeId::CData => return Ok(Some("cdata".to_owned())),
1127 }
1128
1129 let lua = self.0.lua;
1130 let state = lua.state();
1131 unsafe {
1132 let _sg = StackGuard::new(state);
1133 check_stack(state, 3)?;
1134
1135 lua.push_userdata_ref(&self.0)?;
1136 let protect = !lua.unlikely_memory_error();
1137 let name_type = if protect {
1138 protect_lua!(state, 1, 1, |state| {
1139 ffi::luaL_getmetafield(state, -1, MetaMethod::Type.as_cstr().as_ptr())
1140 })?
1141 } else {
1142 ffi::luaL_getmetafield(state, -1, MetaMethod::Type.as_cstr().as_ptr())
1143 };
1144 match name_type {
1145 ffi::LUA_TSTRING => Ok(Some(String(lua.pop_ref()).to_str()?.to_owned())),
1146 _ => Ok(None),
1147 }
1148 }
1149 }
1150
1151 pub(crate) fn equals<T: AsRef<Self>>(&self, other: T) -> Result<bool> {
1152 let other = other.as_ref();
1153 if self == other {
1155 return Ok(true);
1156 }
1157
1158 let mt = self.get_raw_metatable()?;
1159 if mt != other.get_raw_metatable()? {
1160 return Ok(false);
1161 }
1162
1163 if mt.contains_key("__eq")? {
1164 return mt
1165 .get::<_, Function>("__eq")?
1166 .call((self.clone(), other.clone()));
1167 }
1168
1169 Ok(false)
1170 }
1171
1172 #[cfg(feature = "serialize")]
1174 pub(crate) fn is_serializable(&self) -> bool {
1175 let lua = self.0.lua;
1176 let is_serializable = || unsafe {
1177 let _ = lua.get_userdata_ref_type_id(&self.0)?;
1179
1180 let ud = &*get_userdata::<UserDataCell<()>>(lua.ref_thread(), self.0.index);
1181 match &*ud.0.try_borrow().map_err(|_| Error::UserDataBorrowError)? {
1182 UserDataVariant::Serializable(_) => Result::Ok(true),
1183 _ => Result::Ok(false),
1184 }
1185 };
1186 is_serializable().unwrap_or(false)
1187 }
1188
1189 fn inspect<'a, T, F, R>(&'a self, func: F) -> Result<R>
1190 where
1191 T: 'static,
1192 F: FnOnce(&'a UserDataCell<T>) -> Result<R>,
1193 {
1194 let lua = self.0.lua;
1195 unsafe {
1196 let type_id = lua.get_userdata_ref_type_id(&self.0)?;
1197 match type_id {
1198 Some(type_id) if type_id == TypeId::of::<T>() => {
1199 let ref_thread = lua.ref_thread();
1200 func(&*get_userdata::<UserDataCell<T>>(ref_thread, self.0.index))
1201 }
1202 _ => Err(Error::UserDataTypeMismatch),
1203 }
1204 }
1205 }
1206}
1207
1208impl<'lua> PartialEq for AnyUserData<'lua> {
1209 fn eq(&self, other: &Self) -> bool {
1210 self.0 == other.0
1211 }
1212}
1213
1214impl<'lua> AsRef<AnyUserData<'lua>> for AnyUserData<'lua> {
1215 #[inline]
1216 fn as_ref(&self) -> &Self {
1217 self
1218 }
1219}
1220
1221unsafe fn getuservalue_table(state: *mut ffi::lua_State, idx: c_int) -> c_int {
1222 #[cfg(feature = "lua54")]
1223 return ffi::lua_getiuservalue(state, idx, USER_VALUE_MAXSLOT as c_int);
1224 #[cfg(not(feature = "lua54"))]
1225 return ffi::lua_getuservalue(state, idx);
1226}
1227
1228#[cfg(feature = "unstable")]
1230impl OwnedAnyUserData {
1231 #[inline]
1235 pub fn borrow<T: 'static>(&self) -> Result<Ref<T>> {
1236 let ud = self.to_ref();
1237 let t = ud.borrow::<T>()?;
1238 Ok(unsafe { mem::transmute::<Ref<T>, Ref<T>>(t) })
1240 }
1241
1242 #[inline]
1246 pub fn borrow_mut<T: 'static>(&self) -> Result<RefMut<T>> {
1247 let ud = self.to_ref();
1248 let t = ud.borrow_mut::<T>()?;
1249 Ok(unsafe { mem::transmute::<RefMut<T>, RefMut<T>>(t) })
1251 }
1252
1253 #[inline]
1257 pub fn take<T: 'static>(&self) -> Result<T> {
1258 self.to_ref().take()
1259 }
1260}
1261
1262#[derive(Clone, Debug)]
1264pub struct UserDataMetatable<'lua>(pub(crate) Table<'lua>);
1265
1266impl<'lua> UserDataMetatable<'lua> {
1267 pub fn get<V: FromLua<'lua>>(&self, key: impl AsRef<str>) -> Result<V> {
1272 self.0.raw_get(MetaMethod::validate(key.as_ref())?)
1273 }
1274
1275 pub fn set<V: IntoLua<'lua>>(&self, key: impl AsRef<str>, value: V) -> Result<()> {
1282 let key = MetaMethod::validate(key.as_ref())?;
1283 if key == MetaMethod::Index || key == MetaMethod::NewIndex {
1285 return Err(Error::MetaMethodRestricted(key.to_string()));
1286 }
1287 self.0.raw_set(key, value)
1288 }
1289
1290 pub fn contains(&self, key: impl AsRef<str>) -> Result<bool> {
1292 self.0.contains_key(MetaMethod::validate(key.as_ref())?)
1293 }
1294
1295 pub fn pairs<V: FromLua<'lua>>(self) -> UserDataMetatablePairs<'lua, V> {
1301 UserDataMetatablePairs(self.0.pairs())
1302 }
1303}
1304
1305pub struct UserDataMetatablePairs<'lua, V>(TablePairs<'lua, StdString, V>);
1314
1315impl<'lua, V> Iterator for UserDataMetatablePairs<'lua, V>
1316where
1317 V: FromLua<'lua>,
1318{
1319 type Item = Result<(StdString, V)>;
1320
1321 fn next(&mut self) -> Option<Self::Item> {
1322 loop {
1323 match self.0.next()? {
1324 Ok((key, value)) => {
1325 if MetaMethod::validate(&key).is_ok() {
1327 break Some(Ok((key, value)));
1328 }
1329 }
1330 Err(e) => break Some(Err(e)),
1331 }
1332 }
1333 }
1334}
1335
1336#[cfg(feature = "serialize")]
1337impl<'lua> Serialize for AnyUserData<'lua> {
1338 fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
1339 where
1340 S: Serializer,
1341 {
1342 let lua = self.0.lua;
1343
1344 #[cfg(feature = "luau")]
1346 if self.1 == SubtypeId::Buffer {
1347 let buf = unsafe {
1348 let mut size = 0usize;
1349 let buf = ffi::lua_tobuffer(lua.ref_thread(), self.0.index, &mut size);
1350 mlua_assert!(!buf.is_null(), "invalid Luau buffer");
1351 std::slice::from_raw_parts(buf as *const u8, size)
1352 };
1353 return serializer.serialize_bytes(buf);
1354 }
1355
1356 let data = unsafe {
1357 let _ = lua
1358 .get_userdata_ref_type_id(&self.0)
1359 .map_err(ser::Error::custom)?;
1360 let ud = &*get_userdata::<UserDataCell<()>>(lua.ref_thread(), self.0.index);
1361 ud.0.try_borrow()
1362 .map_err(|_| ser::Error::custom(Error::UserDataBorrowError))?
1363 };
1364 match &*data {
1365 UserDataVariant::Serializable(ser) => ser.serialize(serializer),
1366 _ => Err(ser::Error::custom("cannot serialize <userdata>")),
1367 }
1368 }
1369}
1370
1371pub struct UserDataRef<'lua, T: 'static>(#[allow(unused)] AnyUserData<'lua>, Ref<'lua, T>);
1375
1376impl<'lua, T: 'static> Deref for UserDataRef<'lua, T> {
1377 type Target = T;
1378
1379 fn deref(&self) -> &Self::Target {
1380 &self.1
1381 }
1382}
1383
1384impl<'lua, T: 'static> UserDataRef<'lua, T> {
1385 pub(crate) fn from_value(value: Value<'lua>) -> Result<Self> {
1386 let ud = try_value_to_userdata::<T>(value)?;
1387 let this = unsafe { mem::transmute(ud.borrow::<T>()?) };
1389 Ok(UserDataRef(ud, this))
1390 }
1391}
1392
1393pub struct UserDataRefMut<'lua, T: 'static>(#[allow(unused)] AnyUserData<'lua>, RefMut<'lua, T>);
1397
1398impl<'lua, T: 'static> Deref for UserDataRefMut<'lua, T> {
1399 type Target = T;
1400
1401 fn deref(&self) -> &Self::Target {
1402 &self.1
1403 }
1404}
1405
1406impl<'lua, T: 'static> DerefMut for UserDataRefMut<'lua, T> {
1407 fn deref_mut(&mut self) -> &mut Self::Target {
1408 &mut self.1
1409 }
1410}
1411
1412impl<'lua, T: 'static> UserDataRefMut<'lua, T> {
1413 pub(crate) fn from_value(value: Value<'lua>) -> Result<Self> {
1414 let ud = try_value_to_userdata::<T>(value)?;
1415 let this = unsafe { mem::transmute(ud.borrow_mut::<T>()?) };
1417 Ok(UserDataRefMut(ud, this))
1418 }
1419}
1420
1421pub(crate) struct WrappedUserdata<F: for<'lua> FnOnce(&'lua Lua) -> Result<AnyUserData<'lua>>>(F);
1422
1423impl<'lua> AnyUserData<'lua> {
1424 pub fn wrap<T: MaybeSend + 'static>(data: T) -> impl IntoLua<'lua> {
1428 WrappedUserdata(move |lua| lua.create_any_userdata(data))
1429 }
1430}
1431
1432impl<'lua, F> IntoLua<'lua> for WrappedUserdata<F>
1433where
1434 F: for<'l> FnOnce(&'l Lua) -> Result<AnyUserData<'l>>,
1435{
1436 fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
1437 (self.0)(lua).map(Value::UserData)
1438 }
1439}
1440
1441#[inline]
1442fn try_value_to_userdata<T>(value: Value) -> Result<AnyUserData> {
1443 match value {
1444 Value::UserData(ud) => Ok(ud),
1445 _ => Err(Error::FromLuaConversionError {
1446 from: value.type_name(),
1447 to: "userdata",
1448 message: Some(format!("expected userdata of type {}", type_name::<T>())),
1449 }),
1450 }
1451}
1452
1453#[cfg(test)]
1454mod assertions {
1455 use super::*;
1456
1457 static_assertions::assert_not_impl_any!(AnyUserData: Send);
1458
1459 #[cfg(all(feature = "unstable", not(feature = "send")))]
1460 static_assertions::assert_not_impl_any!(OwnedAnyUserData: Send);
1461}