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 ///
820 /// Panics from the value's destructor propagate to the caller. During garbage collection,
821 /// destructor panics abort the process instead.
822 pub fn destroy(&self) -> Result<()> {
823 let lua = self.0.lua.lock();
824 let state = lua.state();
825 unsafe {
826 let _sg = StackGuard::new(state);
827 check_stack(state, 3)?;
828
829 lua.push_userdata_ref(&self.0)?;
830 protect_lua!(state, 1, 1, fn(state) {
831 if ffi::luaL_getmetafield(state, 1, cstr!("__gc")) != ffi::LUA_TNIL {
832 ffi::lua_pushvalue(state, 1);
833 // Only explicit destruction may propagate panics
834 ffi::lua_pushboolean(state, 1);
835 ffi::lua_call(state, 2, 1);
836 } else {
837 ffi::lua_pushboolean(state, 0);
838 }
839 })?;
840 if ffi::lua_isboolean(state, -1) != 0 && ffi::lua_toboolean(state, -1) != 0 {
841 return Ok(());
842 }
843 Err(Error::UserDataBorrowMutError)
844 }
845 }
846
847 /// Sets an associated value to this [`AnyUserData`].
848 ///
849 /// The value may be any Lua value whatsoever, and can be retrieved with [`user_value`].
850 ///
851 /// This is the same as calling [`set_nth_user_value`] with `n` set to 1.
852 ///
853 /// [`user_value`]: AnyUserData::user_value
854 /// [`set_nth_user_value`]: AnyUserData::set_nth_user_value
855 #[inline]
856 pub fn set_user_value(&self, v: impl IntoLua) -> Result<()> {
857 self.set_nth_user_value(1, v)
858 }
859
860 /// Returns an associated value set by [`set_user_value`].
861 ///
862 /// This is the same as calling [`nth_user_value`] with `n` set to 1.
863 ///
864 /// [`set_user_value`]: AnyUserData::set_user_value
865 /// [`nth_user_value`]: AnyUserData::nth_user_value
866 #[inline]
867 pub fn user_value<V: FromLua>(&self) -> Result<V> {
868 self.nth_user_value(1)
869 }
870
871 /// Sets an associated `n`th value to this [`AnyUserData`].
872 ///
873 /// The value may be any Lua value whatsoever, and can be retrieved with [`nth_user_value`].
874 /// `n` starts from 1 and can be up to 65535.
875 ///
876 /// This is supported for all Lua versions using a wrapping table.
877 ///
878 /// [`nth_user_value`]: AnyUserData::nth_user_value
879 pub fn set_nth_user_value(&self, n: usize, v: impl IntoLua) -> Result<()> {
880 if n < 1 || n > u16::MAX as usize {
881 return Err(Error::runtime("user value index out of bounds"));
882 }
883
884 let lua = self.0.lua.lock();
885 let state = lua.state();
886 unsafe {
887 let _sg = StackGuard::new(state);
888 check_stack(state, 5)?;
889
890 lua.push_userdata_ref(&self.0)?;
891 lua.push(v)?;
892
893 // Multiple (extra) user values are emulated by storing them in a table
894 protect_lua!(state, 2, 0, |state| {
895 if ffi::lua_getuservalue(state, -2) != ffi::LUA_TTABLE {
896 // Create a new table to use as uservalue
897 ffi::lua_pop(state, 1);
898 ffi::lua_newtable(state);
899 ffi::lua_pushvalue(state, -1);
900 ffi::lua_setuservalue(state, -4);
901 }
902 ffi::lua_pushvalue(state, -2);
903 ffi::lua_rawseti(state, -2, n as ffi::lua_Integer);
904 })?;
905
906 Ok(())
907 }
908 }
909
910 /// Returns an associated `n`th value set by [`set_nth_user_value`].
911 ///
912 /// `n` starts from 1 and can be up to 65535.
913 ///
914 /// This is supported for all Lua versions using a wrapping table.
915 ///
916 /// [`set_nth_user_value`]: AnyUserData::set_nth_user_value
917 pub fn nth_user_value<V: FromLua>(&self, n: usize) -> Result<V> {
918 if n < 1 || n > u16::MAX as usize {
919 return Err(Error::runtime("user value index out of bounds"));
920 }
921
922 let lua = self.0.lua.lock();
923 let state = lua.state();
924 unsafe {
925 let _sg = StackGuard::new(state);
926 check_stack(state, 4)?;
927
928 lua.push_userdata_ref(&self.0)?;
929
930 // Multiple (extra) user values are emulated by storing them in a table
931 if ffi::lua_getuservalue(state, -1) != ffi::LUA_TTABLE {
932 return V::from_lua(Value::Nil, lua.lua());
933 }
934 ffi::lua_rawgeti(state, -1, n as ffi::lua_Integer);
935
936 V::from_stack(-1, &lua)
937 }
938 }
939
940 /// Sets an associated value to this [`AnyUserData`] by name.
941 ///
942 /// The value can be retrieved with [`named_user_value`].
943 ///
944 /// [`named_user_value`]: AnyUserData::named_user_value
945 pub fn set_named_user_value(&self, name: &str, v: impl IntoLua) -> Result<()> {
946 let lua = self.0.lua.lock();
947 let state = lua.state();
948 unsafe {
949 let _sg = StackGuard::new(state);
950 check_stack(state, 5)?;
951
952 lua.push_userdata_ref(&self.0)?;
953 lua.push(v)?;
954
955 // Multiple (extra) user values are emulated by storing them in a table
956 protect_lua!(state, 2, 0, |state| {
957 if ffi::lua_getuservalue(state, -2) != ffi::LUA_TTABLE {
958 // Create a new table to use as uservalue
959 ffi::lua_pop(state, 1);
960 ffi::lua_newtable(state);
961 ffi::lua_pushvalue(state, -1);
962 ffi::lua_setuservalue(state, -4);
963 }
964 ffi::lua_pushlstring(state, name.as_ptr() as *const c_char, name.len());
965 ffi::lua_pushvalue(state, -3);
966 ffi::lua_rawset(state, -3);
967 })?;
968
969 Ok(())
970 }
971 }
972
973 /// Returns an associated value by name set by [`set_named_user_value`].
974 ///
975 /// [`set_named_user_value`]: AnyUserData::set_named_user_value
976 pub fn named_user_value<V: FromLua>(&self, name: &str) -> Result<V> {
977 let lua = self.0.lua.lock();
978 let state = lua.state();
979 unsafe {
980 let _sg = StackGuard::new(state);
981 check_stack(state, 4)?;
982
983 lua.push_userdata_ref(&self.0)?;
984
985 // Multiple (extra) user values are emulated by storing them in a table
986 if ffi::lua_getuservalue(state, -1) != ffi::LUA_TTABLE {
987 return V::from_lua(Value::Nil, lua.lua());
988 }
989 push_string(state, name.as_bytes(), !lua.unlikely_memory_error())?;
990 ffi::lua_rawget(state, -2);
991
992 V::from_stack(-1, &lua)
993 }
994 }
995
996 /// Returns a metatable of this [`AnyUserData`].
997 ///
998 /// Returned [`UserDataMetatable`] object wraps the original metatable and
999 /// provides safe access to its methods.
1000 ///
1001 /// For `T: 'static` returned metatable is shared among all instances of type `T`.
1002 #[inline]
1003 pub fn metatable(&self) -> Result<UserDataMetatable> {
1004 self.raw_metatable().map(UserDataMetatable)
1005 }
1006
1007 /// Returns a raw metatable of this [`AnyUserData`].
1008 fn raw_metatable(&self) -> Result<Table> {
1009 let lua = self.0.lua.lock();
1010 let ref_thread = lua.ref_thread();
1011 unsafe {
1012 // Check that userdata is registered and not destructed
1013 // All registered userdata types have a non-empty metatable
1014 let _type_id = lua.get_userdata_ref_type_id(&self.0)?;
1015
1016 ffi::lua_getmetatable(ref_thread, self.0.index);
1017 Ok(Table(lua.try_pop_ref_thread()?))
1018 }
1019 }
1020
1021 /// Converts this userdata to a generic C pointer.
1022 ///
1023 /// There is no way to convert the pointer back to its original value.
1024 ///
1025 /// Typically this function is used only for hashing and debug information.
1026 #[inline]
1027 pub fn to_pointer(&self) -> *const c_void {
1028 self.0.to_pointer()
1029 }
1030
1031 /// Returns [`TypeId`] of this userdata if it is registered and `'static`.
1032 ///
1033 /// This method is not available for scoped userdata.
1034 #[inline]
1035 pub fn type_id(&self) -> Option<TypeId> {
1036 let lua = self.0.lua.lock();
1037 lua.get_userdata_ref_type_id(&self.0).ok().flatten()
1038 }
1039
1040 /// Returns a type name of this userdata (from a metatable field).
1041 ///
1042 /// If no type name is set, returns `userdata`.
1043 pub fn type_name(&self) -> Result<LuaString> {
1044 let lua = self.0.lua.lock();
1045 let state = lua.state();
1046 unsafe {
1047 let _sg = StackGuard::new(state);
1048 check_stack(state, 3)?;
1049
1050 lua.push_userdata_ref(&self.0)?;
1051 let name_type = protect_lua_mem!(lua, 1, 1, |state| {
1052 ffi::luaL_getmetafield(state, -1, MetaMethod::Type.as_cstr().as_ptr())
1053 })?;
1054 match name_type {
1055 ffi::LUA_TSTRING => Ok(LuaString(lua.try_pop_ref()?)),
1056 _ => lua.create_string(b"userdata"),
1057 }
1058 }
1059 }
1060
1061 pub(crate) fn equals(&self, other: &Self) -> Result<bool> {
1062 // Uses lua_rawequal() under the hood
1063 if self == other {
1064 return Ok(true);
1065 }
1066
1067 let mt = self.raw_metatable()?;
1068 if mt != other.raw_metatable()? {
1069 return Ok(false);
1070 }
1071
1072 if let Some(eq) = mt.get::<Option<Function>>("__eq")? {
1073 return eq.call((self, other));
1074 }
1075
1076 Ok(false)
1077 }
1078
1079 /// Returns `true` if this [`AnyUserData`] is serializable (e.g. was created using
1080 /// [`Lua::create_ser_userdata`]).
1081 #[cfg(feature = "serde")]
1082 pub(crate) fn is_serializable(&self) -> bool {
1083 let lua = self.0.lua.lock();
1084 let is_serializable = || unsafe {
1085 // Userdata must be registered and not destructed
1086 let _ = lua.get_userdata_ref_type_id(&self.0)?;
1087 let ud = &*get_userdata::<UserDataStorage<()>>(lua.ref_thread(), self.0.index);
1088 Ok::<_, Error>(ud.is_serializable())
1089 };
1090 is_serializable().unwrap_or(false)
1091 }
1092
1093 unsafe fn invoke_tostring_dbg(&self) -> Result<Option<String>> {
1094 let lua = self.0.lua.lock();
1095 let state = lua.state();
1096 let _guard = StackGuard::new(state);
1097 check_stack(state, 3)?;
1098
1099 lua.push_ref(&self.0);
1100 protect_lua!(state, 1, 1, fn(state) {
1101 // Try `__todebugstring` metamethod first, then `__tostring`
1102 #[allow(clippy::collapsible_if)]
1103 if ffi::luaL_callmeta(state, -1, cstr!("__todebugstring")) == 0 {
1104 if ffi::luaL_callmeta(state, -1, cstr!("__tostring")) == 0 {
1105 ffi::lua_pushnil(state);
1106 }
1107 }
1108 })?;
1109 Ok(lua.try_pop_value()?.as_string().map(|s| s.to_string_lossy()))
1110 }
1111
1112 pub(crate) fn fmt_pretty(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1113 // Try converting to a (debug) string first, with fallback to `__name/__type`
1114 match unsafe { self.invoke_tostring_dbg() } {
1115 Ok(Some(s)) => write!(fmt, "{s}"),
1116 _ => {
1117 let name = self.type_name().ok();
1118 let name = (name.as_ref())
1119 .map(|s| Either::Left(s.display()))
1120 .unwrap_or(Either::Right("userdata"));
1121 write!(fmt, "{name}: {:?}", self.to_pointer())
1122 }
1123 }
1124 }
1125}
1126
1127impl fmt::Debug for AnyUserData {
1128 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1129 if fmt.alternate() {
1130 return self.fmt_pretty(fmt);
1131 }
1132 fmt.debug_tuple("AnyUserData").field(&self.0).finish()
1133 }
1134}
1135
1136/// Handle to a [`AnyUserData`] metatable.
1137#[derive(Clone, Debug)]
1138pub struct UserDataMetatable(pub(crate) Table);
1139
1140impl UserDataMetatable {
1141 /// Gets the value associated to `key` from the metatable.
1142 ///
1143 /// If no value is associated to `key`, returns the `Nil` value.
1144 /// Access to restricted metamethods such as `__gc` or `__metatable` will cause an error.
1145 pub fn get<V: FromLua>(&self, key: impl AsRef<str>) -> Result<V> {
1146 self.0.raw_get(MetaMethod::validate(key.as_ref())?)
1147 }
1148
1149 /// Sets a key-value pair in the metatable.
1150 ///
1151 /// If the value is `Nil`, this will effectively remove the `key`.
1152 /// Access to restricted metamethods such as `__gc` or `__metatable` will cause an error.
1153 /// Setting `__index` or `__newindex` metamethods is also restricted because their values are
1154 /// cached for `mlua` internal usage.
1155 pub fn set(&self, key: impl AsRef<str>, value: impl IntoLua) -> Result<()> {
1156 let key = MetaMethod::validate(key.as_ref())?;
1157 // `__index` and `__newindex` cannot be changed in runtime, because values are cached
1158 if key == MetaMethod::Index || key == MetaMethod::NewIndex {
1159 return Err(Error::MetaMethodRestricted(key.to_string()));
1160 }
1161 self.0.raw_set(key, value)
1162 }
1163
1164 /// Checks whether the metatable contains a non-nil value for `key`.
1165 pub fn contains(&self, key: impl AsRef<str>) -> Result<bool> {
1166 self.0.contains_key(MetaMethod::validate(key.as_ref())?)
1167 }
1168
1169 /// Returns an iterator over the pairs of the metatable.
1170 ///
1171 /// The pairs are wrapped in a [`Result`], since they are lazily converted to `V` type.
1172 ///
1173 /// [`Result`]: crate::Result
1174 pub fn pairs<V: FromLua>(&self) -> UserDataMetatablePairs<'_, V> {
1175 UserDataMetatablePairs(self.0.pairs())
1176 }
1177}
1178
1179/// An iterator over the pairs of a [`AnyUserData`] metatable.
1180///
1181/// It skips restricted metamethods, such as `__gc` or `__metatable`.
1182///
1183/// This struct is created by the [`UserDataMetatable::pairs`] method.
1184pub struct UserDataMetatablePairs<'a, V>(TablePairs<'a, String, V>);
1185
1186impl<V> Iterator for UserDataMetatablePairs<'_, V>
1187where
1188 V: FromLua,
1189{
1190 type Item = Result<(String, V)>;
1191
1192 fn next(&mut self) -> Option<Self::Item> {
1193 loop {
1194 match self.0.next()? {
1195 Ok((key, value)) => {
1196 // Skip restricted metamethods
1197 if MetaMethod::validate(&key).is_ok() {
1198 break Some(Ok((key, value)));
1199 }
1200 }
1201 Err(e) => break Some(Err(e)),
1202 }
1203 }
1204 }
1205}
1206
1207#[cfg(feature = "serde")]
1208impl Serialize for AnyUserData {
1209 fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
1210 where
1211 S: Serializer,
1212 {
1213 let lua = self.0.lua.lock();
1214 unsafe {
1215 let _ = lua
1216 .get_userdata_ref_type_id(&self.0)
1217 .map_err(ser::Error::custom)?;
1218 let ud = &*get_userdata::<UserDataStorage<()>>(lua.ref_thread(), self.0.index);
1219 ud.serialize(serializer)
1220 }
1221 }
1222}
1223
1224struct WrappedUserdata<F: FnOnce(&Lua) -> Result<AnyUserData>>(F);
1225
1226impl AnyUserData {
1227 /// Wraps any Rust type, returning an opaque type that implements [`IntoLua`] trait.
1228 ///
1229 /// This function uses [`Lua::create_any_userdata`] under the hood.
1230 pub fn wrap<T: MaybeSend + MaybeSync + 'static>(data: T) -> impl IntoLua {
1231 WrappedUserdata(move |lua| lua.create_any_userdata(data))
1232 }
1233
1234 /// Wraps any Rust type that implements [`Serialize`], returning an opaque type that implements
1235 /// [`IntoLua`] trait.
1236 ///
1237 /// This function uses [`Lua::create_ser_any_userdata`] under the hood.
1238 #[cfg(feature = "serde")]
1239 #[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
1240 pub fn wrap_ser<T: Serialize + MaybeSend + MaybeSync + 'static>(data: T) -> impl IntoLua {
1241 WrappedUserdata(move |lua| lua.create_ser_any_userdata(data))
1242 }
1243}
1244
1245impl<F> IntoLua for WrappedUserdata<F>
1246where
1247 F: for<'l> FnOnce(&'l Lua) -> Result<AnyUserData>,
1248{
1249 fn into_lua(self, lua: &Lua) -> Result<Value> {
1250 (self.0)(lua).map(Value::UserData)
1251 }
1252}
1253
1254mod cell;
1255mod lock;
1256mod object;
1257mod r#ref;
1258mod registry;
1259mod util;
1260
1261#[cfg(test)]
1262mod assertions {
1263 use super::*;
1264
1265 #[cfg(not(feature = "send"))]
1266 static_assertions::assert_not_impl_any!(AnyUserData: Send);
1267 #[cfg(feature = "send")]
1268 static_assertions::assert_impl_all!(AnyUserData: Send, Sync);
1269}