factorio_mlua/
userdata.rs

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/// Kinds of metamethods that can be overridden.
34///
35/// Currently, this mechanism does not allow overriding the `__gc` metamethod, since there is
36/// generally no need to do so: [`UserData`] implementors can instead just implement `Drop`.
37///
38/// [`UserData`]: crate::UserData
39#[derive(Debug, Clone)]
40pub enum MetaMethod {
41    /// The `+` operator.
42    Add,
43    /// The `-` operator.
44    Sub,
45    /// The `*` operator.
46    Mul,
47    /// The `/` operator.
48    Div,
49    /// The `%` operator.
50    Mod,
51    /// The `^` operator.
52    Pow,
53    /// The unary minus (`-`) operator.
54    Unm,
55    /// The floor division (//) operator.
56    /// Requires `feature = "lua54/lua53"`
57    #[cfg(any(feature = "lua54", feature = "lua53"))]
58    IDiv,
59    /// The bitwise AND (&) operator.
60    /// Requires `feature = "lua54/lua53"`
61    #[cfg(any(feature = "lua54", feature = "lua53"))]
62    BAnd,
63    /// The bitwise OR (|) operator.
64    /// Requires `feature = "lua54/lua53"`
65    #[cfg(any(feature = "lua54", feature = "lua53"))]
66    BOr,
67    /// The bitwise XOR (binary ~) operator.
68    /// Requires `feature = "lua54/lua53"`
69    #[cfg(any(feature = "lua54", feature = "lua53"))]
70    BXor,
71    /// The bitwise NOT (unary ~) operator.
72    /// Requires `feature = "lua54/lua53"`
73    #[cfg(any(feature = "lua54", feature = "lua53"))]
74    BNot,
75    /// The bitwise left shift (<<) operator.
76    #[cfg(any(feature = "lua54", feature = "lua53"))]
77    Shl,
78    /// The bitwise right shift (>>) operator.
79    #[cfg(any(feature = "lua54", feature = "lua53"))]
80    Shr,
81    /// The string concatenation operator `..`.
82    Concat,
83    /// The length operator `#`.
84    Len,
85    /// The `==` operator.
86    Eq,
87    /// The `<` operator.
88    Lt,
89    /// The `<=` operator.
90    Le,
91    /// Index access `obj[key]`.
92    Index,
93    /// Index write access `obj[key] = value`.
94    NewIndex,
95    /// The call "operator" `obj(arg1, args2, ...)`.
96    Call,
97    /// The `__tostring` metamethod.
98    ///
99    /// This is not an operator, but will be called by methods such as `tostring` and `print`.
100    ToString,
101    /// The `__pairs` metamethod.
102    ///
103    /// This is not an operator, but it will be called by the built-in `pairs` function.
104    ///
105    /// Requires `feature = "lua54/lua53/lua52/lua-factorio"`
106    #[cfg(any(
107        feature = "lua54",
108        feature = "lua53",
109        feature = "lua52",
110        feature = "luajit52",
111        feature = "lua-factorio",
112    ))]
113    Pairs,
114    /// The `__ipairs` metamethod.
115    ///
116    /// This is not an operator, but it will be called by the built-in [`ipairs`] function.
117    ///
118    /// Requires `feature = "lua52/lua-factorio"`
119    ///
120    /// [`ipairs`]: https://www.lua.org/manual/5.2/manual.html#pdf-ipairs
121    #[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    /// The `__iter` metamethod.
125    ///
126    /// Executed before the iteration begins, and should return an iterator function like `next`
127    /// (or a custom one).
128    ///
129    /// Requires `feature = "lua"`
130    #[cfg(any(feature = "luau", doc))]
131    #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
132    Iter,
133    /// The `__close` metamethod.
134    ///
135    /// Executed when a variable, that marked as to-be-closed, goes out of scope.
136    ///
137    /// More information about to-be-closed variabled can be found in the Lua 5.4
138    /// [documentation][lua_doc].
139    ///
140    /// Requires `feature = "lua54"`
141    ///
142    /// [lua_doc]: https://www.lua.org/manual/5.4/manual.html#3.3.8
143    #[cfg(any(feature = "lua54"))]
144    Close,
145    /// A custom metamethod.
146    ///
147    /// Must not be in the protected list: `__gc`, `__metatable`, `__mlua*`.
148    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    /// Returns Lua metamethod name, usually prefixed by two underscores.
173    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
305/// Method registry for [`UserData`] implementors.
306///
307/// [`UserData`]: crate::UserData
308pub trait UserDataMethods<'lua, T: UserData> {
309    /// Add a regular method which accepts a `&T` as the first parameter.
310    ///
311    /// Regular methods are implemented by overriding the `__index` metamethod and returning the
312    /// accessed method. This allows them to be used with the expected `userdata:method()` syntax.
313    ///
314    /// If `add_meta_method` is used to set the `__index` metamethod, the `__index` metamethod will
315    /// be used as a fall-back if no regular method is found.
316    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    /// Add a regular method which accepts a `&mut T` as the first parameter.
324    ///
325    /// Refer to [`add_method`] for more information about the implementation.
326    ///
327    /// [`add_method`]: #method.add_method
328    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    /// Add an async method which accepts a `T` as the first parameter and returns Future.
336    /// The passed `T` is cloned from the original value.
337    ///
338    /// Refer to [`add_method`] for more information about the implementation.
339    ///
340    /// Requires `feature = "async"`
341    ///
342    /// [`add_method`]: #method.add_method
343    #[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    /// Add a regular method as a function which accepts generic arguments, the first argument will
355    /// be a [`AnyUserData`] of type `T` if the method is called with Lua method syntax:
356    /// `my_userdata:my_method(arg1, arg2)`, or it is passed in as the first argument:
357    /// `my_userdata.my_method(my_userdata, arg1, arg2)`.
358    ///
359    /// Prefer to use [`add_method`] or [`add_method_mut`] as they are easier to use.
360    ///
361    /// [`AnyUserData`]: crate::AnyUserData
362    /// [`add_method`]: #method.add_method
363    /// [`add_method_mut`]: #method.add_method_mut
364    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    /// Add a regular method as a mutable function which accepts generic arguments.
372    ///
373    /// This is a version of [`add_function`] that accepts a FnMut argument.
374    ///
375    /// [`add_function`]: #method.add_function
376    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    /// Add a regular method as an async function which accepts generic arguments
384    /// and returns Future.
385    ///
386    /// This is an async version of [`add_function`].
387    ///
388    /// Requires `feature = "async"`
389    ///
390    /// [`add_function`]: #method.add_function
391    #[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    /// Add a metamethod which accepts a `&T` as the first parameter.
402    ///
403    /// # Note
404    ///
405    /// This can cause an error with certain binary metamethods that can trigger if only the right
406    /// side has a metatable. To prevent this, use [`add_meta_function`].
407    ///
408    /// [`add_meta_function`]: #method.add_meta_function
409    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    /// Add a metamethod as a function which accepts a `&mut T` as the first parameter.
417    ///
418    /// # Note
419    ///
420    /// This can cause an error with certain binary metamethods that can trigger if only the right
421    /// side has a metatable. To prevent this, use [`add_meta_function`].
422    ///
423    /// [`add_meta_function`]: #method.add_meta_function
424    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    /// Add an async metamethod which accepts a `T` as the first parameter and returns Future.
432    /// The passed `T` is cloned from the original value.
433    ///
434    /// This is an async version of [`add_meta_method`].
435    ///
436    /// Requires `feature = "async"`
437    ///
438    /// [`add_meta_method`]: #method.add_meta_method
439    #[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    /// Add a metamethod which accepts generic arguments.
451    ///
452    /// Metamethods for binary operators can be triggered if either the left or right argument to
453    /// the binary operator has a metatable, so the first argument here is not necessarily a
454    /// userdata of type `T`.
455    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    /// Add a metamethod as a mutable function which accepts generic arguments.
463    ///
464    /// This is a version of [`add_meta_function`] that accepts a FnMut argument.
465    ///
466    /// [`add_meta_function`]: #method.add_meta_function
467    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    /// Add a metamethod which accepts generic arguments and returns Future.
475    ///
476    /// This is an async version of [`add_meta_function`].
477    ///
478    /// Requires `feature = "async"`
479    ///
480    /// [`add_meta_function`]: #method.add_meta_function
481    #[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    //
492    // Below are internal methods used in generated code
493    //
494
495    #[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
515/// Field registry for [`UserData`] implementors.
516///
517/// [`UserData`]: crate::UserData
518pub trait UserDataFields<'lua, T: UserData> {
519    /// Add a regular field getter as a method which accepts a `&T` as the parameter.
520    ///
521    /// Regular field getters are implemented by overriding the `__index` metamethod and returning the
522    /// accessed field. This allows them to be used with the expected `userdata.field` syntax.
523    ///
524    /// If `add_meta_method` is used to set the `__index` metamethod, the `__index` metamethod will
525    /// be used as a fall-back if no regular field or method are found.
526    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    /// Add a regular field setter as a method which accepts a `&mut T` as the first parameter.
533    ///
534    /// Regular field setters are implemented by overriding the `__newindex` metamethod and setting the
535    /// accessed field. This allows them to be used with the expected `userdata.field = value` syntax.
536    ///
537    /// If `add_meta_method` is used to set the `__newindex` metamethod, the `__newindex` metamethod will
538    /// be used as a fall-back if no regular field is found.
539    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    /// Add a regular field getter as a function which accepts a generic [`AnyUserData`] of type `T`
546    /// argument.
547    ///
548    /// Prefer to use [`add_field_method_get`] as it is easier to use.
549    ///
550    /// [`AnyUserData`]: crate::AnyUserData
551    /// [`add_field_method_get`]: #method.add_field_method_get
552    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    /// Add a regular field setter as a function which accepts a generic [`AnyUserData`] of type `T`
559    /// first argument.
560    ///
561    /// Prefer to use [`add_field_method_set`] as it is easier to use.
562    ///
563    /// [`AnyUserData`]: crate::AnyUserData
564    /// [`add_field_method_set`]: #method.add_field_method_set
565    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    /// Add a metamethod value computed from `f`.
572    ///
573    /// This will initialize the metamethod value from `f` on `UserData` creation.
574    ///
575    /// # Note
576    ///
577    /// `mlua` will trigger an error on an attempt to define a protected metamethod,
578    /// like `__gc` or `__metatable`.
579    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    //
586    // Below are internal methods used in generated code
587    //
588
589    #[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
596/// Trait for custom userdata types.
597///
598/// By implementing this trait, a struct becomes eligible for use inside Lua code.
599/// Implementation of [`ToLua`] is automatically provided, [`FromLua`] is implemented
600/// only for `T: UserData + Clone`.
601///
602///
603/// # Examples
604///
605/// ```
606/// # use mlua::{Lua, Result, UserData};
607/// # fn main() -> Result<()> {
608/// # let lua = Lua::new();
609/// struct MyUserData(i32);
610///
611/// impl UserData for MyUserData {}
612///
613/// // `MyUserData` now implements `ToLua`:
614/// lua.globals().set("myobject", MyUserData(123))?;
615///
616/// lua.load("assert(type(myobject) == 'userdata')").exec()?;
617/// # Ok(())
618/// # }
619/// ```
620///
621/// Custom fields, methods and operators can be provided by implementing `add_fields` or `add_methods`
622/// (refer to [`UserDataFields`] and [`UserDataMethods`] for more information):
623///
624/// ```
625/// # use mlua::{Lua, MetaMethod, Result, UserData, UserDataFields, UserDataMethods};
626/// # fn main() -> Result<()> {
627/// # let lua = Lua::new();
628/// struct MyUserData(i32);
629///
630/// impl UserData for MyUserData {
631///     fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) {
632///         fields.add_field_method_get("val", |_, this| Ok(this.0));
633///     }
634///
635///     fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
636///         methods.add_method_mut("add", |_, this, value: i32| {
637///             this.0 += value;
638///             Ok(())
639///         });
640///
641///         methods.add_meta_method(MetaMethod::Add, |_, this, value: i32| {
642///             Ok(this.0 + value)
643///         });
644///     }
645/// }
646///
647/// lua.globals().set("myobject", MyUserData(123))?;
648///
649/// lua.load(r#"
650///     assert(myobject.val == 123)
651///     myobject:add(7)
652///     assert(myobject.val == 130)
653///     assert(myobject + 10 == 140)
654/// "#).exec()?;
655/// # Ok(())
656/// # }
657/// ```
658///
659/// [`ToLua`]: crate::ToLua
660/// [`FromLua`]: crate::FromLua
661/// [`UserDataFields`]: crate::UserDataFields
662/// [`UserDataMethods`]: crate::UserDataMethods
663pub trait UserData: Sized {
664    /// Adds custom fields specific to this userdata.
665    fn add_fields<'lua, F: UserDataFields<'lua, Self>>(_fields: &mut F) {}
666
667    /// Adds custom methods and operators specific to this userdata.
668    fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(_methods: &mut M) {}
669}
670
671// Wraps UserData in a way to always implement `serde::Serialize` trait.
672pub(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    // Immutably borrows the wrapped value.
690    #[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    // Mutably borrows the wrapped value.
699    #[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    // Consumes this `UserDataCell`, returning the wrapped value.
708    #[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/// Handle to an internal Lua userdata for any type that implements [`UserData`].
787///
788/// Similar to `std::any::Any`, this provides an interface for dynamic type checking via the [`is`]
789/// and [`borrow`] methods.
790///
791/// Internally, instances are stored in a `RefCell`, to best match the mutable semantics of the Lua
792/// language.
793///
794/// # Note
795///
796/// This API should only be used when necessary. Implementing [`UserData`] already allows defining
797/// methods which check the type and acquire a borrow behind the scenes.
798///
799/// [`UserData`]: crate::UserData
800/// [`is`]: crate::AnyUserData::is
801/// [`borrow`]: crate::AnyUserData::borrow
802#[derive(Clone, Debug)]
803pub struct AnyUserData<'lua>(pub(crate) LuaRef<'lua>);
804
805impl<'lua> AnyUserData<'lua> {
806    /// Checks whether the type of this userdata is `T`.
807    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    /// Borrow this userdata immutably if it is of type `T`.
816    ///
817    /// # Errors
818    ///
819    /// Returns a `UserDataBorrowError` if the userdata is already mutably borrowed. Returns a
820    /// `UserDataTypeMismatch` if the userdata is not of type `T`.
821    #[inline]
822    pub fn borrow<T: 'static + UserData>(&self) -> Result<Ref<T>> {
823        self.inspect(|cell| cell.try_borrow())
824    }
825
826    /// Borrow this userdata mutably if it is of type `T`.
827    ///
828    /// # Errors
829    ///
830    /// Returns a `UserDataBorrowMutError` if the userdata cannot be mutably borrowed.
831    /// Returns a `UserDataTypeMismatch` if the userdata is not of type `T`.
832    #[inline]
833    pub fn borrow_mut<T: 'static + UserData>(&self) -> Result<RefMut<T>> {
834        self.inspect(|cell| cell.try_borrow_mut())
835    }
836
837    /// Takes out the value of `UserData` and sets the special "destructed" metatable that prevents
838    /// any further operations with this userdata.
839    ///
840    /// All associated user values will be also cleared.
841    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                    // Try to borrow userdata exclusively
851                    let _ = (*get_userdata::<UserDataCell<T>>(lua.state, -1)).try_borrow_mut()?;
852
853                    // Clear associated user values
854                    #[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    /// Sets an associated value to this `AnyUserData`.
878    ///
879    /// The value may be any Lua value whatsoever, and can be retrieved with [`get_user_value`].
880    ///
881    /// This is the same as calling [`set_nth_user_value`] with `n` set to 1.
882    ///
883    /// [`get_user_value`]: #method.get_user_value
884    /// [`set_nth_user_value`]: #method.set_nth_user_value
885    #[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    /// Returns an associated value set by [`set_user_value`].
891    ///
892    /// This is the same as calling [`get_nth_user_value`] with `n` set to 1.
893    ///
894    /// [`set_user_value`]: #method.set_user_value
895    /// [`get_nth_user_value`]: #method.get_nth_user_value
896    #[inline]
897    pub fn get_user_value<V: FromLua<'lua>>(&self) -> Result<V> {
898        self.get_nth_user_value(1)
899    }
900
901    /// Sets an associated `n`th value to this `AnyUserData`.
902    ///
903    /// The value may be any Lua value whatsoever, and can be retrieved with [`get_nth_user_value`].
904    /// `n` starts from 1 and can be up to 65535.
905    ///
906    /// This is supported for all Lua versions.
907    /// In Lua 5.4 first 7 elements are stored in a most efficient way.
908    /// For other Lua versions this functionality is provided using a wrapping table.
909    ///
910    /// [`get_nth_user_value`]: #method.get_nth_user_value
911    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            // Multiple (extra) user values are emulated by storing them in a table
933            protect_lua!(lua.state, 2, 0, |state| {
934                if getuservalue_table(state, -2) != ffi::LUA_TTABLE {
935                    // Create a new table to use as uservalue
936                    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    /// Returns an associated `n`th value set by [`set_nth_user_value`].
957    ///
958    /// `n` starts from 1 and can be up to 65535.
959    ///
960    /// This is supported for all Lua versions.
961    /// In Lua 5.4 first 7 elements are stored in a most efficient way.
962    /// For other Lua versions this functionality is provided using a wrapping table.
963    ///
964    /// [`set_nth_user_value`]: #method.set_nth_user_value
965    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            // Multiple (extra) user values are emulated by storing them in a table
986            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    /// Sets an associated value to this `AnyUserData` by name.
1002    ///
1003    /// The value can be retrieved with [`get_named_user_value`].
1004    ///
1005    /// [`get_named_user_value`]: #method.get_named_user_value
1006    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            // Multiple (extra) user values are emulated by storing them in a table
1020            let name = name.as_ref();
1021            protect_lua!(lua.state, 2, 0, |state| {
1022                if getuservalue_table(state, -2) != ffi::LUA_TTABLE {
1023                    // Create a new table to use as uservalue
1024                    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    /// Returns an associated value by name set by [`set_named_user_value`].
1043    ///
1044    /// [`set_named_user_value`]: #method.set_named_user_value
1045    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            // Multiple (extra) user values are emulated by storing them in a table
1058            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    /// Returns a metatable of this `UserData`.
1073    ///
1074    /// Returned [`UserDataMetatable`] object wraps the original metatable and
1075    /// provides safe access to its methods.
1076    ///
1077    /// For `T: UserData + 'static` returned metatable is shared among all instances of type `T`.
1078    ///
1079    /// [`UserDataMetatable`]: crate::UserDataMetatable
1080    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); // Checked that non-empty on the previous call
1092            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        // Uses lua_rawequal() under the hood
1099        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/// Handle to a `UserData` metatable.
1159#[derive(Clone, Debug)]
1160pub struct UserDataMetatable<'lua>(pub(crate) Table<'lua>);
1161
1162impl<'lua> UserDataMetatable<'lua> {
1163    /// Gets the value associated to `key` from the metatable.
1164    ///
1165    /// If no value is associated to `key`, returns the `Nil` value.
1166    /// Access to restricted metamethods such as `__gc` or `__metatable` will cause an error.
1167    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    /// Sets a key-value pair in the metatable.
1172    ///
1173    /// If the value is `Nil`, this will effectively remove the `key`.
1174    /// Access to restricted metamethods such as `__gc` or `__metatable` will cause an error.
1175    /// Setting `__index` or `__newindex` metamethods is also restricted because their values are cached
1176    /// for `mlua` internal usage.
1177    pub fn set<K: Into<MetaMethod>, V: ToLua<'lua>>(&self, key: K, value: V) -> Result<()> {
1178        let key = key.into().validate()?;
1179        // `__index` and `__newindex` cannot be changed in runtime, because values are cached
1180        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    /// Checks whether the metatable contains a non-nil value for `key`.
1187    pub fn contains<K: Into<MetaMethod>>(&self, key: K) -> Result<bool> {
1188        self.0.contains_key(key.into().validate()?.name())
1189    }
1190
1191    /// Consumes this metatable and returns an iterator over the pairs of the metatable.
1192    ///
1193    /// The pairs are wrapped in a [`Result`], since they are lazily converted to `V` type.
1194    ///
1195    /// [`Result`]: crate::Result
1196    pub fn pairs<V: FromLua<'lua>>(self) -> UserDataMetatablePairs<'lua, V> {
1197        UserDataMetatablePairs(self.0.pairs())
1198    }
1199}
1200
1201/// An iterator over the pairs of a [`UserData`] metatable.
1202///
1203/// It skips restricted metamethods, such as `__gc` or `__metatable`.
1204///
1205/// This struct is created by the [`UserDataMetatable::pairs`] method.
1206///
1207/// [`UserData`]: crate::UserData
1208/// [`UserDataMetatable::pairs`]: crate::UserDataMetatable::method.pairs
1209pub 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                    // Skip restricted metamethods
1222                    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}