1use std::any::TypeId;
2use std::cell::{Ref, RefCell, RefMut};
3use std::fmt;
4use std::hash::{Hash, Hasher};
5use std::ops::{Deref, DerefMut};
6use std::os::raw::{c_char, c_int};
7use std::string::String as StdString;
8
9#[cfg(feature = "async")]
10use std::future::Future;
11
12#[cfg(feature = "serialize")]
13use {
14 serde::ser::{self, Serialize, Serializer},
15 std::result::Result as StdResult,
16};
17
18use crate::error::{Error, Result};
19use crate::ffi;
20use crate::function::Function;
21use crate::lua::Lua;
22use crate::table::{Table, TablePairs};
23use crate::types::{Callback, LuaRef, MaybeSend};
24use crate::util::{check_stack, get_userdata, take_userdata, StackGuard};
25use crate::value::{FromLua, FromLuaMulti, ToLua, ToLuaMulti};
26
27#[cfg(feature = "async")]
28use crate::types::AsyncCallback;
29
30#[cfg(feature = "lua54")]
31pub(crate) const USER_VALUE_MAXSLOT: usize = 8;
32
33#[derive(Debug, Clone)]
40pub enum MetaMethod {
41 Add,
43 Sub,
45 Mul,
47 Div,
49 Mod,
51 Pow,
53 Unm,
55 #[cfg(any(feature = "lua54", feature = "lua53"))]
58 IDiv,
59 #[cfg(any(feature = "lua54", feature = "lua53"))]
62 BAnd,
63 #[cfg(any(feature = "lua54", feature = "lua53"))]
66 BOr,
67 #[cfg(any(feature = "lua54", feature = "lua53"))]
70 BXor,
71 #[cfg(any(feature = "lua54", feature = "lua53"))]
74 BNot,
75 #[cfg(any(feature = "lua54", feature = "lua53"))]
77 Shl,
78 #[cfg(any(feature = "lua54", feature = "lua53"))]
80 Shr,
81 Concat,
83 Len,
85 Eq,
87 Lt,
89 Le,
91 Index,
93 NewIndex,
95 Call,
97 ToString,
101 #[cfg(any(
107 feature = "lua54",
108 feature = "lua53",
109 feature = "lua52",
110 feature = "luajit52",
111 feature = "lua-factorio",
112 ))]
113 Pairs,
114 #[cfg(any(feature = "lua52", feature = "luajit52", feature = "lua-factorio", doc))]
122 #[cfg_attr(docsrs, doc(cfg(any(feature = "lua52", feature = "luajit52", feature = "lua-factorio"))))]
123 IPairs,
124 #[cfg(any(feature = "luau", doc))]
131 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
132 Iter,
133 #[cfg(any(feature = "lua54"))]
144 Close,
145 Custom(StdString),
149}
150
151impl PartialEq for MetaMethod {
152 fn eq(&self, other: &Self) -> bool {
153 self.name() == other.name()
154 }
155}
156
157impl Eq for MetaMethod {}
158
159impl Hash for MetaMethod {
160 fn hash<H: Hasher>(&self, state: &mut H) {
161 self.name().hash(state);
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 fn name(&self) -> &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"))]
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 feature = "lua-factorio"
214 ))]
215 MetaMethod::Pairs => "__pairs",
216 #[cfg(any(feature = "lua52", feature = "luajit52", feature = "lua-factorio"))]
217 MetaMethod::IPairs => "__ipairs",
218 #[cfg(feature = "luau")]
219 MetaMethod::Iter => "__iter",
220
221 #[cfg(feature = "lua54")]
222 MetaMethod::Close => "__close",
223
224 MetaMethod::Custom(ref name) => name,
225 }
226 }
227
228 pub(crate) fn validate(self) -> Result<Self> {
229 match self {
230 MetaMethod::Custom(name) if name == "__gc" => Err(Error::MetaMethodRestricted(name)),
231 MetaMethod::Custom(name) if name == "__metatable" => {
232 Err(Error::MetaMethodRestricted(name))
233 }
234 MetaMethod::Custom(name) if name.starts_with("__mlua") => {
235 Err(Error::MetaMethodRestricted(name))
236 }
237 _ => Ok(self),
238 }
239 }
240}
241
242impl From<StdString> for MetaMethod {
243 fn from(name: StdString) -> Self {
244 match name.as_str() {
245 "__add" => MetaMethod::Add,
246 "__sub" => MetaMethod::Sub,
247 "__mul" => MetaMethod::Mul,
248 "__div" => MetaMethod::Div,
249 "__mod" => MetaMethod::Mod,
250 "__pow" => MetaMethod::Pow,
251 "__unm" => MetaMethod::Unm,
252
253 #[cfg(any(feature = "lua54", feature = "lua53"))]
254 "__idiv" => MetaMethod::IDiv,
255 #[cfg(any(feature = "lua54", feature = "lua53"))]
256 "__band" => MetaMethod::BAnd,
257 #[cfg(any(feature = "lua54", feature = "lua53"))]
258 "__bor" => MetaMethod::BOr,
259 #[cfg(any(feature = "lua54", feature = "lua53"))]
260 "__bxor" => MetaMethod::BXor,
261 #[cfg(any(feature = "lua54", feature = "lua53"))]
262 "__bnot" => MetaMethod::BNot,
263 #[cfg(any(feature = "lua54", feature = "lua53"))]
264 "__shl" => MetaMethod::Shl,
265 #[cfg(any(feature = "lua54", feature = "lua53"))]
266 "__shr" => MetaMethod::Shr,
267
268 "__concat" => MetaMethod::Concat,
269 "__len" => MetaMethod::Len,
270 "__eq" => MetaMethod::Eq,
271 "__lt" => MetaMethod::Lt,
272 "__le" => MetaMethod::Le,
273 "__index" => MetaMethod::Index,
274 "__newindex" => MetaMethod::NewIndex,
275 "__call" => MetaMethod::Call,
276 "__tostring" => MetaMethod::ToString,
277
278 #[cfg(any(
279 feature = "lua54",
280 feature = "lua53",
281 feature = "lua52",
282 feature = "luajit52",
283 feature = "lua-factorio"
284 ))]
285 "__pairs" => MetaMethod::Pairs,
286 #[cfg(any(feature = "lua52", feature = "luajit52", feature = "lua-factorio"))]
287 "__ipairs" => MetaMethod::IPairs,
288 #[cfg(feature = "luau")]
289 "__iter" => MetaMethod::Iter,
290
291 #[cfg(feature = "lua54")]
292 "__close" => MetaMethod::Close,
293
294 _ => MetaMethod::Custom(name),
295 }
296 }
297}
298
299impl From<&str> for MetaMethod {
300 fn from(name: &str) -> Self {
301 MetaMethod::from(name.to_owned())
302 }
303}
304
305pub trait UserDataMethods<'lua, T: UserData> {
309 fn add_method<S, A, R, M>(&mut self, name: &S, method: M)
317 where
318 S: AsRef<[u8]> + ?Sized,
319 A: FromLuaMulti<'lua>,
320 R: ToLuaMulti<'lua>,
321 M: 'static + MaybeSend + Fn(&'lua Lua, &T, A) -> Result<R>;
322
323 fn add_method_mut<S, A, R, M>(&mut self, name: &S, method: M)
329 where
330 S: AsRef<[u8]> + ?Sized,
331 A: FromLuaMulti<'lua>,
332 R: ToLuaMulti<'lua>,
333 M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<R>;
334
335 #[cfg(feature = "async")]
344 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
345 fn add_async_method<S, A, R, M, MR>(&mut self, name: &S, method: M)
346 where
347 T: Clone,
348 S: AsRef<[u8]> + ?Sized,
349 A: FromLuaMulti<'lua>,
350 R: ToLuaMulti<'lua>,
351 M: 'static + MaybeSend + Fn(&'lua Lua, T, A) -> MR,
352 MR: 'lua + Future<Output = Result<R>>;
353
354 fn add_function<S, A, R, F>(&mut self, name: &S, function: F)
365 where
366 S: AsRef<[u8]> + ?Sized,
367 A: FromLuaMulti<'lua>,
368 R: ToLuaMulti<'lua>,
369 F: 'static + MaybeSend + Fn(&'lua Lua, A) -> Result<R>;
370
371 fn add_function_mut<S, A, R, F>(&mut self, name: &S, function: F)
377 where
378 S: AsRef<[u8]> + ?Sized,
379 A: FromLuaMulti<'lua>,
380 R: ToLuaMulti<'lua>,
381 F: 'static + MaybeSend + FnMut(&'lua Lua, A) -> Result<R>;
382
383 #[cfg(feature = "async")]
392 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
393 fn add_async_function<S, A, R, F, FR>(&mut self, name: &S, function: F)
394 where
395 S: AsRef<[u8]> + ?Sized,
396 A: FromLuaMulti<'lua>,
397 R: ToLuaMulti<'lua>,
398 F: 'static + MaybeSend + Fn(&'lua Lua, A) -> FR,
399 FR: 'lua + Future<Output = Result<R>>;
400
401 fn add_meta_method<S, A, R, M>(&mut self, meta: S, method: M)
410 where
411 S: Into<MetaMethod>,
412 A: FromLuaMulti<'lua>,
413 R: ToLuaMulti<'lua>,
414 M: 'static + MaybeSend + Fn(&'lua Lua, &T, A) -> Result<R>;
415
416 fn add_meta_method_mut<S, A, R, M>(&mut self, meta: S, method: M)
425 where
426 S: Into<MetaMethod>,
427 A: FromLuaMulti<'lua>,
428 R: ToLuaMulti<'lua>,
429 M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<R>;
430
431 #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
440 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
441 fn add_async_meta_method<S, A, R, M, MR>(&mut self, name: S, method: M)
442 where
443 T: Clone,
444 S: Into<MetaMethod>,
445 A: FromLuaMulti<'lua>,
446 R: ToLuaMulti<'lua>,
447 M: 'static + MaybeSend + Fn(&'lua Lua, T, A) -> MR,
448 MR: 'lua + Future<Output = Result<R>>;
449
450 fn add_meta_function<S, A, R, F>(&mut self, meta: S, function: F)
456 where
457 S: Into<MetaMethod>,
458 A: FromLuaMulti<'lua>,
459 R: ToLuaMulti<'lua>,
460 F: 'static + MaybeSend + Fn(&'lua Lua, A) -> Result<R>;
461
462 fn add_meta_function_mut<S, A, R, F>(&mut self, meta: S, function: F)
468 where
469 S: Into<MetaMethod>,
470 A: FromLuaMulti<'lua>,
471 R: ToLuaMulti<'lua>,
472 F: 'static + MaybeSend + FnMut(&'lua Lua, A) -> Result<R>;
473
474 #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
482 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
483 fn add_async_meta_function<S, A, R, F, FR>(&mut self, name: S, function: F)
484 where
485 S: Into<MetaMethod>,
486 A: FromLuaMulti<'lua>,
487 R: ToLuaMulti<'lua>,
488 F: 'static + MaybeSend + Fn(&'lua Lua, A) -> FR,
489 FR: 'lua + Future<Output = Result<R>>;
490
491 #[doc(hidden)]
496 fn add_callback(&mut self, _name: Vec<u8>, _callback: Callback<'lua, 'static>) {}
497
498 #[doc(hidden)]
499 #[cfg(feature = "async")]
500 fn add_async_callback(&mut self, _name: Vec<u8>, _callback: AsyncCallback<'lua, 'static>) {}
501
502 #[doc(hidden)]
503 fn add_meta_callback(&mut self, _meta: MetaMethod, _callback: Callback<'lua, 'static>) {}
504
505 #[doc(hidden)]
506 #[cfg(feature = "async")]
507 fn add_async_meta_callback(
508 &mut self,
509 _meta: MetaMethod,
510 _callback: AsyncCallback<'lua, 'static>,
511 ) {
512 }
513}
514
515pub trait UserDataFields<'lua, T: UserData> {
519 fn add_field_method_get<S, R, M>(&mut self, name: &S, method: M)
527 where
528 S: AsRef<[u8]> + ?Sized,
529 R: ToLua<'lua>,
530 M: 'static + MaybeSend + Fn(&'lua Lua, &T) -> Result<R>;
531
532 fn add_field_method_set<S, A, M>(&mut self, name: &S, method: M)
540 where
541 S: AsRef<[u8]> + ?Sized,
542 A: FromLua<'lua>,
543 M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<()>;
544
545 fn add_field_function_get<S, R, F>(&mut self, name: &S, function: F)
553 where
554 S: AsRef<[u8]> + ?Sized,
555 R: ToLua<'lua>,
556 F: 'static + MaybeSend + Fn(&'lua Lua, AnyUserData<'lua>) -> Result<R>;
557
558 fn add_field_function_set<S, A, F>(&mut self, name: &S, function: F)
566 where
567 S: AsRef<[u8]> + ?Sized,
568 A: FromLua<'lua>,
569 F: 'static + MaybeSend + FnMut(&'lua Lua, AnyUserData<'lua>, A) -> Result<()>;
570
571 fn add_meta_field_with<S, R, F>(&mut self, meta: S, f: F)
580 where
581 S: Into<MetaMethod>,
582 F: 'static + MaybeSend + Fn(&'lua Lua) -> Result<R>,
583 R: ToLua<'lua>;
584
585 #[doc(hidden)]
590 fn add_field_getter(&mut self, _name: Vec<u8>, _callback: Callback<'lua, 'static>) {}
591
592 #[doc(hidden)]
593 fn add_field_setter(&mut self, _name: Vec<u8>, _callback: Callback<'lua, 'static>) {}
594}
595
596pub trait UserData: Sized {
664 fn add_fields<'lua, F: UserDataFields<'lua, Self>>(_fields: &mut F) {}
666
667 fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(_methods: &mut M) {}
669}
670
671pub(crate) struct UserDataCell<T>(RefCell<UserDataWrapped<T>>);
673
674impl<T> UserDataCell<T> {
675 #[inline]
676 pub(crate) fn new(data: T) -> Self {
677 UserDataCell(RefCell::new(UserDataWrapped::new(data)))
678 }
679
680 #[cfg(feature = "serialize")]
681 #[inline]
682 pub(crate) fn new_ser(data: T) -> Self
683 where
684 T: 'static + Serialize,
685 {
686 UserDataCell(RefCell::new(UserDataWrapped::new_ser(data)))
687 }
688
689 #[inline]
691 pub(crate) fn try_borrow(&self) -> Result<Ref<T>> {
692 self.0
693 .try_borrow()
694 .map(|r| Ref::map(r, |r| r.deref()))
695 .map_err(|_| Error::UserDataBorrowError)
696 }
697
698 #[inline]
700 pub(crate) fn try_borrow_mut(&self) -> Result<RefMut<T>> {
701 self.0
702 .try_borrow_mut()
703 .map(|r| RefMut::map(r, |r| r.deref_mut()))
704 .map_err(|_| Error::UserDataBorrowMutError)
705 }
706
707 #[inline]
709 fn into_inner(self) -> T {
710 self.0.into_inner().into_inner()
711 }
712}
713
714pub(crate) enum UserDataWrapped<T> {
715 Default(Box<T>),
716 #[cfg(feature = "serialize")]
717 Serializable(Box<dyn erased_serde::Serialize>),
718}
719
720impl<T> UserDataWrapped<T> {
721 #[inline]
722 fn new(data: T) -> Self {
723 UserDataWrapped::Default(Box::new(data))
724 }
725
726 #[cfg(feature = "serialize")]
727 #[inline]
728 fn new_ser(data: T) -> Self
729 where
730 T: 'static + Serialize,
731 {
732 UserDataWrapped::Serializable(Box::new(data))
733 }
734
735 #[inline]
736 fn into_inner(self) -> T {
737 match self {
738 Self::Default(data) => *data,
739 #[cfg(feature = "serialize")]
740 Self::Serializable(data) => unsafe { *Box::from_raw(Box::into_raw(data) as *mut T) },
741 }
742 }
743}
744
745impl<T> Deref for UserDataWrapped<T> {
746 type Target = T;
747
748 #[inline]
749 fn deref(&self) -> &Self::Target {
750 match self {
751 Self::Default(data) => data,
752 #[cfg(feature = "serialize")]
753 Self::Serializable(data) => unsafe {
754 &*(data.as_ref() as *const _ as *const Self::Target)
755 },
756 }
757 }
758}
759
760impl<T> DerefMut for UserDataWrapped<T> {
761 #[inline]
762 fn deref_mut(&mut self) -> &mut Self::Target {
763 match self {
764 Self::Default(data) => data,
765 #[cfg(feature = "serialize")]
766 Self::Serializable(data) => unsafe {
767 &mut *(data.as_mut() as *mut _ as *mut Self::Target)
768 },
769 }
770 }
771}
772
773#[cfg(feature = "serialize")]
774struct UserDataSerializeError;
775
776#[cfg(feature = "serialize")]
777impl Serialize for UserDataSerializeError {
778 fn serialize<S>(&self, _serializer: S) -> StdResult<S::Ok, S::Error>
779 where
780 S: Serializer,
781 {
782 Err(ser::Error::custom("cannot serialize <userdata>"))
783 }
784}
785
786#[derive(Clone, Debug)]
803pub struct AnyUserData<'lua>(pub(crate) LuaRef<'lua>);
804
805impl<'lua> AnyUserData<'lua> {
806 pub fn is<T: 'static + UserData>(&self) -> bool {
808 match self.inspect(|_: &UserDataCell<T>| Ok(())) {
809 Ok(()) => true,
810 Err(Error::UserDataTypeMismatch) => false,
811 Err(_) => unreachable!(),
812 }
813 }
814
815 #[inline]
822 pub fn borrow<T: 'static + UserData>(&self) -> Result<Ref<T>> {
823 self.inspect(|cell| cell.try_borrow())
824 }
825
826 #[inline]
833 pub fn borrow_mut<T: 'static + UserData>(&self) -> Result<RefMut<T>> {
834 self.inspect(|cell| cell.try_borrow_mut())
835 }
836
837 pub fn take<T: 'static + UserData>(&self) -> Result<T> {
842 let lua = self.0.lua;
843 unsafe {
844 let _sg = StackGuard::new(lua.state);
845 check_stack(lua.state, 3)?;
846
847 let type_id = lua.push_userdata_ref(&self.0)?;
848 match type_id {
849 Some(type_id) if type_id == TypeId::of::<T>() => {
850 let _ = (*get_userdata::<UserDataCell<T>>(lua.state, -1)).try_borrow_mut()?;
852
853 #[cfg(feature = "lua54")]
855 for i in 1..=USER_VALUE_MAXSLOT {
856 ffi::lua_pushnil(lua.state);
857 ffi::lua_setiuservalue(lua.state, -2, i as c_int);
858 }
859 #[cfg(any(feature = "lua53", feature = "lua52", feature = "luau"))]
860 {
861 ffi::lua_pushnil(lua.state);
862 ffi::lua_setuservalue(lua.state, -2);
863 }
864 #[cfg(any(feature = "lua51", feature = "luajit"))]
865 protect_lua!(lua.state, 1, 1, fn(state) {
866 ffi::lua_newtable(state);
867 ffi::lua_setuservalue(state, -2);
868 })?;
869
870 Ok(take_userdata::<UserDataCell<T>>(lua.state).into_inner())
871 }
872 _ => Err(Error::UserDataTypeMismatch),
873 }
874 }
875 }
876
877 #[inline]
886 pub fn set_user_value<V: ToLua<'lua>>(&self, v: V) -> Result<()> {
887 self.set_nth_user_value(1, v)
888 }
889
890 #[inline]
897 pub fn get_user_value<V: FromLua<'lua>>(&self) -> Result<V> {
898 self.get_nth_user_value(1)
899 }
900
901 pub fn set_nth_user_value<V: ToLua<'lua>>(&self, n: usize, v: V) -> Result<()> {
912 if n < 1 || n > u16::MAX as usize {
913 return Err(Error::RuntimeError(
914 "user value index out of bounds".to_string(),
915 ));
916 }
917
918 let lua = self.0.lua;
919 unsafe {
920 let _sg = StackGuard::new(lua.state);
921 check_stack(lua.state, 5)?;
922
923 lua.push_userdata_ref(&self.0)?;
924 lua.push_value(v.to_lua(lua)?)?;
925
926 #[cfg(feature = "lua54")]
927 if n < USER_VALUE_MAXSLOT {
928 ffi::lua_setiuservalue(lua.state, -2, n as c_int);
929 return Ok(());
930 }
931
932 protect_lua!(lua.state, 2, 0, |state| {
934 if getuservalue_table(state, -2) != ffi::LUA_TTABLE {
935 ffi::lua_pop(state, 1);
937 ffi::lua_newtable(state);
938 ffi::lua_pushvalue(state, -1);
939
940 #[cfg(feature = "lua54")]
941 ffi::lua_setiuservalue(state, -4, USER_VALUE_MAXSLOT as c_int);
942 #[cfg(not(feature = "lua54"))]
943 ffi::lua_setuservalue(state, -4);
944 }
945 ffi::lua_pushvalue(state, -2);
946 #[cfg(feature = "lua54")]
947 ffi::lua_rawseti(state, -2, (n - USER_VALUE_MAXSLOT + 1) as ffi::lua_Integer);
948 #[cfg(not(feature = "lua54"))]
949 ffi::lua_rawseti(state, -2, n as ffi::lua_Integer);
950 })?;
951
952 Ok(())
953 }
954 }
955
956 pub fn get_nth_user_value<V: FromLua<'lua>>(&self, n: usize) -> Result<V> {
966 if n < 1 || n > u16::MAX as usize {
967 return Err(Error::RuntimeError(
968 "user value index out of bounds".to_string(),
969 ));
970 }
971
972 let lua = self.0.lua;
973 unsafe {
974 let _sg = StackGuard::new(lua.state);
975 check_stack(lua.state, 4)?;
976
977 lua.push_userdata_ref(&self.0)?;
978
979 #[cfg(feature = "lua54")]
980 if n < USER_VALUE_MAXSLOT {
981 ffi::lua_getiuservalue(lua.state, -1, n as c_int);
982 return V::from_lua(lua.pop_value(), lua);
983 }
984
985 protect_lua!(lua.state, 1, 1, |state| {
987 if getuservalue_table(state, -1) != ffi::LUA_TTABLE {
988 ffi::lua_pushnil(state);
989 return;
990 }
991 #[cfg(feature = "lua54")]
992 ffi::lua_rawgeti(state, -1, (n - USER_VALUE_MAXSLOT + 1) as ffi::lua_Integer);
993 #[cfg(not(feature = "lua54"))]
994 ffi::lua_rawgeti(state, -1, n as ffi::lua_Integer);
995 })?;
996
997 V::from_lua(lua.pop_value(), lua)
998 }
999 }
1000
1001 pub fn set_named_user_value<S, V>(&self, name: &S, v: V) -> Result<()>
1007 where
1008 S: AsRef<[u8]> + ?Sized,
1009 V: ToLua<'lua>,
1010 {
1011 let lua = self.0.lua;
1012 unsafe {
1013 let _sg = StackGuard::new(lua.state);
1014 check_stack(lua.state, 5)?;
1015
1016 lua.push_userdata_ref(&self.0)?;
1017 lua.push_value(v.to_lua(lua)?)?;
1018
1019 let name = name.as_ref();
1021 protect_lua!(lua.state, 2, 0, |state| {
1022 if getuservalue_table(state, -2) != ffi::LUA_TTABLE {
1023 ffi::lua_pop(state, 1);
1025 ffi::lua_newtable(state);
1026 ffi::lua_pushvalue(state, -1);
1027
1028 #[cfg(feature = "lua54")]
1029 ffi::lua_setiuservalue(state, -4, USER_VALUE_MAXSLOT as c_int);
1030 #[cfg(not(feature = "lua54"))]
1031 ffi::lua_setuservalue(state, -4);
1032 }
1033 ffi::lua_pushlstring(state, name.as_ptr() as *const c_char, name.len());
1034 ffi::lua_pushvalue(state, -3);
1035 ffi::lua_rawset(state, -3);
1036 })?;
1037
1038 Ok(())
1039 }
1040 }
1041
1042 pub fn get_named_user_value<S, V>(&self, name: &S) -> Result<V>
1046 where
1047 S: AsRef<[u8]> + ?Sized,
1048 V: FromLua<'lua>,
1049 {
1050 let lua = self.0.lua;
1051 unsafe {
1052 let _sg = StackGuard::new(lua.state);
1053 check_stack(lua.state, 4)?;
1054
1055 lua.push_userdata_ref(&self.0)?;
1056
1057 let name = name.as_ref();
1059 protect_lua!(lua.state, 1, 1, |state| {
1060 if getuservalue_table(state, -1) != ffi::LUA_TTABLE {
1061 ffi::lua_pushnil(state);
1062 return;
1063 }
1064 ffi::lua_pushlstring(state, name.as_ptr() as *const c_char, name.len());
1065 ffi::lua_rawget(state, -2);
1066 })?;
1067
1068 V::from_lua(lua.pop_value(), lua)
1069 }
1070 }
1071
1072 pub fn get_metatable(&self) -> Result<UserDataMetatable<'lua>> {
1081 self.get_raw_metatable().map(UserDataMetatable)
1082 }
1083
1084 fn get_raw_metatable(&self) -> Result<Table<'lua>> {
1085 unsafe {
1086 let lua = self.0.lua;
1087 let _sg = StackGuard::new(lua.state);
1088 check_stack(lua.state, 3)?;
1089
1090 lua.push_userdata_ref(&self.0)?;
1091 ffi::lua_getmetatable(lua.state, -1); Ok(Table(lua.pop_ref()))
1093 }
1094 }
1095
1096 pub(crate) fn equals<T: AsRef<Self>>(&self, other: T) -> Result<bool> {
1097 let other = other.as_ref();
1098 if self == other {
1100 return Ok(true);
1101 }
1102
1103 let mt = self.get_raw_metatable()?;
1104 if mt != other.get_raw_metatable()? {
1105 return Ok(false);
1106 }
1107
1108 if mt.contains_key("__eq")? {
1109 return mt
1110 .get::<_, Function>("__eq")?
1111 .call((self.clone(), other.clone()));
1112 }
1113
1114 Ok(false)
1115 }
1116
1117 fn inspect<'a, T, R, F>(&'a self, func: F) -> Result<R>
1118 where
1119 T: 'static + UserData,
1120 F: FnOnce(&'a UserDataCell<T>) -> Result<R>,
1121 {
1122 let lua = self.0.lua;
1123 unsafe {
1124 let _sg = StackGuard::new(lua.state);
1125 check_stack(lua.state, 2)?;
1126
1127 let type_id = lua.push_userdata_ref(&self.0)?;
1128 match type_id {
1129 Some(type_id) if type_id == TypeId::of::<T>() => {
1130 func(&*get_userdata::<UserDataCell<T>>(lua.state, -1))
1131 }
1132 _ => Err(Error::UserDataTypeMismatch),
1133 }
1134 }
1135 }
1136}
1137
1138impl<'lua> PartialEq for AnyUserData<'lua> {
1139 fn eq(&self, other: &Self) -> bool {
1140 self.0 == other.0
1141 }
1142}
1143
1144impl<'lua> AsRef<AnyUserData<'lua>> for AnyUserData<'lua> {
1145 #[inline]
1146 fn as_ref(&self) -> &Self {
1147 self
1148 }
1149}
1150
1151unsafe fn getuservalue_table(state: *mut ffi::lua_State, idx: c_int) -> c_int {
1152 #[cfg(feature = "lua54")]
1153 return ffi::lua_getiuservalue(state, idx, USER_VALUE_MAXSLOT as c_int);
1154 #[cfg(not(feature = "lua54"))]
1155 return ffi::lua_getuservalue(state, idx);
1156}
1157
1158#[derive(Clone, Debug)]
1160pub struct UserDataMetatable<'lua>(pub(crate) Table<'lua>);
1161
1162impl<'lua> UserDataMetatable<'lua> {
1163 pub fn get<K: Into<MetaMethod>, V: FromLua<'lua>>(&self, key: K) -> Result<V> {
1168 self.0.raw_get(key.into().validate()?.name())
1169 }
1170
1171 pub fn set<K: Into<MetaMethod>, V: ToLua<'lua>>(&self, key: K, value: V) -> Result<()> {
1178 let key = key.into().validate()?;
1179 if key == MetaMethod::Index || key == MetaMethod::NewIndex {
1181 return Err(Error::MetaMethodRestricted(key.to_string()));
1182 }
1183 self.0.raw_set(key.name(), value)
1184 }
1185
1186 pub fn contains<K: Into<MetaMethod>>(&self, key: K) -> Result<bool> {
1188 self.0.contains_key(key.into().validate()?.name())
1189 }
1190
1191 pub fn pairs<V: FromLua<'lua>>(self) -> UserDataMetatablePairs<'lua, V> {
1197 UserDataMetatablePairs(self.0.pairs())
1198 }
1199}
1200
1201pub struct UserDataMetatablePairs<'lua, V>(TablePairs<'lua, StdString, V>);
1210
1211impl<'lua, V> Iterator for UserDataMetatablePairs<'lua, V>
1212where
1213 V: FromLua<'lua>,
1214{
1215 type Item = Result<(MetaMethod, V)>;
1216
1217 fn next(&mut self) -> Option<Self::Item> {
1218 loop {
1219 match self.0.next()? {
1220 Ok((key, value)) => {
1221 if let Ok(metamethod) = MetaMethod::from(key).validate() {
1223 break Some(Ok((metamethod, value)));
1224 }
1225 }
1226 Err(e) => break Some(Err(e)),
1227 }
1228 }
1229 }
1230}
1231
1232#[cfg(feature = "serialize")]
1233impl<'lua> Serialize for AnyUserData<'lua> {
1234 fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
1235 where
1236 S: Serializer,
1237 {
1238 let lua = self.0.lua;
1239 let data = unsafe {
1240 let _sg = StackGuard::new(lua.state);
1241 check_stack(lua.state, 3).map_err(ser::Error::custom)?;
1242
1243 lua.push_userdata_ref(&self.0).map_err(ser::Error::custom)?;
1244 let ud = &*get_userdata::<UserDataCell<()>>(lua.state, -1);
1245 ud.0.try_borrow()
1246 .map_err(|_| ser::Error::custom(Error::UserDataBorrowError))?
1247 };
1248 match &*data {
1249 UserDataWrapped::Default(_) => UserDataSerializeError.serialize(serializer),
1250 UserDataWrapped::Serializable(ser) => ser.serialize(serializer),
1251 }
1252 }
1253}