Skip to main content

mlua/
userdata.rs

1//! Lua userdata handling.
2//!
3//! This module provides types for creating and working with Lua userdata from Rust.
4//!
5//! # Main Types
6//!
7//! - [`AnyUserData`] - A handle to a Lua userdata value of any Rust type.
8//! - [`UserData`] - Trait to implement for types that should be exposed to Lua as userdata.
9//! - [`UserDataFields`] - Trait for registering fields on userdata types.
10//! - [`UserDataMethods`] - Trait for registering methods on userdata types.
11//! - [`UserDataRegistry`] - Registry for userdata methods and fields.
12//! - [`UserDataMetatable`] - A handle to the metatable of a userdata type.
13//! - [`UserDataRef`] - A borrowed reference to a userdata value.
14//! - [`UserDataRefMut`] - A mutably borrowed reference to a userdata value.
15//! - [`MetaMethod`] - Metamethod names for customizing Lua operators.
16
17use std::any::TypeId;
18use std::ffi::CStr;
19use std::fmt;
20use std::hash::Hash;
21use std::os::raw::{c_char, c_void};
22
23use crate::error::{Error, Result};
24use crate::function::Function;
25use crate::state::Lua;
26use crate::string::LuaString;
27use crate::table::{Table, TablePairs};
28use crate::traits::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti};
29use crate::types::{MaybeSend, MaybeSync, ValueRef};
30use crate::util::{StackGuard, check_stack, get_userdata, push_string, short_type_name, take_userdata};
31use crate::value::Value;
32
33#[cfg(feature = "async")]
34use std::future::Future;
35
36#[cfg(feature = "serde")]
37use {
38    serde::ser::{self, Serialize, Serializer},
39    std::result::Result as StdResult,
40};
41
42// Re-export for convenience
43pub(crate) use cell::UserDataStorage;
44pub use r#ref::{UserDataRef, UserDataRefMut};
45pub use registry::UserDataRegistry;
46pub(crate) use registry::{RawUserDataRegistry, UserDataProxy};
47pub(crate) use util::{
48    TypeIdHints, borrow_userdata_scoped, borrow_userdata_scoped_mut, collect_userdata,
49    init_userdata_metatable,
50};
51
52/// Kinds of metamethods that can be overridden.
53///
54/// Currently, this mechanism does not allow overriding the `__gc` metamethod, since there is
55/// generally no need to do so: [`UserData`] implementors can instead just implement `Drop`.
56#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
57#[non_exhaustive]
58pub enum MetaMethod {
59    /// The `+` operator.
60    Add,
61    /// The `-` operator.
62    Sub,
63    /// The `*` operator.
64    Mul,
65    /// The `/` operator.
66    Div,
67    /// The `%` operator.
68    Mod,
69    /// The `^` operator.
70    Pow,
71    /// The unary minus (`-`) operator.
72    Unm,
73    /// The floor division (//) operator.
74    #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "luau"))]
75    #[cfg_attr(
76        docsrs,
77        doc(cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "luau")))
78    )]
79    IDiv,
80    /// The bitwise AND (&) operator.
81    #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
82    #[cfg_attr(
83        docsrs,
84        doc(cfg(any(feature = "lua55", feature = "lua54", feature = "lua53")))
85    )]
86    BAnd,
87    /// The bitwise OR (|) operator.
88    #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
89    #[cfg_attr(
90        docsrs,
91        doc(cfg(any(feature = "lua55", feature = "lua54", feature = "lua53")))
92    )]
93    BOr,
94    /// The bitwise XOR (binary ~) operator.
95    #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
96    #[cfg_attr(
97        docsrs,
98        doc(cfg(any(feature = "lua55", feature = "lua54", feature = "lua53")))
99    )]
100    BXor,
101    /// The bitwise NOT (unary ~) operator.
102    #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
103    #[cfg_attr(
104        docsrs,
105        doc(cfg(any(feature = "lua55", feature = "lua54", feature = "lua53")))
106    )]
107    BNot,
108    /// The bitwise left shift (<<) operator.
109    #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
110    #[cfg_attr(
111        docsrs,
112        doc(cfg(any(feature = "lua55", feature = "lua54", feature = "lua53")))
113    )]
114    Shl,
115    /// The bitwise right shift (>>) operator.
116    #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
117    #[cfg_attr(
118        docsrs,
119        doc(cfg(any(feature = "lua55", feature = "lua54", feature = "lua53")))
120    )]
121    Shr,
122    /// The string concatenation operator `..`.
123    Concat,
124    /// The length operator `#`.
125    Len,
126    /// The `==` operator.
127    Eq,
128    /// The `<` operator.
129    Lt,
130    /// The `<=` operator.
131    Le,
132    /// Index access `obj[key]`.
133    Index,
134    /// Index write access `obj[key] = value`.
135    NewIndex,
136    /// The call "operator" `obj(arg1, args2, ...)`.
137    Call,
138    /// The `__tostring` metamethod.
139    ///
140    /// This is not an operator, but will be called by methods such as `tostring` and `print`.
141    ToString,
142    /// The `__todebugstring` metamethod for debug purposes.
143    ///
144    /// This is an mlua-specific metamethod that can be used to provide debug representation for
145    /// userdata.
146    ToDebugString,
147    /// The `__pairs` metamethod.
148    ///
149    /// This is not an operator, but it will be called by the built-in `pairs` function.
150    #[cfg(any(
151        feature = "lua55",
152        feature = "lua54",
153        feature = "lua53",
154        feature = "lua52",
155        feature = "luajit52"
156    ))]
157    #[cfg_attr(
158        docsrs,
159        doc(cfg(any(
160            feature = "lua55",
161            feature = "lua54",
162            feature = "lua53",
163            feature = "lua52",
164            feature = "luajit52"
165        )))
166    )]
167    Pairs,
168    /// The `__ipairs` metamethod.
169    ///
170    /// This is not an operator, but it will be called by the built-in [`ipairs`] function.
171    ///
172    /// [`ipairs`]: https://www.lua.org/manual/5.2/manual.html#pdf-ipairs
173    #[cfg(any(feature = "lua52", feature = "luajit52", doc))]
174    #[cfg_attr(docsrs, doc(cfg(any(feature = "lua52", feature = "luajit52"))))]
175    IPairs,
176    /// The `__iter` metamethod.
177    ///
178    /// Executed before the iteration begins, and should return an iterator function like `next`
179    /// (or a custom one).
180    #[cfg(any(feature = "luau", doc))]
181    #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
182    Iter,
183    /// The `__close` metamethod.
184    ///
185    /// Executed when a variable, that marked as to-be-closed, goes out of scope.
186    ///
187    /// More information about to-be-closed variables can be found in the Lua 5.4
188    /// [documentation][lua_doc].
189    ///
190    /// [lua_doc]: https://www.lua.org/manual/5.4/manual.html#3.3.8
191    #[cfg(any(feature = "lua55", feature = "lua54"))]
192    #[cfg_attr(docsrs, doc(cfg(any(feature = "lua55", feature = "lua54"))))]
193    Close,
194    /// The `__name`/`__type` metafield.
195    ///
196    /// This is not a function, but it's value can be used by `tostring` and `typeof` built-in
197    /// functions.
198    #[doc(hidden)]
199    Type,
200}
201
202impl PartialEq<MetaMethod> for &str {
203    fn eq(&self, other: &MetaMethod) -> bool {
204        *self == other.name()
205    }
206}
207
208impl PartialEq<MetaMethod> for String {
209    fn eq(&self, other: &MetaMethod) -> bool {
210        self == other.name()
211    }
212}
213
214impl fmt::Display for MetaMethod {
215    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
216        write!(fmt, "{}", self.name())
217    }
218}
219
220impl MetaMethod {
221    /// Returns Lua metamethod name, usually prefixed by two underscores.
222    pub const fn name(self) -> &'static str {
223        match self {
224            MetaMethod::Add => "__add",
225            MetaMethod::Sub => "__sub",
226            MetaMethod::Mul => "__mul",
227            MetaMethod::Div => "__div",
228            MetaMethod::Mod => "__mod",
229            MetaMethod::Pow => "__pow",
230            MetaMethod::Unm => "__unm",
231
232            #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "luau"))]
233            MetaMethod::IDiv => "__idiv",
234            #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
235            MetaMethod::BAnd => "__band",
236            #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
237            MetaMethod::BOr => "__bor",
238            #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
239            MetaMethod::BXor => "__bxor",
240            #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
241            MetaMethod::BNot => "__bnot",
242            #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
243            MetaMethod::Shl => "__shl",
244            #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
245            MetaMethod::Shr => "__shr",
246
247            MetaMethod::Concat => "__concat",
248            MetaMethod::Len => "__len",
249            MetaMethod::Eq => "__eq",
250            MetaMethod::Lt => "__lt",
251            MetaMethod::Le => "__le",
252            MetaMethod::Index => "__index",
253            MetaMethod::NewIndex => "__newindex",
254            MetaMethod::Call => "__call",
255            MetaMethod::ToString => "__tostring",
256            MetaMethod::ToDebugString => "__todebugstring",
257
258            #[cfg(any(
259                feature = "lua55",
260                feature = "lua54",
261                feature = "lua53",
262                feature = "lua52",
263                feature = "luajit52"
264            ))]
265            MetaMethod::Pairs => "__pairs",
266            #[cfg(any(feature = "lua52", feature = "luajit52"))]
267            MetaMethod::IPairs => "__ipairs",
268            #[cfg(feature = "luau")]
269            MetaMethod::Iter => "__iter",
270
271            #[cfg(any(feature = "lua55", feature = "lua54"))]
272            MetaMethod::Close => "__close",
273
274            #[rustfmt::skip]
275            MetaMethod::Type => if cfg!(feature = "luau") { "__type" } else { "__name" },
276        }
277    }
278
279    pub(crate) const fn as_cstr(self) -> &'static CStr {
280        match self {
281            #[rustfmt::skip]
282            MetaMethod::Type => if cfg!(feature = "luau") { c"__type" } else { c"__name" },
283            _ => unreachable!(),
284        }
285    }
286
287    pub(crate) fn validate(name: &str) -> Result<&str> {
288        match name {
289            "__gc" => Err(Error::MetaMethodRestricted(name.to_string())),
290            "__metatable" => Err(Error::MetaMethodRestricted(name.to_string())),
291            _ if name.starts_with("__mlua") => Err(Error::MetaMethodRestricted(name.to_string())),
292            name => Ok(name),
293        }
294    }
295}
296
297impl AsRef<str> for MetaMethod {
298    fn as_ref(&self) -> &str {
299        self.name()
300    }
301}
302
303impl From<MetaMethod> for String {
304    #[inline]
305    fn from(method: MetaMethod) -> Self {
306        method.name().to_owned()
307    }
308}
309
310/// Method registry for [`UserData`] implementors.
311pub trait UserDataMethods<T> {
312    /// Add a regular method which accepts a `&T` as the first parameter.
313    ///
314    /// Regular methods are implemented by overriding the `__index` metamethod and returning the
315    /// accessed method. This allows them to be used with the expected `userdata:method()` syntax.
316    ///
317    /// If `add_meta_method` is used to set the `__index` metamethod, the `__index` metamethod will
318    /// be used as a fall-back if no regular method is found.
319    fn add_method<M, A, R>(&mut self, name: impl Into<String>, method: M)
320    where
321        M: Fn(&Lua, &T, A) -> Result<R> + MaybeSend + 'static,
322        A: FromLuaMulti,
323        R: IntoLuaMulti;
324
325    /// Add a regular method which accepts a `&mut T` as the first parameter.
326    ///
327    /// Refer to [`add_method`] for more information about the implementation.
328    ///
329    /// [`add_method`]: UserDataMethods::add_method
330    fn add_method_mut<M, A, R>(&mut self, name: impl Into<String>, method: M)
331    where
332        M: FnMut(&Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
333        A: FromLuaMulti,
334        R: IntoLuaMulti;
335
336    /// Add a method which accepts `T` as the first parameter.
337    ///
338    /// The userdata `T` will be moved out of the userdata container. This is useful for
339    /// methods that need to consume the userdata.
340    ///
341    /// The method can be called only once per userdata instance, subsequent calls will result in a
342    /// [`Error::UserDataDestructed`] error.
343    fn add_method_once<M, A, R>(&mut self, name: impl Into<String>, method: M)
344    where
345        T: 'static,
346        M: Fn(&Lua, T, A) -> Result<R> + MaybeSend + 'static,
347        A: FromLuaMulti,
348        R: IntoLuaMulti,
349    {
350        let name = name.into();
351        let method_name = format!("{}.{name}", short_type_name::<T>());
352        self.add_function(name, move |lua, (ud, args): (AnyUserData, A)| {
353            let this = (ud.take()).map_err(|err| Error::bad_self_argument(&method_name, err))?;
354            method(lua, this, args)
355        });
356    }
357
358    /// Add an async method which accepts a `&T` as the first parameter and returns [`Future`].
359    ///
360    /// Refer to [`add_method`] for more information about the implementation.
361    ///
362    /// [`add_method`]: UserDataMethods::add_method
363    #[cfg(feature = "async")]
364    #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
365    fn add_async_method<M, A, MR, R>(&mut self, name: impl Into<String>, method: M)
366    where
367        T: 'static,
368        M: Fn(Lua, UserDataRef<T>, A) -> MR + MaybeSend + 'static,
369        A: FromLuaMulti,
370        MR: Future<Output = Result<R>> + MaybeSend + 'static,
371        R: IntoLuaMulti;
372
373    /// Add an async method which accepts a `&mut T` as the first parameter and returns [`Future`].
374    ///
375    /// Refer to [`add_method`] for more information about the implementation.
376    ///
377    /// [`add_method`]: UserDataMethods::add_method
378    #[cfg(feature = "async")]
379    #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
380    fn add_async_method_mut<M, A, MR, R>(&mut self, name: impl Into<String>, method: M)
381    where
382        T: 'static,
383        M: Fn(Lua, UserDataRefMut<T>, A) -> MR + MaybeSend + 'static,
384        A: FromLuaMulti,
385        MR: Future<Output = Result<R>> + MaybeSend + 'static,
386        R: IntoLuaMulti;
387
388    /// Add an async method which accepts a `T` as the first parameter and returns [`Future`].
389    ///
390    /// The userdata `T` will be moved out of the userdata container. This is useful for
391    /// methods that need to consume the userdata.
392    ///
393    /// The method can be called only once per userdata instance, subsequent calls will result in a
394    /// [`Error::UserDataDestructed`] error.
395    #[cfg(feature = "async")]
396    #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
397    fn add_async_method_once<M, A, MR, R>(&mut self, name: impl Into<String>, method: M)
398    where
399        T: 'static,
400        M: Fn(Lua, T, A) -> MR + MaybeSend + 'static,
401        A: FromLuaMulti,
402        MR: Future<Output = Result<R>> + MaybeSend + 'static,
403        R: IntoLuaMulti,
404    {
405        let name = name.into();
406        let method_name = format!("{}.{name}", short_type_name::<T>());
407        self.add_async_function(name, move |lua, (ud, args): (AnyUserData, A)| {
408            match (ud.take()).map_err(|err| Error::bad_self_argument(&method_name, err)) {
409                Ok(this) => either::Either::Left(method(lua, this, args)),
410                Err(err) => either::Either::Right(async move { Err(err) }),
411            }
412        });
413    }
414
415    /// Add a regular method as a function which accepts generic arguments.
416    ///
417    /// The first argument will be a [`AnyUserData`] of type `T` if the method is called with Lua
418    /// method syntax: `my_userdata:my_method(arg1, arg2)`, or it is passed in as the first
419    /// argument: `my_userdata.my_method(my_userdata, arg1, arg2)`.
420    fn add_function<F, A, R>(&mut self, name: impl Into<String>, function: F)
421    where
422        F: Fn(&Lua, A) -> Result<R> + MaybeSend + 'static,
423        A: FromLuaMulti,
424        R: IntoLuaMulti;
425
426    /// Add a regular method as a mutable function which accepts generic arguments.
427    ///
428    /// This is a version of [`add_function`] that accepts a `FnMut` argument.
429    ///
430    /// [`add_function`]: UserDataMethods::add_function
431    fn add_function_mut<F, A, R>(&mut self, name: impl Into<String>, function: F)
432    where
433        F: FnMut(&Lua, A) -> Result<R> + MaybeSend + 'static,
434        A: FromLuaMulti,
435        R: IntoLuaMulti;
436
437    /// Add a regular method as an async function which accepts generic arguments and returns
438    /// [`Future`].
439    ///
440    /// This is an async version of [`add_function`].
441    ///
442    /// [`add_function`]: UserDataMethods::add_function
443    #[cfg(feature = "async")]
444    #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
445    fn add_async_function<F, A, FR, R>(&mut self, name: impl Into<String>, function: F)
446    where
447        F: Fn(Lua, A) -> FR + MaybeSend + 'static,
448        A: FromLuaMulti,
449        FR: Future<Output = Result<R>> + MaybeSend + 'static,
450        R: IntoLuaMulti;
451
452    /// Add a metamethod which accepts a `&T` as the first parameter.
453    ///
454    /// # Note
455    ///
456    /// This can cause an error with certain binary metamethods that can trigger if only the right
457    /// side has a metatable. To prevent this, use [`add_meta_function`].
458    ///
459    /// [`add_meta_function`]: UserDataMethods::add_meta_function
460    fn add_meta_method<M, A, R>(&mut self, name: impl Into<String>, method: M)
461    where
462        M: Fn(&Lua, &T, A) -> Result<R> + MaybeSend + 'static,
463        A: FromLuaMulti,
464        R: IntoLuaMulti;
465
466    /// Add a metamethod as a function which accepts a `&mut T` as the first parameter.
467    ///
468    /// # Note
469    ///
470    /// This can cause an error with certain binary metamethods that can trigger if only the right
471    /// side has a metatable. To prevent this, use [`add_meta_function`].
472    ///
473    /// [`add_meta_function`]: UserDataMethods::add_meta_function
474    fn add_meta_method_mut<M, A, R>(&mut self, name: impl Into<String>, method: M)
475    where
476        M: FnMut(&Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
477        A: FromLuaMulti,
478        R: IntoLuaMulti;
479
480    /// Add an async metamethod which accepts a `&T` as the first parameter and returns [`Future`].
481    ///
482    /// This is an async version of [`add_meta_method`].
483    ///
484    /// [`add_meta_method`]: UserDataMethods::add_meta_method
485    #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
486    #[cfg_attr(
487        docsrs,
488        doc(cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau")))))
489    )]
490    fn add_async_meta_method<M, A, MR, R>(&mut self, name: impl Into<String>, method: M)
491    where
492        T: 'static,
493        M: Fn(Lua, UserDataRef<T>, A) -> MR + MaybeSend + 'static,
494        A: FromLuaMulti,
495        MR: Future<Output = Result<R>> + MaybeSend + 'static,
496        R: IntoLuaMulti;
497
498    /// Add an async metamethod which accepts a `&mut T` as the first parameter and returns
499    /// [`Future`].
500    ///
501    /// This is an async version of [`add_meta_method_mut`].
502    ///
503    /// [`add_meta_method_mut`]: UserDataMethods::add_meta_method_mut
504    #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
505    #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
506    fn add_async_meta_method_mut<M, A, MR, R>(&mut self, name: impl Into<String>, method: M)
507    where
508        T: 'static,
509        M: Fn(Lua, UserDataRefMut<T>, A) -> MR + MaybeSend + 'static,
510        A: FromLuaMulti,
511        MR: Future<Output = Result<R>> + MaybeSend + 'static,
512        R: IntoLuaMulti;
513
514    /// Add a metamethod which accepts generic arguments.
515    ///
516    /// Metamethods for binary operators can be triggered if either the left or right argument to
517    /// the binary operator has a metatable, so the first argument here is not necessarily a
518    /// userdata of type `T`.
519    fn add_meta_function<F, A, R>(&mut self, name: impl Into<String>, function: F)
520    where
521        F: Fn(&Lua, A) -> Result<R> + MaybeSend + 'static,
522        A: FromLuaMulti,
523        R: IntoLuaMulti;
524
525    /// Add a metamethod as a mutable function which accepts generic arguments.
526    ///
527    /// This is a version of [`add_meta_function`] that accepts a `FnMut` argument.
528    ///
529    /// [`add_meta_function`]: UserDataMethods::add_meta_function
530    fn add_meta_function_mut<F, A, R>(&mut self, name: impl Into<String>, function: F)
531    where
532        F: FnMut(&Lua, A) -> Result<R> + MaybeSend + 'static,
533        A: FromLuaMulti,
534        R: IntoLuaMulti;
535
536    /// Add a metamethod which accepts generic arguments and returns [`Future`].
537    ///
538    /// This is an async version of [`add_meta_function`].
539    ///
540    /// [`add_meta_function`]: UserDataMethods::add_meta_function
541    #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
542    #[cfg_attr(
543        docsrs,
544        doc(cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau")))))
545    )]
546    fn add_async_meta_function<F, A, FR, R>(&mut self, name: impl Into<String>, function: F)
547    where
548        F: Fn(Lua, A) -> FR + MaybeSend + 'static,
549        A: FromLuaMulti,
550        FR: Future<Output = Result<R>> + MaybeSend + 'static,
551        R: IntoLuaMulti;
552}
553
554/// Field registry for [`UserData`] implementors.
555pub trait UserDataFields<T> {
556    /// Add a static field to the [`UserData`].
557    ///
558    /// Static fields are implemented by updating the `__index` metamethod and returning the
559    /// accessed field. This allows them to be used with the expected `userdata.field` syntax.
560    ///
561    /// Static fields are usually shared between all instances of the [`UserData`] of the same type.
562    ///
563    /// If `add_meta_method` is used to set the `__index` metamethod, it will
564    /// be used as a fall-back if no regular field or method are found.
565    fn add_field<V>(&mut self, name: impl Into<String>, value: V)
566    where
567        V: IntoLua + 'static;
568
569    /// Add a regular field getter as a method which accepts a `&T` as the parameter.
570    ///
571    /// Regular field getters are implemented by overriding the `__index` metamethod and returning
572    /// the accessed field. This allows them to be used with the expected `userdata.field` syntax.
573    ///
574    /// If `add_meta_method` is used to set the `__index` metamethod, the `__index` metamethod will
575    /// be used as a fall-back if no regular field or method are found.
576    fn add_field_method_get<M, R>(&mut self, name: impl Into<String>, method: M)
577    where
578        M: Fn(&Lua, &T) -> Result<R> + MaybeSend + 'static,
579        R: IntoLua;
580
581    /// Add a regular field setter as a method which accepts a `&mut T` as the first parameter.
582    ///
583    /// Regular field setters are implemented by overriding the `__newindex` metamethod and setting
584    /// the accessed field. This allows them to be used with the expected `userdata.field = value`
585    /// syntax.
586    ///
587    /// If `add_meta_method` is used to set the `__newindex` metamethod, the `__newindex` metamethod
588    /// will be used as a fall-back if no regular field is found.
589    fn add_field_method_set<M, A>(&mut self, name: impl Into<String>, method: M)
590    where
591        M: FnMut(&Lua, &mut T, A) -> Result<()> + MaybeSend + 'static,
592        A: FromLua;
593
594    /// Add a regular field getter as a function which accepts a generic [`AnyUserData`] of type `T`
595    /// argument.
596    fn add_field_function_get<F, R>(&mut self, name: impl Into<String>, function: F)
597    where
598        F: Fn(&Lua, AnyUserData) -> Result<R> + MaybeSend + 'static,
599        R: IntoLua;
600
601    /// Add a regular field setter as a function which accepts a generic [`AnyUserData`] of type `T`
602    /// first argument.
603    fn add_field_function_set<F, A>(&mut self, name: impl Into<String>, function: F)
604    where
605        F: FnMut(&Lua, AnyUserData, A) -> Result<()> + MaybeSend + 'static,
606        A: FromLua;
607
608    /// Add a metatable field.
609    ///
610    /// This will initialize the metatable field with `value` on [`UserData`] creation.
611    ///
612    /// # Note
613    ///
614    /// `mlua` will trigger an error on an attempt to define a protected metamethod,
615    /// like `__gc` or `__metatable`.
616    fn add_meta_field<V>(&mut self, name: impl Into<String>, value: V)
617    where
618        V: IntoLua + 'static;
619
620    /// Add a metatable field computed from `f`.
621    ///
622    /// This will initialize the metatable field from `f` on [`UserData`] creation.
623    ///
624    /// # Note
625    ///
626    /// `mlua` will trigger an error on an attempt to define a protected metamethod,
627    /// like `__gc` or `__metatable`.
628    fn add_meta_field_with<F, R>(&mut self, name: impl Into<String>, f: F)
629    where
630        F: FnOnce(&Lua) -> Result<R> + 'static,
631        R: IntoLua;
632}
633
634/// Trait for custom userdata types.
635///
636/// By implementing this trait, a struct becomes eligible for use inside Lua code.
637///
638/// Implementation of [`IntoLua`] is automatically provided, [`FromLua`] needs to be implemented
639/// manually.
640///
641///
642/// # Examples
643///
644/// ```
645/// # use mlua::{Lua, Result, UserData};
646/// # fn main() -> Result<()> {
647/// # let lua = Lua::new();
648/// struct MyUserData;
649///
650/// impl UserData for MyUserData {}
651///
652/// // `MyUserData` now implements `IntoLua`:
653/// lua.globals().set("myobject", MyUserData)?;
654///
655/// lua.load("assert(type(myobject) == 'userdata')").exec()?;
656/// # Ok(())
657/// # }
658/// ```
659///
660/// Custom fields, methods and operators can be provided by implementing `add_fields` or
661/// `add_methods` (refer to [`UserDataFields`] and [`UserDataMethods`] for more information):
662///
663/// ```
664/// # use mlua::{Lua, MetaMethod, Result, UserData, UserDataFields, UserDataMethods};
665/// # fn main() -> Result<()> {
666/// # let lua = Lua::new();
667/// struct MyUserData(i32);
668///
669/// impl UserData for MyUserData {
670///     fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
671///         fields.add_field_method_get("val", |_, this| Ok(this.0));
672///     }
673///
674///     fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
675///         methods.add_method_mut("add", |_, mut this, value: i32| {
676///             this.0 += value;
677///             Ok(())
678///         });
679///
680///         methods.add_meta_method(MetaMethod::Add, |_, this, value: i32| {
681///             Ok(this.0 + value)
682///         });
683///     }
684/// }
685///
686/// lua.globals().set("myobject", MyUserData(123))?;
687///
688/// lua.load(r#"
689///     assert(myobject.val == 123)
690///     myobject:add(7)
691///     assert(myobject.val == 130)
692///     assert(myobject + 10 == 140)
693/// "#).exec()?;
694/// # Ok(())
695/// # }
696/// ```
697pub trait UserData: Sized {
698    /// Adds custom fields specific to this userdata.
699    #[allow(unused_variables)]
700    fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {}
701
702    /// Adds custom methods and operators specific to this userdata.
703    #[allow(unused_variables)]
704    fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {}
705
706    /// Registers this type for use in Lua.
707    ///
708    /// This method is responsible for calling `add_fields` and `add_methods` on the provided
709    /// [`UserDataRegistry`].
710    fn register(registry: &mut UserDataRegistry<Self>) {
711        Self::add_fields(registry);
712        Self::add_methods(registry);
713    }
714}
715
716/// Handle to an internal Lua userdata for any type that implements [`UserData`].
717///
718/// Similar to [`std::any::Any`], this provides an interface for dynamic type checking via the
719/// [`is`] and [`borrow`] methods.
720///
721/// # Note
722///
723/// This API should only be used when necessary. Implementing [`UserData`] already allows defining
724/// methods which check the type and acquire a borrow behind the scenes.
725///
726/// [`is`]: crate::AnyUserData::is
727/// [`borrow`]: crate::AnyUserData::borrow
728#[derive(Clone, PartialEq)]
729pub struct AnyUserData(pub(crate) ValueRef);
730
731impl AnyUserData {
732    /// Checks whether the type of this userdata is `T`.
733    #[inline]
734    pub fn is<T: 'static>(&self) -> bool {
735        let type_id = self.type_id();
736        // We do not use wrapped types here, rather prefer to check the "real" type of the userdata
737        matches!(type_id, Some(type_id) if type_id == TypeId::of::<T>())
738    }
739
740    /// Checks whether the type of this userdata is a [proxy object] for `T`.
741    ///
742    /// [proxy object]: crate::Lua::create_proxy
743    #[inline]
744    pub fn is_proxy<T: 'static>(&self) -> bool {
745        self.is::<UserDataProxy<T>>()
746    }
747
748    /// Borrow this userdata immutably if it is of type `T`.
749    ///
750    /// # Errors
751    ///
752    /// Returns a [`UserDataBorrowError`] if the userdata is already mutably borrowed.
753    /// Returns a [`DataTypeMismatch`] if the userdata is not of type `T` or if it's
754    /// scoped.
755    ///
756    /// [`UserDataBorrowError`]: crate::Error::UserDataBorrowError
757    /// [`DataTypeMismatch`]: crate::Error::UserDataTypeMismatch
758    #[inline]
759    pub fn borrow<T: 'static>(&self) -> Result<UserDataRef<T>> {
760        let lua = self.0.lua.lock();
761        unsafe { UserDataRef::borrow_from_stack(&lua, lua.ref_thread(), self.0.index) }
762    }
763
764    /// Borrow this userdata immutably if it is of type `T`, passing the borrowed value
765    /// to the closure.
766    ///
767    /// This method is the only way to borrow scoped userdata (created inside [`Lua::scope`]).
768    pub fn borrow_scoped<T: 'static, R>(&self, f: impl FnOnce(&T) -> R) -> Result<R> {
769        let lua = self.0.lua.lock();
770        let type_id = lua.get_userdata_ref_type_id(&self.0)?;
771        let type_hints = TypeIdHints::new::<T>();
772        unsafe { borrow_userdata_scoped(lua.ref_thread(), self.0.index, type_id, type_hints, f) }
773    }
774
775    /// Borrow this userdata mutably if it is of type `T`.
776    ///
777    /// # Errors
778    ///
779    /// Returns a [`UserDataBorrowMutError`] if the userdata cannot be mutably borrowed.
780    /// Returns a [`UserDataTypeMismatch`] if the userdata is not of type `T` or if it's
781    /// scoped.
782    ///
783    /// [`UserDataBorrowMutError`]: crate::Error::UserDataBorrowMutError
784    /// [`UserDataTypeMismatch`]: crate::Error::UserDataTypeMismatch
785    #[inline]
786    pub fn borrow_mut<T: 'static>(&self) -> Result<UserDataRefMut<T>> {
787        let lua = self.0.lua.lock();
788        unsafe { UserDataRefMut::borrow_from_stack(&lua, lua.ref_thread(), self.0.index) }
789    }
790
791    /// Borrow this userdata mutably if it is of type `T`, passing the borrowed value
792    /// to the closure.
793    ///
794    /// This method is the only way to borrow scoped userdata (created inside [`Lua::scope`]).
795    pub fn borrow_mut_scoped<T: 'static, R>(&self, f: impl FnOnce(&mut T) -> R) -> Result<R> {
796        let lua = self.0.lua.lock();
797        let type_id = lua.get_userdata_ref_type_id(&self.0)?;
798        let type_hints = TypeIdHints::new::<T>();
799        unsafe { borrow_userdata_scoped_mut(lua.ref_thread(), self.0.index, type_id, type_hints, f) }
800    }
801
802    /// Takes the value out of this userdata.
803    ///
804    /// Sets the special "destructed" metatable that prevents any further operations with this
805    /// userdata.
806    ///
807    /// Keeps associated user values unchanged (they will be collected by Lua's GC).
808    pub fn take<T: 'static>(&self) -> Result<T> {
809        let lua = self.0.lua.lock();
810        match lua.get_userdata_ref_type_id(&self.0)? {
811            Some(type_id) if type_id == TypeId::of::<T>() => unsafe {
812                let ref_thread = lua.ref_thread();
813                if (*get_userdata::<UserDataStorage<T>>(ref_thread, self.0.index)).has_exclusive_access() {
814                    take_userdata::<UserDataStorage<T>>(ref_thread, self.0.index).into_inner()
815                } else {
816                    Err(Error::UserDataBorrowMutError)
817                }
818            },
819            _ => Err(Error::UserDataTypeMismatch),
820        }
821    }
822
823    /// Destroys this userdata.
824    ///
825    /// This is similar to [`AnyUserData::take`], but it doesn't require a type.
826    ///
827    /// This method works for non-scoped userdata only.
828    pub fn destroy(&self) -> Result<()> {
829        let lua = self.0.lua.lock();
830        let state = lua.state();
831        unsafe {
832            let _sg = StackGuard::new(state);
833            check_stack(state, 3)?;
834
835            lua.push_userdata_ref(&self.0)?;
836            protect_lua!(state, 1, 1, fn(state) {
837                if ffi::luaL_callmeta(state, -1, cstr!("__gc")) == 0 {
838                    ffi::lua_pushboolean(state, 0);
839                }
840            })?;
841            if ffi::lua_isboolean(state, -1) != 0 && ffi::lua_toboolean(state, -1) != 0 {
842                return Ok(());
843            }
844            Err(Error::UserDataBorrowMutError)
845        }
846    }
847
848    /// Sets an associated value to this [`AnyUserData`].
849    ///
850    /// The value may be any Lua value whatsoever, and can be retrieved with [`user_value`].
851    ///
852    /// This is the same as calling [`set_nth_user_value`] with `n` set to 1.
853    ///
854    /// [`user_value`]: AnyUserData::user_value
855    /// [`set_nth_user_value`]: AnyUserData::set_nth_user_value
856    #[inline]
857    pub fn set_user_value(&self, v: impl IntoLua) -> Result<()> {
858        self.set_nth_user_value(1, v)
859    }
860
861    /// Returns an associated value set by [`set_user_value`].
862    ///
863    /// This is the same as calling [`nth_user_value`] with `n` set to 1.
864    ///
865    /// [`set_user_value`]: AnyUserData::set_user_value
866    /// [`nth_user_value`]: AnyUserData::nth_user_value
867    #[inline]
868    pub fn user_value<V: FromLua>(&self) -> Result<V> {
869        self.nth_user_value(1)
870    }
871
872    /// Sets an associated `n`th value to this [`AnyUserData`].
873    ///
874    /// The value may be any Lua value whatsoever, and can be retrieved with [`nth_user_value`].
875    /// `n` starts from 1 and can be up to 65535.
876    ///
877    /// This is supported for all Lua versions using a wrapping table.
878    ///
879    /// [`nth_user_value`]: AnyUserData::nth_user_value
880    pub fn set_nth_user_value(&self, n: usize, v: impl IntoLua) -> Result<()> {
881        if n < 1 || n > u16::MAX as usize {
882            return Err(Error::runtime("user value index out of bounds"));
883        }
884
885        let lua = self.0.lua.lock();
886        let state = lua.state();
887        unsafe {
888            let _sg = StackGuard::new(state);
889            check_stack(state, 5)?;
890
891            lua.push_userdata_ref(&self.0)?;
892            lua.push(v)?;
893
894            // Multiple (extra) user values are emulated by storing them in a table
895            protect_lua!(state, 2, 0, |state| {
896                if ffi::lua_getuservalue(state, -2) != ffi::LUA_TTABLE {
897                    // Create a new table to use as uservalue
898                    ffi::lua_pop(state, 1);
899                    ffi::lua_newtable(state);
900                    ffi::lua_pushvalue(state, -1);
901                    ffi::lua_setuservalue(state, -4);
902                }
903                ffi::lua_pushvalue(state, -2);
904                ffi::lua_rawseti(state, -2, n as ffi::lua_Integer);
905            })?;
906
907            Ok(())
908        }
909    }
910
911    /// Returns an associated `n`th value set by [`set_nth_user_value`].
912    ///
913    /// `n` starts from 1 and can be up to 65535.
914    ///
915    /// This is supported for all Lua versions using a wrapping table.
916    ///
917    /// [`set_nth_user_value`]: AnyUserData::set_nth_user_value
918    pub fn nth_user_value<V: FromLua>(&self, n: usize) -> Result<V> {
919        if n < 1 || n > u16::MAX as usize {
920            return Err(Error::runtime("user value index out of bounds"));
921        }
922
923        let lua = self.0.lua.lock();
924        let state = lua.state();
925        unsafe {
926            let _sg = StackGuard::new(state);
927            check_stack(state, 4)?;
928
929            lua.push_userdata_ref(&self.0)?;
930
931            // Multiple (extra) user values are emulated by storing them in a table
932            if ffi::lua_getuservalue(state, -1) != ffi::LUA_TTABLE {
933                return V::from_lua(Value::Nil, lua.lua());
934            }
935            ffi::lua_rawgeti(state, -1, n as ffi::lua_Integer);
936
937            V::from_lua(lua.pop_value(), lua.lua())
938        }
939    }
940
941    /// Sets an associated value to this [`AnyUserData`] by name.
942    ///
943    /// The value can be retrieved with [`named_user_value`].
944    ///
945    /// [`named_user_value`]: AnyUserData::named_user_value
946    pub fn set_named_user_value(&self, name: &str, v: impl IntoLua) -> Result<()> {
947        let lua = self.0.lua.lock();
948        let state = lua.state();
949        unsafe {
950            let _sg = StackGuard::new(state);
951            check_stack(state, 5)?;
952
953            lua.push_userdata_ref(&self.0)?;
954            lua.push(v)?;
955
956            // Multiple (extra) user values are emulated by storing them in a table
957            protect_lua!(state, 2, 0, |state| {
958                if ffi::lua_getuservalue(state, -2) != ffi::LUA_TTABLE {
959                    // Create a new table to use as uservalue
960                    ffi::lua_pop(state, 1);
961                    ffi::lua_newtable(state);
962                    ffi::lua_pushvalue(state, -1);
963                    ffi::lua_setuservalue(state, -4);
964                }
965                ffi::lua_pushlstring(state, name.as_ptr() as *const c_char, name.len());
966                ffi::lua_pushvalue(state, -3);
967                ffi::lua_rawset(state, -3);
968            })?;
969
970            Ok(())
971        }
972    }
973
974    /// Returns an associated value by name set by [`set_named_user_value`].
975    ///
976    /// [`set_named_user_value`]: AnyUserData::set_named_user_value
977    pub fn named_user_value<V: FromLua>(&self, name: &str) -> Result<V> {
978        let lua = self.0.lua.lock();
979        let state = lua.state();
980        unsafe {
981            let _sg = StackGuard::new(state);
982            check_stack(state, 4)?;
983
984            lua.push_userdata_ref(&self.0)?;
985
986            // Multiple (extra) user values are emulated by storing them in a table
987            if ffi::lua_getuservalue(state, -1) != ffi::LUA_TTABLE {
988                return V::from_lua(Value::Nil, lua.lua());
989            }
990            push_string(state, name.as_bytes(), !lua.unlikely_memory_error())?;
991            ffi::lua_rawget(state, -2);
992
993            V::from_stack(-1, &lua)
994        }
995    }
996
997    /// Returns a metatable of this [`AnyUserData`].
998    ///
999    /// Returned [`UserDataMetatable`] object wraps the original metatable and
1000    /// provides safe access to its methods.
1001    ///
1002    /// For `T: 'static` returned metatable is shared among all instances of type `T`.
1003    #[inline]
1004    pub fn metatable(&self) -> Result<UserDataMetatable> {
1005        self.raw_metatable().map(UserDataMetatable)
1006    }
1007
1008    /// Returns a raw metatable of this [`AnyUserData`].
1009    fn raw_metatable(&self) -> Result<Table> {
1010        let lua = self.0.lua.lock();
1011        let ref_thread = lua.ref_thread();
1012        unsafe {
1013            // Check that userdata is registered and not destructed
1014            // All registered userdata types have a non-empty metatable
1015            let _type_id = lua.get_userdata_ref_type_id(&self.0)?;
1016
1017            ffi::lua_getmetatable(ref_thread, self.0.index);
1018            Ok(Table(lua.pop_ref_thread()))
1019        }
1020    }
1021
1022    /// Converts this userdata to a generic C pointer.
1023    ///
1024    /// There is no way to convert the pointer back to its original value.
1025    ///
1026    /// Typically this function is used only for hashing and debug information.
1027    #[inline]
1028    pub fn to_pointer(&self) -> *const c_void {
1029        self.0.to_pointer()
1030    }
1031
1032    /// Returns [`TypeId`] of this userdata if it is registered and `'static`.
1033    ///
1034    /// This method is not available for scoped userdata.
1035    #[inline]
1036    pub fn type_id(&self) -> Option<TypeId> {
1037        let lua = self.0.lua.lock();
1038        lua.get_userdata_ref_type_id(&self.0).ok().flatten()
1039    }
1040
1041    /// Returns a type name of this userdata (from a metatable field).
1042    ///
1043    /// If no type name is set, returns `None`.
1044    pub fn type_name(&self) -> Result<Option<String>> {
1045        let lua = self.0.lua.lock();
1046        let state = lua.state();
1047        unsafe {
1048            let _sg = StackGuard::new(state);
1049            check_stack(state, 3)?;
1050
1051            lua.push_userdata_ref(&self.0)?;
1052            let protect = !lua.unlikely_memory_error();
1053            let name_type = if protect {
1054                protect_lua!(state, 1, 1, |state| {
1055                    ffi::luaL_getmetafield(state, -1, MetaMethod::Type.as_cstr().as_ptr())
1056                })?
1057            } else {
1058                ffi::luaL_getmetafield(state, -1, MetaMethod::Type.as_cstr().as_ptr())
1059            };
1060            match name_type {
1061                ffi::LUA_TSTRING => Ok(Some(LuaString(lua.pop_ref()).to_str()?.to_owned())),
1062                _ => Ok(None),
1063            }
1064        }
1065    }
1066
1067    pub(crate) fn equals(&self, other: &Self) -> Result<bool> {
1068        // Uses lua_rawequal() under the hood
1069        if self == other {
1070            return Ok(true);
1071        }
1072
1073        let mt = self.raw_metatable()?;
1074        if mt != other.raw_metatable()? {
1075            return Ok(false);
1076        }
1077
1078        if mt.contains_key("__eq")? {
1079            return mt.get::<Function>("__eq")?.call((self, other));
1080        }
1081
1082        Ok(false)
1083    }
1084
1085    /// Returns `true` if this [`AnyUserData`] is serializable (e.g. was created using
1086    /// [`Lua::create_ser_userdata`]).
1087    #[cfg(feature = "serde")]
1088    pub(crate) fn is_serializable(&self) -> bool {
1089        let lua = self.0.lua.lock();
1090        let is_serializable = || unsafe {
1091            // Userdata must be registered and not destructed
1092            let _ = lua.get_userdata_ref_type_id(&self.0)?;
1093            let ud = &*get_userdata::<UserDataStorage<()>>(lua.ref_thread(), self.0.index);
1094            Ok::<_, Error>((*ud).is_serializable())
1095        };
1096        is_serializable().unwrap_or(false)
1097    }
1098
1099    unsafe fn invoke_tostring_dbg(&self) -> Result<Option<String>> {
1100        let lua = self.0.lua.lock();
1101        let state = lua.state();
1102        let _guard = StackGuard::new(state);
1103        check_stack(state, 3)?;
1104
1105        lua.push_ref(&self.0);
1106        protect_lua!(state, 1, 1, fn(state) {
1107            // Try `__todebugstring` metamethod first, then `__tostring`
1108            #[allow(clippy::collapsible_if)]
1109            if ffi::luaL_callmeta(state, -1, cstr!("__todebugstring")) == 0 {
1110                if ffi::luaL_callmeta(state, -1, cstr!("__tostring")) == 0 {
1111                    ffi::lua_pushnil(state);
1112                }
1113            }
1114        })?;
1115        Ok(lua.pop_value().as_string().map(|s| s.to_string_lossy()))
1116    }
1117
1118    pub(crate) fn fmt_pretty(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1119        // Try converting to a (debug) string first, with fallback to `__name/__type`
1120        match unsafe { self.invoke_tostring_dbg() } {
1121            Ok(Some(s)) => write!(fmt, "{s}"),
1122            _ => {
1123                let name = self.type_name().ok().flatten();
1124                let name = name.as_deref().unwrap_or("userdata");
1125                write!(fmt, "{name}: {:?}", self.to_pointer())
1126            }
1127        }
1128    }
1129}
1130
1131impl fmt::Debug for AnyUserData {
1132    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1133        if fmt.alternate() {
1134            return self.fmt_pretty(fmt);
1135        }
1136        fmt.debug_tuple("AnyUserData").field(&self.0).finish()
1137    }
1138}
1139
1140/// Handle to a [`AnyUserData`] metatable.
1141#[derive(Clone, Debug)]
1142pub struct UserDataMetatable(pub(crate) Table);
1143
1144impl UserDataMetatable {
1145    /// Gets the value associated to `key` from the metatable.
1146    ///
1147    /// If no value is associated to `key`, returns the `Nil` value.
1148    /// Access to restricted metamethods such as `__gc` or `__metatable` will cause an error.
1149    pub fn get<V: FromLua>(&self, key: impl AsRef<str>) -> Result<V> {
1150        self.0.raw_get(MetaMethod::validate(key.as_ref())?)
1151    }
1152
1153    /// Sets a key-value pair in the metatable.
1154    ///
1155    /// If the value is `Nil`, this will effectively remove the `key`.
1156    /// Access to restricted metamethods such as `__gc` or `__metatable` will cause an error.
1157    /// Setting `__index` or `__newindex` metamethods is also restricted because their values are
1158    /// cached for `mlua` internal usage.
1159    pub fn set(&self, key: impl AsRef<str>, value: impl IntoLua) -> Result<()> {
1160        let key = MetaMethod::validate(key.as_ref())?;
1161        // `__index` and `__newindex` cannot be changed in runtime, because values are cached
1162        if key == MetaMethod::Index || key == MetaMethod::NewIndex {
1163            return Err(Error::MetaMethodRestricted(key.to_string()));
1164        }
1165        self.0.raw_set(key, value)
1166    }
1167
1168    /// Checks whether the metatable contains a non-nil value for `key`.
1169    pub fn contains(&self, key: impl AsRef<str>) -> Result<bool> {
1170        self.0.contains_key(MetaMethod::validate(key.as_ref())?)
1171    }
1172
1173    /// Returns an iterator over the pairs of the metatable.
1174    ///
1175    /// The pairs are wrapped in a [`Result`], since they are lazily converted to `V` type.
1176    ///
1177    /// [`Result`]: crate::Result
1178    pub fn pairs<V: FromLua>(&self) -> UserDataMetatablePairs<'_, V> {
1179        UserDataMetatablePairs(self.0.pairs())
1180    }
1181}
1182
1183/// An iterator over the pairs of a [`AnyUserData`] metatable.
1184///
1185/// It skips restricted metamethods, such as `__gc` or `__metatable`.
1186///
1187/// This struct is created by the [`UserDataMetatable::pairs`] method.
1188pub struct UserDataMetatablePairs<'a, V>(TablePairs<'a, String, V>);
1189
1190impl<V> Iterator for UserDataMetatablePairs<'_, V>
1191where
1192    V: FromLua,
1193{
1194    type Item = Result<(String, V)>;
1195
1196    fn next(&mut self) -> Option<Self::Item> {
1197        loop {
1198            match self.0.next()? {
1199                Ok((key, value)) => {
1200                    // Skip restricted metamethods
1201                    if MetaMethod::validate(&key).is_ok() {
1202                        break Some(Ok((key, value)));
1203                    }
1204                }
1205                Err(e) => break Some(Err(e)),
1206            }
1207        }
1208    }
1209}
1210
1211#[cfg(feature = "serde")]
1212impl Serialize for AnyUserData {
1213    fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
1214    where
1215        S: Serializer,
1216    {
1217        let lua = self.0.lua.lock();
1218        unsafe {
1219            let _ = lua
1220                .get_userdata_ref_type_id(&self.0)
1221                .map_err(ser::Error::custom)?;
1222            let ud = &*get_userdata::<UserDataStorage<()>>(lua.ref_thread(), self.0.index);
1223            ud.serialize(serializer)
1224        }
1225    }
1226}
1227
1228struct WrappedUserdata<F: FnOnce(&Lua) -> Result<AnyUserData>>(F);
1229
1230impl AnyUserData {
1231    /// Wraps any Rust type, returning an opaque type that implements [`IntoLua`] trait.
1232    ///
1233    /// This function uses [`Lua::create_any_userdata`] under the hood.
1234    pub fn wrap<T: MaybeSend + MaybeSync + 'static>(data: T) -> impl IntoLua {
1235        WrappedUserdata(move |lua| lua.create_any_userdata(data))
1236    }
1237
1238    /// Wraps any Rust type that implements [`Serialize`], returning an opaque type that implements
1239    /// [`IntoLua`] trait.
1240    ///
1241    /// This function uses [`Lua::create_ser_any_userdata`] under the hood.
1242    #[cfg(feature = "serde")]
1243    #[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
1244    pub fn wrap_ser<T: Serialize + MaybeSend + MaybeSync + 'static>(data: T) -> impl IntoLua {
1245        WrappedUserdata(move |lua| lua.create_ser_any_userdata(data))
1246    }
1247}
1248
1249impl<F> IntoLua for WrappedUserdata<F>
1250where
1251    F: for<'l> FnOnce(&'l Lua) -> Result<AnyUserData>,
1252{
1253    fn into_lua(self, lua: &Lua) -> Result<Value> {
1254        (self.0)(lua).map(Value::UserData)
1255    }
1256}
1257
1258mod cell;
1259mod lock;
1260mod object;
1261mod r#ref;
1262mod registry;
1263mod util;
1264
1265#[cfg(test)]
1266mod assertions {
1267    use super::*;
1268
1269    #[cfg(not(feature = "send"))]
1270    static_assertions::assert_not_impl_any!(AnyUserData: Send);
1271    #[cfg(feature = "send")]
1272    static_assertions::assert_impl_all!(AnyUserData: Send, Sync);
1273}