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