mlua/state.rs
1//! Lua state management.
2//!
3//! This module provides the main [`Lua`] state handle together with state-specific
4//! configuration and garbage collector controls.
5
6use std::any::TypeId;
7use std::cell::{BorrowError, BorrowMutError, RefCell};
8use std::marker::PhantomData;
9use std::ops::Deref;
10use std::os::raw::{c_char, c_int};
11use std::panic::Location;
12use std::result::Result as StdResult;
13use std::{fmt, mem, ptr};
14
15use crate::chunk::{AsChunk, Chunk};
16use crate::debug::Debug;
17use crate::error::{Error, Result};
18use crate::function::Function;
19use crate::memory::MemoryState;
20use crate::multi::MultiValue;
21use crate::scope::Scope;
22use crate::stdlib::StdLib;
23use crate::string::LuaString;
24use crate::table::Table;
25use crate::thread::{Thread, ThreadEvent, ThreadTriggers};
26use crate::traits::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti};
27use crate::types::{
28 AppDataRef, AppDataRefMut, ArcReentrantMutexGuard, Integer, LuaType, MaybeSend, MaybeSync, Number,
29 ReentrantMutex, ReentrantMutexGuard, RegistryKey, VmState, XRc, XWeak,
30};
31use crate::userdata::{AnyUserData, UserData, UserDataProxy, UserDataRegistry, UserDataStorage};
32use crate::util::{StackGuard, assert_stack, check_stack, protect_lua_closure, push_string, rawset_field};
33use crate::value::{Nil, Value};
34
35#[cfg(not(feature = "luau"))]
36use crate::{debug::HookTriggers, types::HookKind};
37
38#[cfg(any(feature = "luau", doc))]
39use crate::{buffer::Buffer, chunk::Compiler};
40
41#[cfg(feature = "async")]
42use {
43 crate::types::LightUserData,
44 std::future::{self, Future},
45 std::task::Poll,
46};
47
48#[cfg(feature = "serde")]
49use serde::Serialize;
50
51pub(crate) use extra::ExtraData;
52#[doc(hidden)]
53pub use raw::RawLua;
54pub(crate) use util::callback_error_ext;
55
56/// Top level Lua struct which represents an instance of Lua VM.
57pub struct Lua {
58 pub(self) raw: XRc<ReentrantMutex<RawLua>>,
59 // Controls whether garbage collection should be run on drop
60 pub(self) collect_garbage: bool,
61}
62
63/// Weak reference to Lua instance.
64///
65/// This can used to prevent circular references between Lua and Rust objects.
66#[derive(Clone)]
67pub struct WeakLua(XWeak<ReentrantMutex<RawLua>>);
68
69pub(crate) struct LuaGuard(ArcReentrantMutexGuard<RawLua>);
70
71/// Tuning parameters for the incremental GC collector.
72///
73/// More information can be found in the Lua [documentation].
74///
75/// [documentation]: https://www.lua.org/manual/5.5/manual.html#2.5.1
76#[non_exhaustive]
77#[derive(Clone, Copy, Debug, Default)]
78pub struct GcIncParams {
79 /// Pause between successive GC cycles, expressed as a percentage of live memory.
80 #[cfg(not(feature = "luau"))]
81 #[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
82 pub pause: Option<c_int>,
83
84 /// Target heap size as a percentage of live data, controlling how aggressively
85 /// the GC reclaims memory (`LUA_GCSETGOAL`).
86 #[cfg(any(feature = "luau", doc))]
87 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
88 pub goal: Option<c_int>,
89
90 /// GC work performed per unit of memory allocated.
91 pub step_multiplier: Option<c_int>,
92
93 /// Granularity of each GC step (see Lua reference for details).
94 #[cfg(any(feature = "lua55", feature = "lua54", feature = "luau"))]
95 #[cfg_attr(docsrs, doc(cfg(any(feature = "lua55", feature = "lua54", feature = "luau"))))]
96 pub step_size: Option<c_int>,
97}
98
99impl GcIncParams {
100 /// Sets the `pause` parameter.
101 #[cfg(not(feature = "luau"))]
102 #[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
103 pub fn pause(mut self, v: c_int) -> Self {
104 self.pause = Some(v);
105 self
106 }
107
108 /// Sets the `goal` parameter.
109 #[cfg(any(feature = "luau", doc))]
110 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
111 pub fn goal(mut self, v: c_int) -> Self {
112 self.goal = Some(v);
113 self
114 }
115
116 /// Sets the `step_multiplier` parameter.
117 pub fn step_multiplier(mut self, v: c_int) -> Self {
118 self.step_multiplier = Some(v);
119 self
120 }
121
122 /// Sets the `step_size` parameter.
123 #[cfg(any(feature = "lua55", feature = "lua54", feature = "luau"))]
124 #[cfg_attr(docsrs, doc(cfg(any(feature = "lua55", feature = "lua54", feature = "luau"))))]
125 pub fn step_size(mut self, v: c_int) -> Self {
126 self.step_size = Some(v);
127 self
128 }
129}
130
131/// Tuning parameters for the generational GC collector (Lua 5.4+).
132///
133/// More information can be found in the Lua [documentation].
134///
135/// [documentation]: https://www.lua.org/manual/5.5/manual.html#2.5.2
136#[cfg(any(feature = "lua55", feature = "lua54"))]
137#[cfg_attr(docsrs, doc(cfg(any(feature = "lua55", feature = "lua54"))))]
138#[non_exhaustive]
139#[derive(Clone, Copy, Debug, Default)]
140pub struct GcGenParams {
141 /// Frequency of minor (young-generation) collection steps.
142 pub minor_multiplier: Option<c_int>,
143
144 /// Threshold controlling how large the young generation can grow before triggering
145 /// a shift from minor to major collection.
146 pub minor_to_major: Option<c_int>,
147
148 /// Threshold controlling how much the major collection must shrink the heap before
149 /// switching back to minor (young-generation) collection.
150 #[cfg(feature = "lua55")]
151 #[cfg_attr(docsrs, doc(cfg(feature = "lua55")))]
152 pub major_to_minor: Option<c_int>,
153}
154
155#[cfg(any(feature = "lua55", feature = "lua54"))]
156impl GcGenParams {
157 /// Sets the `minor_multiplier` parameter.
158 pub fn minor_multiplier(mut self, v: c_int) -> Self {
159 self.minor_multiplier = Some(v);
160 self
161 }
162
163 /// Sets the `minor_to_major` threshold.
164 pub fn minor_to_major(mut self, v: c_int) -> Self {
165 self.minor_to_major = Some(v);
166 self
167 }
168
169 /// Sets the `major_to_minor` parameter.
170 #[cfg(feature = "lua55")]
171 #[cfg_attr(docsrs, doc(cfg(feature = "lua55")))]
172 pub fn major_to_minor(mut self, v: c_int) -> Self {
173 self.major_to_minor = Some(v);
174 self
175 }
176}
177
178/// Lua garbage collector (GC) operating mode.
179///
180/// Use [`Lua::gc_set_mode`] to switch the collector mode and/or tune its parameters.
181#[non_exhaustive]
182#[derive(Clone, Debug)]
183pub enum GcMode {
184 /// Incremental mark-and-sweep
185 Incremental(GcIncParams),
186
187 /// Generational
188 #[cfg(any(feature = "lua55", feature = "lua54"))]
189 #[cfg_attr(docsrs, doc(cfg(any(feature = "lua55", feature = "lua54"))))]
190 Generational(GcGenParams),
191}
192
193/// Controls Lua interpreter behavior such as Rust panics handling.
194#[derive(Clone, Debug)]
195#[non_exhaustive]
196pub struct LuaOptions {
197 /// Catch Rust panics when using [`pcall`]/[`xpcall`].
198 ///
199 /// If disabled, wraps these functions and automatically resumes panic if found.
200 /// Also in Lua 5.1 adds ability to provide arguments to [`xpcall`] similar to Lua >= 5.2.
201 ///
202 /// If enabled, keeps [`pcall`]/[`xpcall`] unmodified.
203 /// Panics are still automatically resumed if returned to the Rust side.
204 ///
205 /// Default: **true**
206 ///
207 /// [`pcall`]: https://www.lua.org/manual/5.4/manual.html#pdf-pcall
208 /// [`xpcall`]: https://www.lua.org/manual/5.4/manual.html#pdf-xpcall
209 pub catch_rust_panics: bool,
210
211 /// Max size of thread (coroutine) object pool used to execute asynchronous functions.
212 ///
213 /// Default: **0** (disabled)
214 ///
215 /// [`lua_resetthread`]: https://www.lua.org/manual/5.4/manual.html#lua_resetthread
216 #[cfg(feature = "async")]
217 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
218 pub thread_pool_size: usize,
219}
220
221impl Default for LuaOptions {
222 fn default() -> Self {
223 const { LuaOptions::new() }
224 }
225}
226
227impl LuaOptions {
228 /// Returns a new instance of `LuaOptions` with default parameters.
229 pub const fn new() -> Self {
230 LuaOptions {
231 catch_rust_panics: true,
232 #[cfg(feature = "async")]
233 thread_pool_size: 0,
234 }
235 }
236
237 /// Sets [`catch_rust_panics`] option.
238 ///
239 /// [`catch_rust_panics`]: #structfield.catch_rust_panics
240 #[must_use]
241 pub const fn catch_rust_panics(mut self, enabled: bool) -> Self {
242 self.catch_rust_panics = enabled;
243 self
244 }
245
246 /// Sets [`thread_pool_size`] option.
247 ///
248 /// [`thread_pool_size`]: #structfield.thread_pool_size
249 #[cfg(feature = "async")]
250 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
251 #[must_use]
252 pub const fn thread_pool_size(mut self, size: usize) -> Self {
253 self.thread_pool_size = size;
254 self
255 }
256}
257
258impl Drop for Lua {
259 fn drop(&mut self) {
260 if self.collect_garbage {
261 let _ = self.gc_collect();
262 }
263 }
264}
265
266impl Clone for Lua {
267 #[inline]
268 fn clone(&self) -> Self {
269 Lua {
270 raw: XRc::clone(&self.raw),
271 collect_garbage: false,
272 }
273 }
274}
275
276impl fmt::Debug for Lua {
277 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
278 write!(f, "Lua({:p})", self.lock().state())
279 }
280}
281
282impl Default for Lua {
283 #[inline]
284 fn default() -> Self {
285 Lua::new()
286 }
287}
288
289impl Lua {
290 /// Creates a new Lua state and loads the **safe** subset of the standard libraries.
291 ///
292 /// # Safety
293 /// The created Lua state will have _some_ safety guarantees and will not allow to load unsafe
294 /// standard libraries or C modules.
295 ///
296 /// See [`StdLib`] documentation for a list of unsafe modules that cannot be loaded.
297 pub fn new() -> Lua {
298 mlua_expect!(
299 Self::new_with(StdLib::ALL_SAFE, LuaOptions::default()),
300 "Cannot create a Lua state"
301 )
302 }
303
304 /// Creates a new Lua state and loads all the standard libraries.
305 ///
306 /// # Safety
307 /// The created Lua state will not have safety guarantees and will allow to load C modules.
308 pub unsafe fn unsafe_new() -> Lua {
309 Self::unsafe_new_with(StdLib::ALL, LuaOptions::default())
310 }
311
312 /// Creates a new Lua state and loads the specified safe subset of the standard libraries.
313 ///
314 /// Use the [`StdLib`] flags to specify the libraries you want to load.
315 ///
316 /// # Safety
317 /// The created Lua state will have _some_ safety guarantees and will not allow to load unsafe
318 /// standard libraries or C modules.
319 ///
320 /// See [`StdLib`] documentation for a list of unsafe modules that cannot be loaded.
321 pub fn new_with(libs: StdLib, options: LuaOptions) -> Result<Lua> {
322 #[cfg(not(feature = "luau"))]
323 if libs.contains(StdLib::DEBUG) {
324 return Err(Error::SafetyError(
325 "The unsafe `debug` module can't be loaded using safe `new_with`".to_string(),
326 ));
327 }
328 #[cfg(feature = "luajit")]
329 if libs.contains(StdLib::FFI) {
330 return Err(Error::SafetyError(
331 "The unsafe `ffi` module can't be loaded using safe `new_with`".to_string(),
332 ));
333 }
334
335 let lua = unsafe { Self::inner_new(libs, options) };
336
337 #[cfg(not(feature = "luau"))]
338 if libs.contains(StdLib::PACKAGE) {
339 mlua_expect!(lua.disable_c_modules(), "Error disabling C modules");
340 }
341 lua.lock().mark_safe();
342
343 Ok(lua)
344 }
345
346 /// Creates a new Lua state and loads the specified subset of the standard libraries.
347 ///
348 /// Use the [`StdLib`] flags to specify the libraries you want to load.
349 ///
350 /// # Safety
351 /// The created Lua state will not have safety guarantees and allow to load C modules.
352 pub unsafe fn unsafe_new_with(libs: StdLib, options: LuaOptions) -> Lua {
353 // Workaround to avoid stripping a few unused Lua symbols that could be imported
354 // by C modules in unsafe mode
355 let mut _symbols: Vec<*const extern "C-unwind" fn()> =
356 vec![ffi::lua_isuserdata as _, ffi::lua_tocfunction as _];
357
358 #[cfg(not(feature = "luau"))]
359 _symbols.extend_from_slice(&[
360 ffi::lua_atpanic as _,
361 ffi::luaL_loadstring as _,
362 ffi::luaL_openlibs as _,
363 ]);
364 #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua52"))]
365 {
366 _symbols.push(ffi::lua_getglobal as _);
367 _symbols.push(ffi::lua_setglobal as _);
368 _symbols.push(ffi::luaL_setfuncs as _);
369 }
370
371 Self::inner_new(libs, options)
372 }
373
374 /// Creates a new Lua state with required `libs` and `options`
375 unsafe fn inner_new(libs: StdLib, options: LuaOptions) -> Lua {
376 let lua = Lua {
377 raw: RawLua::new(libs, &options),
378 collect_garbage: true,
379 };
380
381 #[cfg(feature = "luau")]
382 mlua_expect!(lua.configure_luau(), "Error configuring Luau");
383
384 lua
385 }
386
387 /// Returns or constructs Lua instance from a raw state.
388 ///
389 /// Once initialized, the returned Lua instance is cached in the registry and can be retrieved
390 /// by calling this function again.
391 ///
392 /// # Safety
393 /// The `Lua` must outlive the chosen lifetime `'a`.
394 #[inline]
395 pub unsafe fn get_or_init_from_ptr<'a>(state: *mut ffi::lua_State) -> &'a Lua {
396 debug_assert!(!state.is_null(), "Lua state is null");
397 match ExtraData::get(state) {
398 extra if !extra.is_null() => (*extra).lua(),
399 _ => {
400 // The `owned` flag is set to `false` as we don't own the Lua state.
401 RawLua::init_from_ptr(state, false);
402 (*ExtraData::get(state)).lua()
403 }
404 }
405 }
406
407 /// Calls provided function passing a raw lua state.
408 ///
409 /// The arguments will be pushed onto the stack before calling the function.
410 ///
411 /// This method ensures that the Lua instance is locked while the function is called
412 /// and restores Lua stack after the function returns.
413 ///
414 /// # Example
415 /// ```
416 /// # use mlua::{Lua, Result};
417 /// # fn main() -> Result<()> {
418 /// let lua = Lua::new();
419 /// let n: i32 = unsafe {
420 /// let nums = (3, 4, 5);
421 /// lua.exec_raw(nums, |state| {
422 /// let n = ffi::lua_gettop(state);
423 /// let mut sum = 0;
424 /// for i in 1..=n {
425 /// sum += ffi::lua_tointeger(state, i);
426 /// }
427 /// ffi::lua_pop(state, n);
428 /// ffi::lua_pushinteger(state, sum);
429 /// })
430 /// }?;
431 /// assert_eq!(n, 12);
432 /// # Ok(())
433 /// # }
434 /// ```
435 #[allow(clippy::missing_safety_doc)]
436 pub unsafe fn exec_raw<R: FromLuaMulti>(
437 &self,
438 args: impl IntoLuaMulti,
439 f: impl FnOnce(*mut ffi::lua_State),
440 ) -> Result<R> {
441 let lua = self.lock();
442 let state = lua.state();
443 let _sg = StackGuard::new(state);
444 let stack_start = ffi::lua_gettop(state);
445 let nargs = args.push_into_stack_multi(&lua)?;
446 check_stack(state, 3)?;
447 protect_lua_closure::<_, ()>(state, nargs, ffi::LUA_MULTRET, f)?;
448 let nresults = ffi::lua_gettop(state) - stack_start;
449 R::from_stack_multi(nresults, &lua)
450 }
451
452 /// Calls provided function passing a reference to the [`RawLua`] handle.
453 ///
454 /// Provided [`RawLua`] handle can be used to manually pushing/popping values to/from the stack.
455 ///
456 /// # Example
457 /// ```
458 /// # use mlua::{Lua, Result, FromLua, IntoLua, IntoLuaMulti};
459 /// # fn main() -> Result<()> {
460 /// let lua = Lua::new();
461 /// let n: i32 = {
462 /// let nums = (3, 4, 5);
463 /// lua.exec_raw_lua(|rawlua| unsafe {
464 /// nums.push_into_stack_multi(rawlua)?;
465 /// let mut sum = 0;
466 /// for _ in 0..3 {
467 /// sum += rawlua.pop::<i32>()?;
468 /// }
469 /// Result::Ok(sum)
470 /// })
471 /// }?;
472 /// assert_eq!(n, 12);
473 /// # Ok(())
474 /// # }
475 /// ```
476 #[doc(hidden)]
477 pub fn exec_raw_lua<R>(&self, f: impl FnOnce(&RawLua) -> R) -> R {
478 let lua = self.lock();
479 f(&lua)
480 }
481
482 /// Loads the specified subset of the standard libraries into an existing Lua state.
483 ///
484 /// Use the [`StdLib`] flags to specify the libraries you want to load.
485 pub fn load_std_libs(&self, libs: StdLib) -> Result<()> {
486 unsafe { self.lock().load_std_libs(libs) }
487 }
488
489 /// Registers module into an existing Lua state using the specified value.
490 ///
491 /// After registration, the given value will always be immediately returned when the
492 /// given module is [required].
493 ///
494 /// [required]: https://www.lua.org/manual/5.4/manual.html#pdf-require
495 pub fn register_module(&self, modname: &str, value: impl IntoLua) -> Result<()> {
496 #[cfg(not(feature = "luau"))]
497 const LOADED_MODULES_KEY: *const c_char = ffi::LUA_LOADED_TABLE;
498 #[cfg(feature = "luau")]
499 const LOADED_MODULES_KEY: *const c_char = ffi::LUA_REGISTERED_MODULES_TABLE;
500
501 if cfg!(feature = "luau") && !modname.starts_with('@') {
502 return Err(Error::runtime("module name must begin with '@'"));
503 }
504 #[cfg(feature = "luau")]
505 let modname = modname.to_ascii_lowercase();
506 unsafe {
507 self.exec_raw::<()>(value, |state| {
508 ffi::luaL_getsubtable(state, ffi::LUA_REGISTRYINDEX, LOADED_MODULES_KEY);
509 ffi::lua_pushlstring(state, modname.as_ptr() as *const c_char, modname.len() as _);
510 ffi::lua_pushvalue(state, -3);
511 ffi::lua_rawset(state, -3);
512 })
513 }
514 }
515
516 /// Preloads module into an existing Lua state using the specified loader function.
517 ///
518 /// When the module is required, the loader function will be called with module name as the
519 /// first argument.
520 ///
521 /// This is similar to setting the [`package.preload[modname]`] field.
522 ///
523 /// [`package.preload[modname]`]: <https://www.lua.org/manual/5.4/manual.html#pdf-package.preload>
524 #[cfg(not(feature = "luau"))]
525 #[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
526 pub fn preload_module(&self, modname: &str, func: Function) -> Result<()> {
527 #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua52"))]
528 let preload = unsafe {
529 self.exec_raw::<Option<Table>>((), |state| {
530 ffi::lua_getfield(state, ffi::LUA_REGISTRYINDEX, ffi::LUA_PRELOAD_TABLE);
531 })?
532 };
533 #[cfg(any(feature = "lua51", feature = "luajit"))]
534 let preload = unsafe {
535 self.exec_raw::<Option<Table>>((), |state| {
536 if ffi::lua_getfield(state, ffi::LUA_REGISTRYINDEX, ffi::LUA_LOADED_TABLE) != ffi::LUA_TNIL {
537 ffi::luaL_getsubtable(state, -1, ffi::LUA_LOADLIBNAME);
538 ffi::luaL_getsubtable(state, -1, cstr!("preload"));
539 ffi::lua_rotate(state, 1, 1);
540 }
541 })?
542 };
543 if let Some(preload) = preload {
544 preload.raw_set(modname, func)?;
545 }
546 Ok(())
547 }
548
549 /// Unloads module `modname`.
550 ///
551 /// This method does not support unloading binary Lua modules since they are internally cached
552 /// and can be unloaded only by closing Lua state.
553 ///
554 /// This is similar to calling [`Lua::register_module`] with `Nil` value.
555 ///
556 /// [`package.loaded`]: https://www.lua.org/manual/5.4/manual.html#pdf-package.loaded
557 pub fn unload_module(&self, modname: &str) -> Result<()> {
558 self.register_module(modname, Nil)
559 }
560
561 // Executes module entrypoint function, which returns only one Value.
562 // The returned value then pushed onto the stack.
563 #[doc(hidden)]
564 #[cfg(not(tarpaulin_include))]
565 pub unsafe fn entrypoint<F, A, R>(state: *mut ffi::lua_State, func: F) -> c_int
566 where
567 F: FnOnce(&Lua, A) -> Result<R>,
568 A: FromLuaMulti,
569 R: IntoLua,
570 {
571 // Make sure that Lua is initialized
572 let _ = Self::get_or_init_from_ptr(state);
573
574 callback_error_ext(state, ptr::null_mut(), true, move |extra, nargs| {
575 let rawlua = (*extra).raw_lua();
576 let args = A::from_stack_args(nargs, 1, None, rawlua)?;
577 func(rawlua.lua(), args)?.push_into_stack(rawlua)?;
578 Ok(1)
579 })
580 }
581
582 // A simple module entrypoint without arguments
583 #[doc(hidden)]
584 #[cfg(not(tarpaulin_include))]
585 pub unsafe fn entrypoint1<F, R>(state: *mut ffi::lua_State, func: F) -> c_int
586 where
587 F: FnOnce(&Lua) -> Result<R>,
588 R: IntoLua,
589 {
590 Self::entrypoint(state, move |lua, _: ()| func(lua))
591 }
592
593 /// Skips memory checks for some operations.
594 #[doc(hidden)]
595 #[cfg(feature = "module")]
596 pub fn skip_memory_check(&self, skip: bool) {
597 let lua = self.lock();
598 unsafe { (*lua.extra.get()).skip_memory_check = skip };
599 }
600
601 /// Enables (or disables) sandbox mode on this Lua instance.
602 ///
603 /// This method, in particular:
604 /// - Set all libraries to read-only
605 /// - Set all builtin metatables to read-only
606 /// - Set globals to read-only (and activates safeenv)
607 /// - Setup local environment table that performs writes locally and proxies reads to the global
608 /// environment.
609 /// - Allow only `count` mode in `collectgarbage` function.
610 ///
611 /// # Examples
612 ///
613 /// ```
614 /// # use mlua::{Lua, Result};
615 /// # #[cfg(feature = "luau")]
616 /// # fn main() -> Result<()> {
617 /// let lua = Lua::new();
618 ///
619 /// lua.sandbox(true)?;
620 /// lua.load("var = 123").exec()?;
621 /// assert_eq!(lua.globals().get::<u32>("var")?, 123);
622 ///
623 /// // Restore the global environment (clear changes made in sandbox)
624 /// lua.sandbox(false)?;
625 /// assert_eq!(lua.globals().get::<Option<u32>>("var")?, None);
626 /// # Ok(())
627 /// # }
628 ///
629 /// # #[cfg(not(feature = "luau"))]
630 /// # fn main() {}
631 /// ```
632 #[cfg(any(feature = "luau", doc))]
633 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
634 pub fn sandbox(&self, enabled: bool) -> Result<()> {
635 let lua = self.lock();
636 unsafe {
637 if (*lua.extra.get()).sandboxed != enabled {
638 let state = lua.main_state();
639 check_stack(state, 3)?;
640 protect_lua!(state, 0, 0, |state| {
641 if enabled {
642 ffi::luaL_sandbox(state, 1);
643 ffi::luaL_sandboxthread(state);
644 } else {
645 // Restore original `LUA_GLOBALSINDEX`
646 ffi::lua_xpush(lua.ref_thread(), state, ffi::LUA_GLOBALSINDEX);
647 ffi::lua_replace(state, ffi::LUA_GLOBALSINDEX);
648 ffi::luaL_sandbox(state, 0);
649 }
650 })?;
651 (*lua.extra.get()).sandboxed = enabled;
652 }
653 Ok(())
654 }
655 }
656
657 /// Sets or replaces a global hook function that will periodically be called as Lua code
658 /// executes.
659 ///
660 /// All new threads created (by mlua) after this call will use the global hook function.
661 ///
662 /// For more information see [`Lua::set_hook`].
663 #[cfg(not(feature = "luau"))]
664 #[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
665 pub fn set_global_hook<F>(&self, triggers: HookTriggers, callback: F) -> Result<()>
666 where
667 F: Fn(&Lua, &Debug) -> Result<VmState> + MaybeSend + 'static,
668 {
669 let lua = self.lock();
670 unsafe {
671 (*lua.extra.get()).hook_triggers = triggers;
672 (*lua.extra.get()).hook_callback = Some(XRc::new(callback));
673 lua.set_thread_hook(lua.state(), HookKind::Global)
674 }
675 }
676
677 /// Sets a hook function that will periodically be called as Lua code executes.
678 ///
679 /// When exactly the hook function is called depends on the contents of the `triggers`
680 /// parameter, see [`HookTriggers`] for more details.
681 ///
682 /// The provided hook function can error, and this error will be propagated through the Lua code
683 /// that was executing at the time the hook was triggered. This can be used to implement a
684 /// limited form of execution limits by setting [`HookTriggers.every_nth_instruction`] and
685 /// erroring once an instruction limit has been reached.
686 ///
687 /// This method sets a hook function for the *current* thread of this Lua instance.
688 /// If you want to set a hook function for another thread (coroutine), use
689 /// [`Thread::set_hook`] instead.
690 ///
691 /// # Example
692 ///
693 /// Shows each line number of code being executed by the Lua interpreter.
694 ///
695 /// ```
696 /// # use mlua::{Lua, HookTriggers, Result, VmState};
697 /// # fn main() -> Result<()> {
698 /// let lua = Lua::new();
699 /// lua.set_hook(HookTriggers::EVERY_LINE, |_lua, debug| {
700 /// println!("line {:?}", debug.current_line());
701 /// Ok(VmState::Continue)
702 /// });
703 ///
704 /// lua.load(r#"
705 /// local x = 2 + 3
706 /// local y = x * 63
707 /// local z = string.len(x..", "..y)
708 /// "#).exec()
709 /// # }
710 /// ```
711 ///
712 /// [`HookTriggers.every_nth_instruction`]: crate::HookTriggers::every_nth_instruction
713 #[cfg(not(feature = "luau"))]
714 #[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
715 pub fn set_hook<F>(&self, triggers: HookTriggers, callback: F) -> Result<()>
716 where
717 F: Fn(&Lua, &Debug) -> Result<VmState> + MaybeSend + 'static,
718 {
719 let lua = self.lock();
720 unsafe { lua.set_thread_hook(lua.state(), HookKind::Thread(triggers, XRc::new(callback))) }
721 }
722
723 /// Removes a global hook previously set by [`Lua::set_global_hook`].
724 ///
725 /// This function has no effect if a hook was not previously set.
726 #[cfg(not(feature = "luau"))]
727 #[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
728 pub fn remove_global_hook(&self) {
729 let lua = self.lock();
730 unsafe {
731 (*lua.extra.get()).hook_callback = None;
732 (*lua.extra.get()).hook_triggers = HookTriggers::default();
733 }
734 }
735
736 /// Removes any hook from the current thread.
737 ///
738 /// This function has no effect if a hook was not previously set.
739 #[cfg(not(feature = "luau"))]
740 #[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
741 pub fn remove_hook(&self) {
742 let lua = self.lock();
743 unsafe {
744 ffi::lua_sethook(lua.state(), None, 0, 0);
745 }
746 }
747
748 /// Sets an interrupt function that will periodically be called by Luau VM.
749 ///
750 /// Any Luau code is guaranteed to call this handler "eventually"
751 /// (in practice this can happen at any function call or at any loop iteration).
752 /// This is similar to `Lua::set_hook` but in more simplified form.
753 ///
754 /// The provided interrupt function can error, and this error will be propagated through
755 /// the Luau code that was executing at the time the interrupt was triggered.
756 /// Also this can be used to implement continuous execution limits by instructing Luau VM to
757 /// yield by returning [`VmState::Yield`]. The yield will happen only at yieldable points
758 /// of execution (not across metamethod/C-call boundaries).
759 ///
760 /// # Example
761 ///
762 /// Periodically yield Luau VM to suspend execution.
763 ///
764 /// ```
765 /// # use std::sync::{Arc, atomic::{AtomicU64, Ordering}};
766 /// # use mlua::{Lua, Result, ThreadStatus, VmState};
767 /// # #[cfg(feature = "luau")]
768 /// # fn main() -> Result<()> {
769 /// let lua = Lua::new();
770 /// let count = Arc::new(AtomicU64::new(0));
771 /// lua.set_interrupt(move |_| {
772 /// if count.fetch_add(1, Ordering::Relaxed) % 2 == 0 {
773 /// return Ok(VmState::Yield);
774 /// }
775 /// Ok(VmState::Continue)
776 /// });
777 ///
778 /// let co = lua.create_thread(
779 /// lua.load(r#"
780 /// local b = 0
781 /// for _, x in ipairs({1, 2, 3}) do b += x end
782 /// "#)
783 /// .into_function()?,
784 /// )?;
785 /// while co.status() == ThreadStatus::Resumable {
786 /// co.resume::<()>(())?;
787 /// }
788 /// # Ok(())
789 /// # }
790 ///
791 /// # #[cfg(not(feature = "luau"))]
792 /// # fn main() {}
793 /// ```
794 #[cfg(any(feature = "luau", doc))]
795 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
796 pub fn set_interrupt<F>(&self, callback: F)
797 where
798 F: Fn(&Lua) -> Result<VmState> + MaybeSend + 'static,
799 {
800 unsafe extern "C-unwind" fn interrupt_proc(state: *mut ffi::lua_State, gc: c_int) {
801 if gc >= 0 {
802 // We don't support GC interrupts since they cannot survive Lua exceptions
803 return;
804 }
805 let result = callback_error_ext(state, ptr::null_mut(), false, move |extra, _| {
806 let interrupt_cb = (*extra).interrupt_callback.clone();
807 let interrupt_cb = mlua_expect!(interrupt_cb, "no interrupt callback set in interrupt_proc");
808 if XRc::strong_count(&interrupt_cb) > 2 {
809 return Ok(VmState::Continue); // Don't allow recursion
810 }
811 interrupt_cb((*extra).lua())
812 });
813 match result {
814 VmState::Continue => {}
815 VmState::Yield => {
816 // We can yield only at yieldable points, otherwise ignore and continue
817 if ffi::lua_isyieldable(state) != 0 {
818 ffi::lua_yield(state, 0);
819 }
820 }
821 }
822 }
823
824 // Set interrupt callback
825 let lua = self.lock();
826 unsafe {
827 (*lua.extra.get()).interrupt_callback = Some(XRc::new(callback));
828 (*ffi::lua_callbacks(lua.main_state())).interrupt = Some(interrupt_proc);
829 }
830 }
831
832 /// Removes any interrupt function previously set by `set_interrupt`.
833 ///
834 /// This function has no effect if an 'interrupt' was not previously set.
835 #[cfg(any(feature = "luau", doc))]
836 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
837 pub fn remove_interrupt(&self) {
838 let lua = self.lock();
839 unsafe {
840 (*lua.extra.get()).interrupt_callback = None;
841 (*ffi::lua_callbacks(lua.main_state())).interrupt = None;
842 }
843 }
844
845 /// Sets a callback invoked when thread lifecycle events occur.
846 ///
847 /// `triggers` controls which events trigger the callback, see [`ThreadTriggers`] for more
848 /// details.
849 ///
850 /// Only one callback can be registered at a time. Calling this again replaces the previous
851 /// callback and its triggers.
852 ///
853 /// # Example
854 ///
855 /// Subscribe only to yield events:
856 ///
857 /// ```
858 /// # use mlua::{Lua, Result, ThreadTriggers, ThreadEvent};
859 /// # fn main() -> Result<()> {
860 /// let lua = Lua::new();
861 /// lua.set_thread_event_callback(
862 /// ThreadTriggers::ON_YIELD,
863 /// |_lua, event| {
864 /// if let ThreadEvent::Yield(thread) = event {
865 /// println!("thread yielded");
866 /// }
867 /// Ok(())
868 /// },
869 /// );
870 /// # Ok(())
871 /// # }
872 /// ```
873 pub fn set_thread_event_callback<F>(&self, triggers: ThreadTriggers, callback: F)
874 where
875 F: Fn(&Lua, ThreadEvent) -> Result<()> + MaybeSend + 'static,
876 {
877 let lua = self.lock();
878 unsafe {
879 (*lua.extra.get()).thread_triggers = triggers;
880 (*lua.extra.get()).thread_event_callback = Some(XRc::new(callback));
881 #[cfg(feature = "luau")]
882 {
883 let proc = Self::userthread_proc as _;
884 (*ffi::lua_callbacks(lua.main_state())).userthread = triggers.on_create.then(|| proc);
885 }
886 }
887 }
888
889 /// Removes the thread event callback previously set by [`Lua::set_thread_event_callback`].
890 ///
891 /// This function has no effect if a callback was not previously set.
892 pub fn remove_thread_event_callback(&self) {
893 let lua = self.lock();
894 let extra = lua.extra.get();
895 unsafe {
896 (*extra).thread_triggers = ThreadTriggers::new();
897 (*extra).thread_event_callback = None;
898 #[cfg(feature = "luau")]
899 {
900 (*ffi::lua_callbacks(lua.main_state())).userthread = None;
901 }
902 }
903 }
904
905 #[cfg(feature = "luau")]
906 unsafe extern "C-unwind" fn userthread_proc(parent: *mut ffi::lua_State, child: *mut ffi::lua_State) {
907 // Only handle thread creation
908 if parent.is_null() {
909 return;
910 }
911
912 let extra = ExtraData::get(child);
913 if !(*extra).thread_triggers.on_create {
914 return;
915 }
916 let callback = match &(*extra).thread_event_callback {
917 Some(cb) if XRc::strong_count(cb) == 1 => cb.clone(),
918 _ => return,
919 };
920 ffi::lua_pushthread(child);
921 ffi::lua_xmove(child, (*extra).ref_thread, 1);
922 let thread = Thread((*extra).raw_lua().pop_ref_thread(), child);
923 callback_error_ext(parent, extra, false, move |extra, _| {
924 callback((*extra).lua(), ThreadEvent::Create(thread))
925 })
926 }
927
928 /// Sets the warning function to be used by Lua to emit warnings.
929 #[cfg(any(feature = "lua55", feature = "lua54"))]
930 #[cfg_attr(docsrs, doc(cfg(any(feature = "lua55", feature = "lua54"))))]
931 pub fn set_warning_function<F>(&self, callback: F)
932 where
933 F: Fn(&Lua, &str, bool) -> Result<()> + MaybeSend + 'static,
934 {
935 use std::ffi::CStr;
936 use std::os::raw::{c_char, c_void};
937
938 unsafe extern "C-unwind" fn warn_proc(ud: *mut c_void, msg: *const c_char, tocont: c_int) {
939 let extra = ud as *mut ExtraData;
940 callback_error_ext((*extra).raw_lua().state(), extra, false, |extra, _| {
941 let warn_callback = (*extra).warn_callback.clone();
942 let warn_callback = mlua_expect!(warn_callback, "no warning callback set in warn_proc");
943 if XRc::strong_count(&warn_callback) > 2 {
944 return Ok(());
945 }
946 let msg = String::from_utf8_lossy(CStr::from_ptr(msg).to_bytes());
947 warn_callback((*extra).lua(), &msg, tocont != 0)
948 });
949 }
950
951 let lua = self.lock();
952 unsafe {
953 (*lua.extra.get()).warn_callback = Some(XRc::new(callback));
954 ffi::lua_setwarnf(lua.state(), Some(warn_proc), lua.extra.get() as *mut c_void);
955 }
956 }
957
958 /// Removes warning function previously set by `set_warning_function`.
959 ///
960 /// This function has no effect if a warning function was not previously set.
961 #[cfg(any(feature = "lua55", feature = "lua54"))]
962 #[cfg_attr(docsrs, doc(cfg(any(feature = "lua55", feature = "lua54"))))]
963 pub fn remove_warning_function(&self) {
964 let lua = self.lock();
965 unsafe {
966 (*lua.extra.get()).warn_callback = None;
967 ffi::lua_setwarnf(lua.state(), None, ptr::null_mut());
968 }
969 }
970
971 /// Emits a warning with the given message.
972 ///
973 /// A message in a call with `incomplete` set to `true` should be continued in
974 /// another call to this function.
975 #[cfg(any(feature = "lua55", feature = "lua54"))]
976 #[cfg_attr(docsrs, doc(cfg(any(feature = "lua55", feature = "lua54"))))]
977 pub fn warning(&self, msg: impl AsRef<str>, incomplete: bool) {
978 let msg = msg.as_ref();
979 let mut bytes = vec![0; msg.len() + 1];
980 bytes[..msg.len()].copy_from_slice(msg.as_bytes());
981 let real_len = bytes.iter().position(|&c| c == 0).unwrap();
982 bytes.truncate(real_len);
983 let lua = self.lock();
984 unsafe {
985 ffi::lua_warning(lua.state(), bytes.as_ptr() as *const _, incomplete as c_int);
986 }
987 }
988
989 /// Gets information about the interpreter runtime stack at the given level.
990 ///
991 /// This function calls callback `f`, passing the [`struct@Debug`] structure that can be used to
992 /// get information about the function executing at a given level.
993 /// Level `0` is the current running function, whereas level `n+1` is the function that has
994 /// called level `n` (except for tail calls, which do not count in the stack).
995 pub fn inspect_stack<R>(&self, level: usize, f: impl FnOnce(&Debug) -> R) -> Option<R> {
996 let lua = self.lock();
997 unsafe {
998 let mut ar = mem::zeroed::<ffi::lua_Debug>();
999 let level = level as c_int;
1000 #[cfg(not(feature = "luau"))]
1001 if ffi::lua_getstack(lua.state(), level, &mut ar) == 0 {
1002 return None;
1003 }
1004 #[cfg(feature = "luau")]
1005 if ffi::lua_getinfo(lua.state(), level, cstr!(""), &mut ar) == 0 {
1006 return None;
1007 }
1008
1009 Some(f(&Debug::new(&lua, level, &mut ar)))
1010 }
1011 }
1012
1013 /// Creates a traceback of the call stack at the given level.
1014 ///
1015 /// The `msg` parameter, if provided, is added at the beginning of the traceback.
1016 /// The `level` parameter works the same way as in [`Lua::inspect_stack`].
1017 pub fn traceback(&self, msg: Option<&str>, level: usize) -> Result<LuaString> {
1018 let lua = self.lock();
1019 unsafe {
1020 check_stack(lua.state(), 3)?;
1021 protect_lua!(lua.state(), 0, 1, |state| {
1022 let msg = match msg {
1023 Some(s) => ffi::lua_pushlstring(state, s.as_ptr() as *const c_char, s.len()),
1024 None => ptr::null(),
1025 };
1026 // `protect_lua` adds it's own call frame, so we need to increase level by 1
1027 ffi::luaL_traceback(state, state, msg, (level + 1) as c_int);
1028 })?;
1029 Ok(LuaString(lua.pop_ref()))
1030 }
1031 }
1032
1033 /// Returns the amount of memory (in bytes) currently used inside this Lua state.
1034 pub fn used_memory(&self) -> usize {
1035 let lua = self.lock();
1036 let state = lua.main_state();
1037 unsafe {
1038 match MemoryState::get(state) {
1039 mem_state if !mem_state.is_null() => (*mem_state).used_memory(),
1040 _ => {
1041 // Get data from the Lua GC
1042 let used_kbytes = ffi::lua_gc(state, ffi::LUA_GCCOUNT, 0);
1043 let used_kbytes_rem = ffi::lua_gc(state, ffi::LUA_GCCOUNTB, 0);
1044 (used_kbytes as usize) * 1024 + (used_kbytes_rem as usize)
1045 }
1046 }
1047 }
1048 }
1049
1050 /// Sets a memory limit (in bytes) on this Lua state.
1051 ///
1052 /// Once an allocation occurs that would pass this memory limit, a `Error::MemoryError` is
1053 /// generated instead.
1054 /// Returns previous limit (zero means no limit).
1055 ///
1056 /// Does not work in module mode where Lua state is managed externally.
1057 pub fn set_memory_limit(&self, limit: usize) -> Result<usize> {
1058 let lua = self.lock();
1059 unsafe {
1060 match MemoryState::get(lua.state()) {
1061 mem_state if !mem_state.is_null() => Ok((*mem_state).set_memory_limit(limit)),
1062 _ => Err(Error::MemoryControlNotAvailable),
1063 }
1064 }
1065 }
1066
1067 /// Returns `true` if the garbage collector is currently running automatically.
1068 #[cfg(any(
1069 feature = "lua55",
1070 feature = "lua54",
1071 feature = "lua53",
1072 feature = "lua52",
1073 feature = "luau"
1074 ))]
1075 pub fn gc_is_running(&self) -> bool {
1076 let lua = self.lock();
1077 unsafe { ffi::lua_gc(lua.main_state(), ffi::LUA_GCISRUNNING, 0) != 0 }
1078 }
1079
1080 /// Stops the Lua GC from running.
1081 pub fn gc_stop(&self) {
1082 let lua = self.lock();
1083 unsafe { ffi::lua_gc(lua.main_state(), ffi::LUA_GCSTOP, 0) };
1084 }
1085
1086 /// Restarts the Lua GC if it is not running.
1087 pub fn gc_restart(&self) {
1088 let lua = self.lock();
1089 unsafe { ffi::lua_gc(lua.main_state(), ffi::LUA_GCRESTART, 0) };
1090 }
1091
1092 /// Performs a full garbage-collection cycle.
1093 ///
1094 /// It may be necessary to call this function twice to collect all currently unreachable
1095 /// objects. Once to finish the current gc cycle, and once to start and finish the next cycle.
1096 pub fn gc_collect(&self) -> Result<()> {
1097 let lua = self.lock();
1098 let state = lua.main_state();
1099 unsafe {
1100 check_stack(state, 2)?;
1101 protect_lua!(state, 0, 0, fn(state) ffi::lua_gc(state, ffi::LUA_GCCOLLECT, 0))
1102 }
1103 }
1104
1105 /// Performs a basic step of garbage collection.
1106 ///
1107 /// In incremental mode, a basic step corresponds to the current step size. In generational
1108 /// mode, a basic step performs a full minor collection or an incremental step, if the collector
1109 /// has scheduled one.
1110 ///
1111 /// In incremental mode, returns `true` if this step has finished a collection cycle.
1112 /// In generational mode, returns `true` if the step finished a major collection.
1113 pub fn gc_step(&self) -> Result<bool> {
1114 let lua = self.lock();
1115 let state = lua.main_state();
1116 unsafe {
1117 check_stack(state, 3)?;
1118 protect_lua!(state, 0, 0, |state| {
1119 ffi::lua_gc(state, ffi::LUA_GCSTEP, 0) != 0
1120 })
1121 }
1122 }
1123
1124 /// Switches the GC to the given mode with the provided parameters.
1125 ///
1126 /// Returns the previous [`GcMode`]. The returned value's parameter fields are always
1127 /// `None` because Lua's C API does not provide a way to read back current parameter values
1128 /// without changing them.
1129 ///
1130 /// # Examples
1131 ///
1132 /// Switch to generational mode (Lua 5.4+):
1133 /// ```ignore
1134 /// let prev = lua.gc_set_mode(GcMode::Generational(GcGenParams::default()));
1135 /// ```
1136 ///
1137 /// Switch to incremental mode with custom parameters:
1138 /// ```ignore
1139 /// lua.gc_set_mode(GcMode::Incremental(
1140 /// GcIncParams::default().pause(200).step_multiplier(100)
1141 /// ));
1142 /// ```
1143 pub fn gc_set_mode(&self, mode: GcMode) -> GcMode {
1144 let lua = self.lock();
1145 let state = lua.main_state();
1146
1147 match mode {
1148 #[cfg(feature = "lua55")]
1149 GcMode::Incremental(params) => unsafe {
1150 if let Some(v) = params.pause {
1151 ffi::lua_gc(state, ffi::LUA_GCPARAM, ffi::LUA_GCPPAUSE, v);
1152 }
1153 if let Some(v) = params.step_multiplier {
1154 ffi::lua_gc(state, ffi::LUA_GCPARAM, ffi::LUA_GCPSTEPMUL, v);
1155 }
1156 if let Some(v) = params.step_size {
1157 ffi::lua_gc(state, ffi::LUA_GCPARAM, ffi::LUA_GCPSTEPSIZE, v);
1158 }
1159 match ffi::lua_gc(state, ffi::LUA_GCINC) {
1160 ffi::LUA_GCINC => GcMode::Incremental(GcIncParams::default()),
1161 ffi::LUA_GCGEN => GcMode::Generational(GcGenParams::default()),
1162 _ => unreachable!(),
1163 }
1164 },
1165 #[cfg(feature = "lua54")]
1166 GcMode::Incremental(params) => unsafe {
1167 let pause = params.pause.unwrap_or(0);
1168 let step_mul = params.step_multiplier.unwrap_or(0);
1169 let step_size = params.step_size.unwrap_or(0);
1170 match ffi::lua_gc(state, ffi::LUA_GCINC, pause, step_mul, step_size) {
1171 ffi::LUA_GCINC => GcMode::Incremental(GcIncParams::default()),
1172 ffi::LUA_GCGEN => GcMode::Generational(GcGenParams::default()),
1173 _ => unreachable!(),
1174 }
1175 },
1176 #[cfg(any(feature = "lua53", feature = "lua52", feature = "lua51", feature = "luajit"))]
1177 GcMode::Incremental(params) => unsafe {
1178 if let Some(v) = params.pause {
1179 ffi::lua_gc(state, ffi::LUA_GCSETPAUSE, v);
1180 }
1181 if let Some(v) = params.step_multiplier {
1182 ffi::lua_gc(state, ffi::LUA_GCSETSTEPMUL, v);
1183 }
1184 GcMode::Incremental(GcIncParams::default())
1185 },
1186 #[cfg(feature = "luau")]
1187 GcMode::Incremental(params) => unsafe {
1188 if let Some(v) = params.goal {
1189 ffi::lua_gc(state, ffi::LUA_GCSETGOAL, v);
1190 }
1191 if let Some(v) = params.step_multiplier {
1192 ffi::lua_gc(state, ffi::LUA_GCSETSTEPMUL, v);
1193 }
1194 if let Some(v) = params.step_size {
1195 ffi::lua_gc(state, ffi::LUA_GCSETSTEPSIZE, v);
1196 }
1197 GcMode::Incremental(GcIncParams::default())
1198 },
1199
1200 #[cfg(feature = "lua55")]
1201 GcMode::Generational(params) => unsafe {
1202 if let Some(v) = params.minor_multiplier {
1203 ffi::lua_gc(state, ffi::LUA_GCPARAM, ffi::LUA_GCPMINORMUL, v);
1204 }
1205 if let Some(v) = params.minor_to_major {
1206 ffi::lua_gc(state, ffi::LUA_GCPARAM, ffi::LUA_GCPMINORMAJOR, v);
1207 }
1208 if let Some(v) = params.major_to_minor {
1209 ffi::lua_gc(state, ffi::LUA_GCPARAM, ffi::LUA_GCPMAJORMINOR, v);
1210 }
1211 match ffi::lua_gc(state, ffi::LUA_GCGEN) {
1212 ffi::LUA_GCGEN => GcMode::Generational(GcGenParams::default()),
1213 ffi::LUA_GCINC => GcMode::Incremental(GcIncParams::default()),
1214 _ => unreachable!(),
1215 }
1216 },
1217 #[cfg(feature = "lua54")]
1218 GcMode::Generational(params) => unsafe {
1219 let minor = params.minor_multiplier.unwrap_or(0);
1220 let minor_to_major = params.minor_to_major.unwrap_or(0);
1221 match ffi::lua_gc(state, ffi::LUA_GCGEN, minor, minor_to_major) {
1222 ffi::LUA_GCGEN => GcMode::Generational(GcGenParams::default()),
1223 ffi::LUA_GCINC => GcMode::Incremental(GcIncParams::default()),
1224 _ => unreachable!(),
1225 }
1226 },
1227 }
1228 }
1229
1230 /// Sets a default Luau compiler (with custom options).
1231 ///
1232 /// This compiler will be used by default to load all Lua chunks
1233 /// including via `require` function.
1234 ///
1235 /// See [`Compiler`] for details and possible options.
1236 #[cfg(any(feature = "luau", doc))]
1237 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
1238 pub fn set_compiler(&self, compiler: Compiler) {
1239 let lua = self.lock();
1240 unsafe { (*lua.extra.get()).compiler = Some(compiler) };
1241 }
1242
1243 /// Toggles JIT compilation mode for new chunks of code.
1244 ///
1245 /// By default JIT is enabled. Changing this option does not have any effect on
1246 /// already loaded functions.
1247 #[cfg(any(feature = "luau-jit", doc))]
1248 #[cfg_attr(docsrs, doc(cfg(feature = "luau-jit")))]
1249 pub fn enable_jit(&self, enable: bool) {
1250 let lua = self.lock();
1251 unsafe { (*lua.extra.get()).enable_jit = enable };
1252 }
1253
1254 /// Sets Luau feature flag (global setting).
1255 ///
1256 /// See https://github.com/luau-lang/luau/blob/master/CONTRIBUTING.md#feature-flags for details.
1257 #[cfg(feature = "luau")]
1258 #[doc(hidden)]
1259 #[allow(clippy::result_unit_err)]
1260 pub fn set_fflag(name: &str, enabled: bool) -> StdResult<(), ()> {
1261 if let Ok(name) = std::ffi::CString::new(name)
1262 && unsafe { ffi::luau_setfflag(name.as_ptr(), enabled as c_int) != 0 }
1263 {
1264 return Ok(());
1265 }
1266 Err(())
1267 }
1268
1269 /// Returns Lua source code as a `Chunk` builder type.
1270 ///
1271 /// In order to actually compile or run the resulting code, you must call [`Chunk::exec`] or
1272 /// similar on the returned builder. Code is not even parsed until one of these methods is
1273 /// called.
1274 ///
1275 /// [`Chunk::exec`]: crate::Chunk::exec
1276 #[track_caller]
1277 pub fn load<'a>(&self, chunk: impl AsChunk + 'a) -> Chunk<'a> {
1278 self.load_with_location(chunk, Location::caller())
1279 }
1280
1281 pub(crate) fn load_with_location<'a>(
1282 &self,
1283 chunk: impl AsChunk + 'a,
1284 location: &'static Location<'static>,
1285 ) -> Chunk<'a> {
1286 Chunk {
1287 lua: self.weak(),
1288 name: chunk
1289 .name()
1290 .unwrap_or_else(|| format!("@{}:{}", location.file(), location.line())),
1291 env: chunk.environment(self),
1292 mode: chunk.mode(),
1293 source: chunk.source(),
1294 #[cfg(feature = "luau")]
1295 compiler: unsafe { (*self.lock().extra.get()).compiler.clone() },
1296 }
1297 }
1298
1299 /// Creates and returns an interned Lua string.
1300 ///
1301 /// Lua strings can be arbitrary `[u8]` data including embedded nulls, so in addition to `&str`
1302 /// and `&String`, you can also pass plain `&[u8]` here.
1303 #[inline]
1304 pub fn create_string(&self, s: impl AsRef<[u8]>) -> Result<LuaString> {
1305 unsafe { self.lock().create_string(s.as_ref()) }
1306 }
1307
1308 /// Creates and returns an external Lua string.
1309 ///
1310 /// External string is a string where the memory is managed by Rust code, and Lua only holds a
1311 /// reference to it. This can be used to avoid copying large strings into Lua memory.
1312 #[cfg(feature = "lua55")]
1313 #[cfg_attr(docsrs, doc(cfg(feature = "lua55")))]
1314 #[inline]
1315 pub fn create_external_string(&self, s: impl Into<Vec<u8>>) -> Result<LuaString> {
1316 unsafe { self.lock().create_external_string(s.into()) }
1317 }
1318
1319 /// Creates and returns a Luau [buffer] object from a byte slice of data.
1320 ///
1321 /// [buffer]: https://luau.org/library#buffer-library
1322 #[cfg(any(feature = "luau", doc))]
1323 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
1324 pub fn create_buffer(&self, data: impl AsRef<[u8]>) -> Result<Buffer> {
1325 let lua = self.lock();
1326 let data = data.as_ref();
1327 unsafe {
1328 let (ptr, buffer) = lua.create_buffer_with_capacity(data.len())?;
1329 ptr.copy_from_nonoverlapping(data.as_ptr(), data.len());
1330 Ok(buffer)
1331 }
1332 }
1333
1334 /// Creates and returns a Luau [buffer] object with the specified size.
1335 ///
1336 /// Size limit is 1GB. All bytes will be initialized to zero.
1337 ///
1338 /// [buffer]: https://luau.org/library#buffer-library
1339 #[cfg(any(feature = "luau", doc))]
1340 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
1341 pub fn create_buffer_with_capacity(&self, size: usize) -> Result<Buffer> {
1342 unsafe { Ok(self.lock().create_buffer_with_capacity(size)?.1) }
1343 }
1344
1345 /// Creates and returns a new empty table.
1346 #[inline]
1347 pub fn create_table(&self) -> Result<Table> {
1348 self.create_table_with_capacity(0, 0)
1349 }
1350
1351 /// Creates and returns a new empty table, with the specified capacity.
1352 ///
1353 /// - `narr` is a hint for how many elements the table will have as a sequence.
1354 /// - `nrec` is a hint for how many other elements the table will have.
1355 ///
1356 /// Lua may use these hints to preallocate memory for the new table.
1357 pub fn create_table_with_capacity(&self, narr: usize, nrec: usize) -> Result<Table> {
1358 unsafe { self.lock().create_table_with_capacity(narr, nrec) }
1359 }
1360
1361 /// Creates a table and fills it with values from an iterator.
1362 pub fn create_table_from<K, V>(&self, iter: impl IntoIterator<Item = (K, V)>) -> Result<Table>
1363 where
1364 K: IntoLua,
1365 V: IntoLua,
1366 {
1367 unsafe { self.lock().create_table_from(iter) }
1368 }
1369
1370 /// Creates a table from an iterator of values, using `1..` as the keys.
1371 pub fn create_sequence_from<T>(&self, iter: impl IntoIterator<Item = T>) -> Result<Table>
1372 where
1373 T: IntoLua,
1374 {
1375 unsafe { self.lock().create_sequence_from(iter) }
1376 }
1377
1378 /// Wraps a Rust function or closure, creating a callable Lua function handle to it.
1379 ///
1380 /// The function's return value is always a `Result`: If the function returns `Err`, the error
1381 /// is raised as a Lua error, which can be caught using `(x)pcall` or bubble up to the Rust code
1382 /// that invoked the Lua code. This allows using the `?` operator to propagate errors through
1383 /// intermediate Lua code.
1384 ///
1385 /// If the function returns `Ok`, the contained value will be converted to one or more Lua
1386 /// values. For details on Rust-to-Lua conversions, refer to the [`IntoLua`] and
1387 /// [`IntoLuaMulti`] traits.
1388 ///
1389 /// # Examples
1390 ///
1391 /// Create a function which prints its argument:
1392 ///
1393 /// ```
1394 /// # use mlua::{Lua, Result};
1395 /// # fn main() -> Result<()> {
1396 /// # let lua = Lua::new();
1397 /// let greet = lua.create_function(|_, name: String| {
1398 /// println!("Hello, {}!", name);
1399 /// Ok(())
1400 /// });
1401 /// # let _ = greet; // used
1402 /// # Ok(())
1403 /// # }
1404 /// ```
1405 ///
1406 /// Use tuples to accept multiple arguments:
1407 ///
1408 /// ```
1409 /// # use mlua::{Lua, Result};
1410 /// # fn main() -> Result<()> {
1411 /// # let lua = Lua::new();
1412 /// let print_person = lua.create_function(|_, (name, age): (String, u8)| {
1413 /// println!("{} is {} years old!", name, age);
1414 /// Ok(())
1415 /// });
1416 /// # let _ = print_person; // used
1417 /// # Ok(())
1418 /// # }
1419 /// ```
1420 pub fn create_function<F, A, R>(&self, func: F) -> Result<Function>
1421 where
1422 F: Fn(&Lua, A) -> Result<R> + MaybeSend + 'static,
1423 A: FromLuaMulti,
1424 R: IntoLuaMulti,
1425 {
1426 (self.lock()).create_callback(Box::new(move |rawlua, nargs| unsafe {
1427 let args = A::from_stack_args(nargs, 1, None, rawlua)?;
1428 func(rawlua.lua(), args)?.push_into_stack_multi(rawlua)
1429 }))
1430 }
1431
1432 /// Wraps a Rust mutable closure, creating a callable Lua function handle to it.
1433 ///
1434 /// This is a version of [`Lua::create_function`] that accepts a `FnMut` argument.
1435 pub fn create_function_mut<F, A, R>(&self, func: F) -> Result<Function>
1436 where
1437 F: FnMut(&Lua, A) -> Result<R> + MaybeSend + 'static,
1438 A: FromLuaMulti,
1439 R: IntoLuaMulti,
1440 {
1441 let func = RefCell::new(func);
1442 self.create_function(move |lua, args| {
1443 (*func.try_borrow_mut().map_err(|_| Error::RecursiveMutCallback)?)(lua, args)
1444 })
1445 }
1446
1447 /// Wraps a C function, creating a callable Lua function handle to it.
1448 ///
1449 /// # Safety
1450 /// This function is unsafe because provides a way to execute unsafe C function.
1451 pub unsafe fn create_c_function(&self, func: ffi::lua_CFunction) -> Result<Function> {
1452 let lua = self.lock();
1453 if cfg!(any(
1454 feature = "lua55",
1455 feature = "lua54",
1456 feature = "lua53",
1457 feature = "lua52"
1458 )) {
1459 ffi::lua_pushcfunction(lua.ref_thread(), func);
1460 return Ok(Function(lua.pop_ref_thread()));
1461 }
1462
1463 // Lua <5.2 requires memory allocation to push a C function
1464 let state = lua.state();
1465 {
1466 let _sg = StackGuard::new(state);
1467 check_stack(state, 3)?;
1468
1469 if lua.unlikely_memory_error() {
1470 ffi::lua_pushcfunction(state, func);
1471 } else {
1472 protect_lua!(state, 0, 1, |state| ffi::lua_pushcfunction(state, func))?;
1473 }
1474 Ok(Function(lua.pop_ref()))
1475 }
1476 }
1477
1478 /// Wraps a Rust async function or closure, creating a callable Lua function handle to it.
1479 ///
1480 /// While executing the function Rust will poll the Future and if the result is not ready,
1481 /// call `yield()` passing internal representation of a `Poll::Pending` value.
1482 ///
1483 /// The function must be called inside Lua coroutine ([`Thread`]) to be able to suspend its
1484 /// execution. An executor should be used to poll [`AsyncThread`] and mlua will take a provided
1485 /// Waker in that case. Otherwise noop waker will be used if try to call the function outside of
1486 /// Rust executors.
1487 ///
1488 /// The family of `call_async()` functions takes care about creating [`Thread`].
1489 ///
1490 /// # Examples
1491 ///
1492 /// Non blocking sleep:
1493 ///
1494 /// ```
1495 /// use std::time::Duration;
1496 /// use mlua::{Lua, Result};
1497 ///
1498 /// async fn sleep(_lua: Lua, n: u64) -> Result<&'static str> {
1499 /// tokio::time::sleep(Duration::from_millis(n)).await;
1500 /// Ok("done")
1501 /// }
1502 ///
1503 /// #[tokio::main]
1504 /// async fn main() -> Result<()> {
1505 /// let lua = Lua::new();
1506 /// lua.globals().set("sleep", lua.create_async_function(sleep)?)?;
1507 /// let res: String = lua.load("return sleep(...)").call_async(100).await?; // Sleep 100ms
1508 /// assert_eq!(res, "done");
1509 /// Ok(())
1510 /// }
1511 /// ```
1512 ///
1513 /// [`AsyncThread`]: crate::thread::AsyncThread
1514 #[cfg(feature = "async")]
1515 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
1516 pub fn create_async_function<F, A, FR, R>(&self, func: F) -> Result<Function>
1517 where
1518 F: Fn(Lua, A) -> FR + MaybeSend + 'static,
1519 A: FromLuaMulti,
1520 FR: Future<Output = Result<R>> + MaybeSend + 'static,
1521 R: IntoLuaMulti,
1522 {
1523 // In future we should switch to async closures when they are stable to capture `&Lua`
1524 // See https://rust-lang.github.io/rfcs/3668-async-closures.html
1525 (self.lock()).create_async_callback(Box::new(move |rawlua, nargs| unsafe {
1526 let args = match A::from_stack_args(nargs, 1, None, rawlua) {
1527 Ok(args) => args,
1528 Err(e) => return Box::pin(future::ready(Err(e))),
1529 };
1530 let lua = rawlua.lua();
1531 let fut = func(lua.clone(), args);
1532 Box::pin(async move { fut.await?.push_into_stack_multi(lua.raw_lua()) })
1533 }))
1534 }
1535
1536 /// Wraps a Lua function into a new thread (or coroutine).
1537 ///
1538 /// Equivalent to `coroutine.create`.
1539 pub fn create_thread(&self, func: Function) -> Result<Thread> {
1540 unsafe { self.lock().create_thread(&func) }
1541 }
1542
1543 /// Creates a Lua userdata object from a custom userdata type.
1544 ///
1545 /// All userdata instances of the same type `T` shares the same metatable.
1546 #[inline]
1547 pub fn create_userdata<T>(&self, data: T) -> Result<AnyUserData>
1548 where
1549 T: UserData + MaybeSend + MaybeSync + 'static,
1550 {
1551 unsafe { self.lock().make_userdata(UserDataStorage::new(data)) }
1552 }
1553
1554 /// Creates a Lua userdata object from a custom serializable userdata type.
1555 #[cfg(feature = "serde")]
1556 #[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
1557 #[inline]
1558 pub fn create_ser_userdata<T>(&self, data: T) -> Result<AnyUserData>
1559 where
1560 T: UserData + Serialize + MaybeSend + MaybeSync + 'static,
1561 {
1562 unsafe { self.lock().make_userdata(UserDataStorage::new_ser(data)) }
1563 }
1564
1565 /// Creates a Lua userdata object from a custom Rust type.
1566 ///
1567 /// You can register the type using [`Lua::register_userdata_type`] to add fields or methods
1568 /// _before_ calling this method.
1569 /// Otherwise, the userdata object will have an empty metatable.
1570 ///
1571 /// All userdata instances of the same type `T` shares the same metatable.
1572 #[inline]
1573 pub fn create_any_userdata<T>(&self, data: T) -> Result<AnyUserData>
1574 where
1575 T: MaybeSend + MaybeSync + 'static,
1576 {
1577 unsafe { self.lock().make_any_userdata(UserDataStorage::new(data)) }
1578 }
1579
1580 /// Creates a Lua userdata object from a custom serializable Rust type.
1581 ///
1582 /// See [`Lua::create_any_userdata`] for more details.
1583 #[cfg(feature = "serde")]
1584 #[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
1585 #[inline]
1586 pub fn create_ser_any_userdata<T>(&self, data: T) -> Result<AnyUserData>
1587 where
1588 T: Serialize + MaybeSend + MaybeSync + 'static,
1589 {
1590 unsafe { (self.lock()).make_any_userdata(UserDataStorage::new_ser(data)) }
1591 }
1592
1593 /// Registers a custom Rust type in Lua to use in userdata objects.
1594 ///
1595 /// This methods provides a way to add fields or methods to userdata objects of a type `T`.
1596 pub fn register_userdata_type<T: 'static>(&self, f: impl FnOnce(&mut UserDataRegistry<T>)) -> Result<()> {
1597 let type_id = TypeId::of::<T>();
1598 let mut registry = UserDataRegistry::new(self);
1599 f(&mut registry);
1600
1601 let lua = self.lock();
1602 unsafe {
1603 // Deregister the type if it already registered
1604 if let Some(table_id) = (*lua.extra.get()).registered_userdata_t.remove(&type_id) {
1605 ffi::luaL_unref(lua.state(), ffi::LUA_REGISTRYINDEX, table_id);
1606 }
1607
1608 // Add to "pending" registration map
1609 ((*lua.extra.get()).pending_userdata_reg).insert(type_id, registry.into_raw());
1610 }
1611 Ok(())
1612 }
1613
1614 /// Create a Lua userdata "proxy" object from a custom userdata type.
1615 ///
1616 /// Proxy object is an empty userdata object that has `T` metatable attached.
1617 /// The main purpose of this object is to provide access to static fields and functions
1618 /// without creating an instance of type `T`.
1619 ///
1620 /// You can get or set uservalues on this object but you cannot borrow any Rust type.
1621 ///
1622 /// # Examples
1623 ///
1624 /// ```
1625 /// # use mlua::{Lua, Result, UserData, UserDataFields, UserDataMethods};
1626 /// # fn main() -> Result<()> {
1627 /// # let lua = Lua::new();
1628 /// struct MyUserData(i32);
1629 ///
1630 /// impl UserData for MyUserData {
1631 /// fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
1632 /// fields.add_field_method_get("val", |_, this| Ok(this.0));
1633 /// }
1634 ///
1635 /// fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
1636 /// methods.add_function("new", |_, value: i32| Ok(MyUserData(value)));
1637 /// }
1638 /// }
1639 ///
1640 /// lua.globals().set("MyUserData", lua.create_proxy::<MyUserData>()?)?;
1641 ///
1642 /// lua.load("assert(MyUserData.new(321).val == 321)").exec()?;
1643 /// # Ok(())
1644 /// # }
1645 /// ```
1646 #[inline]
1647 pub fn create_proxy<T>(&self) -> Result<AnyUserData>
1648 where
1649 T: UserData + 'static,
1650 {
1651 let ud = UserDataProxy::<T>(PhantomData);
1652 unsafe { self.lock().make_userdata(UserDataStorage::new(ud)) }
1653 }
1654
1655 /// Gets the metatable of a Lua built-in (primitive) type.
1656 ///
1657 /// The metatable is shared by all values of the given type.
1658 ///
1659 /// See [`Lua::set_type_metatable`] for examples.
1660 #[allow(private_bounds)]
1661 pub fn type_metatable<T: LuaType>(&self) -> Option<Table> {
1662 let lua = self.lock();
1663 let state = lua.state();
1664 unsafe {
1665 let _sg = StackGuard::new(state);
1666 assert_stack(state, 2);
1667
1668 if lua.push_primitive_type::<T>() && ffi::lua_getmetatable(state, -1) != 0 {
1669 return Some(Table(lua.pop_ref()));
1670 }
1671 }
1672 None
1673 }
1674
1675 /// Sets the metatable for a Lua built-in (primitive) type.
1676 ///
1677 /// The metatable will be shared by all values of the given type.
1678 ///
1679 /// # Examples
1680 ///
1681 /// Change metatable for Lua boolean type:
1682 ///
1683 /// ```
1684 /// # use mlua::{Lua, Result, Function};
1685 /// # fn main() -> Result<()> {
1686 /// # let lua = Lua::new();
1687 /// let mt = lua.create_table()?;
1688 /// mt.set("__tostring", lua.create_function(|_, b: bool| Ok(if b { "2" } else { "0" }))?)?;
1689 /// lua.set_type_metatable::<bool>(Some(mt));
1690 /// lua.load("assert(tostring(true) == '2')").exec()?;
1691 /// # Ok(())
1692 /// # }
1693 /// ```
1694 #[allow(private_bounds)]
1695 pub fn set_type_metatable<T: LuaType>(&self, metatable: Option<Table>) {
1696 let lua = self.lock();
1697 let state = lua.state();
1698 unsafe {
1699 let _sg = StackGuard::new(state);
1700 assert_stack(state, 2);
1701
1702 if lua.push_primitive_type::<T>() {
1703 match metatable {
1704 Some(metatable) => lua.push_ref(&metatable.0),
1705 None => ffi::lua_pushnil(state),
1706 }
1707 ffi::lua_setmetatable(state, -2);
1708 }
1709 }
1710 }
1711
1712 /// Returns a handle to the global environment.
1713 pub fn globals(&self) -> Table {
1714 let lua = self.lock();
1715 let state = lua.state();
1716 unsafe {
1717 let _sg = StackGuard::new(state);
1718 assert_stack(state, 1);
1719 #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua52"))]
1720 ffi::lua_rawgeti(state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS);
1721 #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
1722 ffi::lua_pushvalue(state, ffi::LUA_GLOBALSINDEX);
1723 Table(lua.pop_ref())
1724 }
1725 }
1726
1727 /// Sets the global environment.
1728 ///
1729 /// This will replace the current global environment with the provided `globals` table.
1730 ///
1731 /// For Lua 5.2+ the globals table is stored in the registry and shared between all threads.
1732 /// For Lua 5.1 and Luau the globals table is stored in each thread.
1733 ///
1734 /// Please note that any existing Lua functions have cached global environment and will not
1735 /// see the changes made by this method.
1736 /// To update the environment for existing Lua functions, use [`Function::set_environment`].
1737 pub fn set_globals(&self, globals: Table) -> Result<()> {
1738 let lua = self.lock();
1739 let state = lua.state();
1740 unsafe {
1741 #[cfg(feature = "luau")]
1742 if (*lua.extra.get()).sandboxed {
1743 return Err(Error::runtime("cannot change globals in a sandboxed Lua state"));
1744 }
1745
1746 let _sg = StackGuard::new(state);
1747 check_stack(state, 1)?;
1748
1749 lua.push_ref(&globals.0);
1750
1751 #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua52"))]
1752 ffi::lua_rawseti(state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS);
1753 #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
1754 ffi::lua_replace(state, ffi::LUA_GLOBALSINDEX);
1755 }
1756
1757 Ok(())
1758 }
1759
1760 /// Returns a handle to the active `Thread`.
1761 ///
1762 /// For calls to `Lua` this will be the main Lua thread, for parameters given to a callback,
1763 /// this will be whatever Lua thread called the callback.
1764 pub fn current_thread(&self) -> Thread {
1765 let lua = self.lock();
1766 let state = lua.state();
1767 unsafe {
1768 let _sg = StackGuard::new(state);
1769 assert_stack(state, 1);
1770 ffi::lua_pushthread(state);
1771 Thread(lua.pop_ref(), state)
1772 }
1773 }
1774
1775 /// Calls the given function with a [`Scope`] parameter, giving the function the ability to
1776 /// create userdata and callbacks from Rust types that are `!Send` or non-`'static`.
1777 ///
1778 /// The lifetime of any function or userdata created through [`Scope`] lasts only until the
1779 /// completion of this method call, on completion all such created values are automatically
1780 /// dropped and Lua references to them are invalidated. If a script accesses a value created
1781 /// through [`Scope`] outside of this method, a Lua error will result. Since we can ensure the
1782 /// lifetime of values created through [`Scope`], and we know that [`Lua`] cannot be sent to
1783 /// another thread while [`Scope`] is live, it is safe to allow `!Send` data types and whose
1784 /// lifetimes only outlive the scope lifetime.
1785 pub fn scope<'env, R>(
1786 &self,
1787 f: impl for<'scope> FnOnce(&'scope Scope<'scope, 'env>) -> Result<R>,
1788 ) -> Result<R> {
1789 f(&Scope::new(self.lock_arc()))
1790 }
1791
1792 /// Attempts to coerce a Lua value into a String in a manner consistent with Lua's internal
1793 /// behavior.
1794 ///
1795 /// To succeed, the value must be a string (in which case this is a no-op), an integer, or a
1796 /// number.
1797 pub fn coerce_string(&self, v: Value) -> Result<Option<LuaString>> {
1798 Ok(match v {
1799 Value::String(s) => Some(s),
1800 v => unsafe {
1801 let lua = self.lock();
1802 let state = lua.state();
1803 let _sg = StackGuard::new(state);
1804 check_stack(state, 4)?;
1805
1806 lua.push_value(&v)?;
1807 let res = if lua.unlikely_memory_error() {
1808 ffi::lua_tolstring(state, -1, ptr::null_mut())
1809 } else {
1810 protect_lua!(state, 1, 1, |state| {
1811 ffi::lua_tolstring(state, -1, ptr::null_mut())
1812 })?
1813 };
1814 if !res.is_null() {
1815 Some(LuaString(lua.pop_ref()))
1816 } else {
1817 None
1818 }
1819 },
1820 })
1821 }
1822
1823 /// Attempts to coerce a Lua value into an integer in a manner consistent with Lua's internal
1824 /// behavior.
1825 ///
1826 /// To succeed, the value must be an integer, a floating point number that has an exact
1827 /// representation as an integer, or a string that can be converted to an integer. Refer to the
1828 /// Lua manual for details.
1829 pub fn coerce_integer(&self, v: Value) -> Result<Option<Integer>> {
1830 Ok(match v {
1831 Value::Integer(i) => Some(i),
1832 v => unsafe {
1833 let lua = self.lock();
1834 let state = lua.state();
1835 let _sg = StackGuard::new(state);
1836 check_stack(state, 2)?;
1837
1838 lua.push_value(&v)?;
1839 let mut isint = 0;
1840 let i = ffi::lua_tointegerx(state, -1, &mut isint);
1841 if isint == 0 { None } else { Some(i) }
1842 },
1843 })
1844 }
1845
1846 /// Attempts to coerce a Lua value into a Number in a manner consistent with Lua's internal
1847 /// behavior.
1848 ///
1849 /// To succeed, the value must be a number or a string that can be converted to a number. Refer
1850 /// to the Lua manual for details.
1851 pub fn coerce_number(&self, v: Value) -> Result<Option<Number>> {
1852 Ok(match v {
1853 Value::Number(n) => Some(n),
1854 v => unsafe {
1855 let lua = self.lock();
1856 let state = lua.state();
1857 let _sg = StackGuard::new(state);
1858 check_stack(state, 2)?;
1859
1860 lua.push_value(&v)?;
1861 let mut isnum = 0;
1862 let n = ffi::lua_tonumberx(state, -1, &mut isnum);
1863 if isnum == 0 { None } else { Some(n) }
1864 },
1865 })
1866 }
1867
1868 /// Converts a value that implements [`IntoLua`] into a [`Value`] instance.
1869 #[inline]
1870 pub fn pack(&self, t: impl IntoLua) -> Result<Value> {
1871 t.into_lua(self)
1872 }
1873
1874 /// Converts a [`Value`] instance into a value that implements [`FromLua`].
1875 #[inline]
1876 pub fn unpack<T: FromLua>(&self, value: Value) -> Result<T> {
1877 T::from_lua(value, self)
1878 }
1879
1880 /// Converts a value that implements [`IntoLua`] into a [`FromLua`] variant.
1881 #[inline]
1882 pub fn convert<U: FromLua>(&self, value: impl IntoLua) -> Result<U> {
1883 U::from_lua(value.into_lua(self)?, self)
1884 }
1885
1886 /// Converts a value that implements [`IntoLuaMulti`] into a [`MultiValue`] instance.
1887 #[inline]
1888 pub fn pack_multi(&self, t: impl IntoLuaMulti) -> Result<MultiValue> {
1889 t.into_lua_multi(self)
1890 }
1891
1892 /// Converts a [`MultiValue`] instance into a value that implements [`FromLuaMulti`].
1893 #[inline]
1894 pub fn unpack_multi<T: FromLuaMulti>(&self, value: MultiValue) -> Result<T> {
1895 T::from_lua_multi(value, self)
1896 }
1897
1898 /// Set a value in the Lua registry based on a string key.
1899 ///
1900 /// This value will be available to Rust from all Lua instances which share the same main
1901 /// state.
1902 pub fn set_named_registry_value(&self, key: &str, t: impl IntoLua) -> Result<()> {
1903 let lua = self.lock();
1904 let state = lua.state();
1905 unsafe {
1906 let _sg = StackGuard::new(state);
1907 check_stack(state, 5)?;
1908
1909 lua.push(t)?;
1910 rawset_field(state, ffi::LUA_REGISTRYINDEX, key)
1911 }
1912 }
1913
1914 /// Get a value from the Lua registry based on a string key.
1915 ///
1916 /// Any Lua instance which shares the underlying main state may call this method to
1917 /// get a value previously set by [`Lua::set_named_registry_value`].
1918 pub fn named_registry_value<T>(&self, key: &str) -> Result<T>
1919 where
1920 T: FromLua,
1921 {
1922 let lua = self.lock();
1923 let state = lua.state();
1924 unsafe {
1925 let _sg = StackGuard::new(state);
1926 check_stack(state, 3)?;
1927
1928 let protect = !lua.unlikely_memory_error();
1929 push_string(state, key.as_bytes(), protect)?;
1930 ffi::lua_rawget(state, ffi::LUA_REGISTRYINDEX);
1931
1932 T::from_stack(-1, &lua)
1933 }
1934 }
1935
1936 /// Removes a named value in the Lua registry.
1937 ///
1938 /// Equivalent to calling [`Lua::set_named_registry_value`] with a value of [`Nil`].
1939 #[inline]
1940 pub fn unset_named_registry_value(&self, key: &str) -> Result<()> {
1941 self.set_named_registry_value(key, Nil)
1942 }
1943
1944 /// Place a value in the Lua registry with an auto-generated key.
1945 ///
1946 /// This value will be available to Rust from all Lua instances which share the same main
1947 /// state.
1948 ///
1949 /// Be warned, garbage collection of values held inside the registry is not automatic, see
1950 /// [`RegistryKey`] for more details.
1951 /// However, dropped [`RegistryKey`]s automatically reused to store new values.
1952 pub fn create_registry_value(&self, t: impl IntoLua) -> Result<RegistryKey> {
1953 let lua = self.lock();
1954 let state = lua.state();
1955 unsafe {
1956 let _sg = StackGuard::new(state);
1957 check_stack(state, 4)?;
1958
1959 lua.push(t)?;
1960
1961 let unref_list = (*lua.extra.get()).registry_unref_list.clone();
1962
1963 // Check if the value is nil (no need to store it in the registry)
1964 if ffi::lua_isnil(state, -1) != 0 {
1965 return Ok(RegistryKey::new(ffi::LUA_REFNIL, unref_list));
1966 }
1967
1968 // Try to reuse previously allocated slot
1969 let free_registry_id = unref_list.lock().as_mut().and_then(|x| x.pop());
1970 if let Some(registry_id) = free_registry_id {
1971 // It must be safe to replace the value without triggering memory error
1972 ffi::lua_rawseti(state, ffi::LUA_REGISTRYINDEX, registry_id as Integer);
1973 return Ok(RegistryKey::new(registry_id, unref_list));
1974 }
1975
1976 // Allocate a new RegistryKey slot
1977 let registry_id = if lua.unlikely_memory_error() {
1978 ffi::luaL_ref(state, ffi::LUA_REGISTRYINDEX)
1979 } else {
1980 protect_lua!(state, 1, 0, |state| {
1981 ffi::luaL_ref(state, ffi::LUA_REGISTRYINDEX)
1982 })?
1983 };
1984 Ok(RegistryKey::new(registry_id, unref_list))
1985 }
1986 }
1987
1988 /// Get a value from the Lua registry by its [`RegistryKey`]
1989 ///
1990 /// Any Lua instance which shares the underlying main state may call this method to get a value
1991 /// previously placed by [`Lua::create_registry_value`].
1992 pub fn registry_value<T: FromLua>(&self, key: &RegistryKey) -> Result<T> {
1993 let lua = self.lock();
1994 if !lua.owns_registry_value(key) {
1995 return Err(Error::MismatchedRegistryKey);
1996 }
1997
1998 let state = lua.state();
1999 match key.id() {
2000 ffi::LUA_REFNIL => T::from_lua(Value::Nil, self),
2001 registry_id => unsafe {
2002 let _sg = StackGuard::new(state);
2003 check_stack(state, 1)?;
2004
2005 ffi::lua_rawgeti(state, ffi::LUA_REGISTRYINDEX, registry_id as Integer);
2006 T::from_stack(-1, &lua)
2007 },
2008 }
2009 }
2010
2011 /// Removes a value from the Lua registry.
2012 ///
2013 /// You may call this function to manually remove a value placed in the registry with
2014 /// [`Lua::create_registry_value`]. In addition to manual [`RegistryKey`] removal, you can also
2015 /// call [`Lua::expire_registry_values`] to automatically remove values from the registry
2016 /// whose [`RegistryKey`]s have been dropped.
2017 pub fn remove_registry_value(&self, key: RegistryKey) -> Result<()> {
2018 let lua = self.lock();
2019 if !lua.owns_registry_value(&key) {
2020 return Err(Error::MismatchedRegistryKey);
2021 }
2022
2023 unsafe { ffi::luaL_unref(lua.state(), ffi::LUA_REGISTRYINDEX, key.take()) };
2024 Ok(())
2025 }
2026
2027 /// Replaces a value in the Lua registry by its [`RegistryKey`].
2028 ///
2029 /// An identifier used in [`RegistryKey`] may possibly be changed to a new value.
2030 ///
2031 /// See [`Lua::create_registry_value`] for more details.
2032 pub fn replace_registry_value(&self, key: &mut RegistryKey, t: impl IntoLua) -> Result<()> {
2033 let lua = self.lock();
2034 if !lua.owns_registry_value(key) {
2035 return Err(Error::MismatchedRegistryKey);
2036 }
2037
2038 let t = t.into_lua(self)?;
2039
2040 let state = lua.state();
2041 unsafe {
2042 let _sg = StackGuard::new(state);
2043 check_stack(state, 2)?;
2044
2045 match (t, key.id()) {
2046 (Value::Nil, ffi::LUA_REFNIL) => {
2047 // Do nothing, no need to replace nil with nil
2048 }
2049 (Value::Nil, registry_id) => {
2050 // Remove the value
2051 ffi::luaL_unref(state, ffi::LUA_REGISTRYINDEX, registry_id);
2052 key.set_id(ffi::LUA_REFNIL);
2053 }
2054 (value, ffi::LUA_REFNIL) => {
2055 // Allocate a new `RegistryKey`
2056 let new_key = self.create_registry_value(value)?;
2057 key.set_id(new_key.take());
2058 }
2059 (value, registry_id) => {
2060 // It must be safe to replace the value without triggering memory error
2061 lua.push_value(&value)?;
2062 ffi::lua_rawseti(state, ffi::LUA_REGISTRYINDEX, registry_id as Integer);
2063 }
2064 }
2065 }
2066 Ok(())
2067 }
2068
2069 /// Returns true if the given [`RegistryKey`] was created by a Lua which shares the
2070 /// underlying main state with this Lua instance.
2071 ///
2072 /// Other than this, methods that accept a [`RegistryKey`] will return
2073 /// [`Error::MismatchedRegistryKey`] if passed a [`RegistryKey`] that was not created with a
2074 /// matching [`Lua`] state.
2075 #[inline]
2076 pub fn owns_registry_value(&self, key: &RegistryKey) -> bool {
2077 self.lock().owns_registry_value(key)
2078 }
2079
2080 /// Remove any registry values whose [`RegistryKey`]s have all been dropped.
2081 ///
2082 /// Unlike normal handle values, [`RegistryKey`]s do not automatically remove themselves on
2083 /// Drop, but you can call this method to remove any unreachable registry values not
2084 /// manually removed by [`Lua::remove_registry_value`].
2085 pub fn expire_registry_values(&self) {
2086 let lua = self.lock();
2087 let state = lua.state();
2088 unsafe {
2089 let mut unref_list = (*lua.extra.get()).registry_unref_list.lock();
2090 let unref_list = unref_list.replace(Vec::new());
2091 for id in mlua_expect!(unref_list, "unref list is not set") {
2092 ffi::luaL_unref(state, ffi::LUA_REGISTRYINDEX, id);
2093 }
2094 }
2095 }
2096
2097 /// Sets or replaces an application data object of type `T`.
2098 ///
2099 /// Application data could be accessed at any time by using [`Lua::app_data_ref`] or
2100 /// [`Lua::app_data_mut`] methods where `T` is the data type.
2101 ///
2102 /// # Panics
2103 ///
2104 /// Panics if the app data container is currently borrowed.
2105 ///
2106 /// # Examples
2107 ///
2108 /// ```
2109 /// use mlua::{Lua, Result};
2110 ///
2111 /// fn hello(lua: &Lua, _: ()) -> Result<()> {
2112 /// let mut s = lua.app_data_mut::<&str>().unwrap();
2113 /// assert_eq!(*s, "hello");
2114 /// *s = "world";
2115 /// Ok(())
2116 /// }
2117 ///
2118 /// fn main() -> Result<()> {
2119 /// let lua = Lua::new();
2120 /// lua.set_app_data("hello");
2121 /// lua.create_function(hello)?.call::<()>(())?;
2122 /// let s = lua.app_data_ref::<&str>().unwrap();
2123 /// assert_eq!(*s, "world");
2124 /// Ok(())
2125 /// }
2126 /// ```
2127 #[track_caller]
2128 pub fn set_app_data<T: MaybeSend + 'static>(&self, data: T) -> Option<T> {
2129 let lua = self.lock();
2130 let extra = unsafe { &*lua.extra.get() };
2131 extra.app_data.insert(data)
2132 }
2133
2134 /// Tries to set or replace an application data object of type `T`.
2135 ///
2136 /// Returns:
2137 /// - `Ok(Some(old_data))` if the data object of type `T` was successfully replaced.
2138 /// - `Ok(None)` if the data object of type `T` was successfully inserted.
2139 /// - `Err(data)` if the data object of type `T` was not inserted because the container is
2140 /// currently borrowed.
2141 ///
2142 /// See [`Lua::set_app_data`] for examples.
2143 pub fn try_set_app_data<T: MaybeSend + 'static>(&self, data: T) -> StdResult<Option<T>, T> {
2144 let lua = self.lock();
2145 let extra = unsafe { &*lua.extra.get() };
2146 extra.app_data.try_insert(data)
2147 }
2148
2149 /// Gets a reference to an application data object stored by [`Lua::set_app_data`] of type
2150 /// `T`.
2151 ///
2152 /// # Panics
2153 ///
2154 /// Panics if the data object of type `T` is currently mutably borrowed. Multiple immutable
2155 /// reads can be taken out at the same time.
2156 #[track_caller]
2157 pub fn app_data_ref<T: 'static>(&self) -> Option<AppDataRef<'_, T>> {
2158 let guard = self.lock_arc();
2159 let extra = unsafe { &*guard.extra.get() };
2160 extra.app_data.borrow(Some(guard))
2161 }
2162
2163 /// Tries to get a reference to an application data object stored by [`Lua::set_app_data`] of
2164 /// type `T`.
2165 pub fn try_app_data_ref<T: 'static>(&self) -> StdResult<Option<AppDataRef<'_, T>>, BorrowError> {
2166 let guard = self.lock_arc();
2167 let extra = unsafe { &*guard.extra.get() };
2168 extra.app_data.try_borrow(Some(guard))
2169 }
2170
2171 /// Gets a mutable reference to an application data object stored by [`Lua::set_app_data`] of
2172 /// type `T`.
2173 ///
2174 /// # Panics
2175 ///
2176 /// Panics if the data object of type `T` is currently borrowed.
2177 #[track_caller]
2178 pub fn app_data_mut<T: 'static>(&self) -> Option<AppDataRefMut<'_, T>> {
2179 let guard = self.lock_arc();
2180 let extra = unsafe { &*guard.extra.get() };
2181 extra.app_data.borrow_mut(Some(guard))
2182 }
2183
2184 /// Tries to get a mutable reference to an application data object stored by
2185 /// [`Lua::set_app_data`] of type `T`.
2186 pub fn try_app_data_mut<T: 'static>(&self) -> StdResult<Option<AppDataRefMut<'_, T>>, BorrowMutError> {
2187 let guard = self.lock_arc();
2188 let extra = unsafe { &*guard.extra.get() };
2189 extra.app_data.try_borrow_mut(Some(guard))
2190 }
2191
2192 /// Removes an application data of type `T`.
2193 ///
2194 /// # Panics
2195 ///
2196 /// Panics if the app data container is currently borrowed.
2197 #[track_caller]
2198 pub fn remove_app_data<T: 'static>(&self) -> Option<T> {
2199 let lua = self.lock();
2200 let extra = unsafe { &*lua.extra.get() };
2201 extra.app_data.remove()
2202 }
2203
2204 /// Returns an internal `Poll::Pending` constant used for executing async callbacks.
2205 ///
2206 /// Every time when [`Future`] is Pending, Lua corotine is suspended with this constant.
2207 #[cfg(feature = "async")]
2208 #[doc(hidden)]
2209 #[inline(always)]
2210 pub fn poll_pending() -> LightUserData {
2211 static ASYNC_POLL_PENDING: u8 = 0;
2212 LightUserData(&ASYNC_POLL_PENDING as *const u8 as *mut std::os::raw::c_void)
2213 }
2214
2215 #[cfg(feature = "async")]
2216 #[inline(always)]
2217 pub(crate) fn poll_terminate() -> LightUserData {
2218 static ASYNC_POLL_TERMINATE: u8 = 0;
2219 LightUserData(&ASYNC_POLL_TERMINATE as *const u8 as *mut std::os::raw::c_void)
2220 }
2221
2222 #[cfg(feature = "async")]
2223 #[inline(always)]
2224 pub(crate) fn poll_yield() -> LightUserData {
2225 static ASYNC_POLL_YIELD: u8 = 0;
2226 LightUserData(&ASYNC_POLL_YIELD as *const u8 as *mut std::os::raw::c_void)
2227 }
2228
2229 /// Suspends the current async function, returning the provided arguments to caller.
2230 ///
2231 /// This function is similar to [`coroutine.yield`] but allow yielding Rust functions
2232 /// and passing values to the caller.
2233 /// Please note that you cannot cross [`Thread`] boundaries (e.g. calling `yield_with` on one
2234 /// thread and resuming on another).
2235 ///
2236 /// # Examples
2237 ///
2238 /// Async iterator:
2239 ///
2240 /// ```
2241 /// # use mlua::{Lua, Result};
2242 /// #
2243 /// async fn generator(lua: Lua, _: ()) -> Result<()> {
2244 /// for i in 0..10 {
2245 /// lua.yield_with::<()>(i).await?;
2246 /// }
2247 /// Ok(())
2248 /// }
2249 ///
2250 /// fn main() -> Result<()> {
2251 /// let lua = Lua::new();
2252 /// lua.globals().set("generator", lua.create_async_function(generator)?)?;
2253 ///
2254 /// lua.load(r#"
2255 /// local n = 0
2256 /// for i in coroutine.wrap(generator) do
2257 /// n = n + i
2258 /// end
2259 /// assert(n == 45)
2260 /// "#)
2261 /// .exec()
2262 /// }
2263 /// ```
2264 ///
2265 /// Exchange values on yield:
2266 ///
2267 /// ```
2268 /// # use mlua::{Lua, Result, Value};
2269 /// #
2270 /// async fn pingpong(lua: Lua, mut val: i32) -> Result<()> {
2271 /// loop {
2272 /// val = lua.yield_with::<i32>(val).await? + 1;
2273 /// }
2274 /// Ok(())
2275 /// }
2276 ///
2277 /// # fn main() -> Result<()> {
2278 /// let lua = Lua::new();
2279 ///
2280 /// let co = lua.create_thread(lua.create_async_function(pingpong)?)?;
2281 /// assert_eq!(co.resume::<i32>(1)?, 1);
2282 /// assert_eq!(co.resume::<i32>(2)?, 3);
2283 /// assert_eq!(co.resume::<i32>(3)?, 4);
2284 ///
2285 /// # Ok(())
2286 /// # }
2287 /// ```
2288 ///
2289 /// [`coroutine.yield`]: https://www.lua.org/manual/5.4/manual.html#pdf-coroutine.yield
2290 #[cfg(feature = "async")]
2291 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
2292 pub async fn yield_with<R: FromLuaMulti>(&self, args: impl IntoLuaMulti) -> Result<R> {
2293 let mut args = Some(args.into_lua_multi(self)?);
2294 future::poll_fn(move |_cx| match args.take() {
2295 Some(args) => unsafe {
2296 let lua = self.lock();
2297 lua.push(Self::poll_yield())?; // yield marker
2298 if args.len() <= 1 {
2299 lua.push(args.front())?;
2300 } else {
2301 lua.push(lua.create_sequence_from(&args)?)?;
2302 }
2303 lua.push(args.len())?;
2304 Poll::Pending
2305 },
2306 None => unsafe {
2307 let lua = self.lock();
2308 let state = lua.state();
2309 let top = ffi::lua_gettop(state);
2310 if top == 0 || ffi::lua_type(state, 1) != ffi::LUA_TUSERDATA {
2311 // This must be impossible scenario if used correctly
2312 return Poll::Ready(R::from_stack_multi(0, &lua));
2313 }
2314 let _sg = StackGuard::with_top(state, 1);
2315 Poll::Ready(R::from_stack_multi(top - 1, &lua))
2316 },
2317 })
2318 .await
2319 }
2320
2321 /// Returns a weak reference to the Lua instance.
2322 ///
2323 /// This is useful for creating a reference to the Lua instance that does not prevent it from
2324 /// being deallocated.
2325 #[inline(always)]
2326 pub fn weak(&self) -> WeakLua {
2327 WeakLua(XRc::downgrade(&self.raw))
2328 }
2329
2330 #[cfg(not(feature = "luau"))]
2331 fn disable_c_modules(&self) -> Result<()> {
2332 let package: Table = self.globals().get("package")?;
2333
2334 package.set(
2335 "loadlib",
2336 self.create_function(|_, ()| -> Result<()> {
2337 Err(Error::SafetyError(
2338 "package.loadlib is disabled in safe mode".to_string(),
2339 ))
2340 })?,
2341 )?;
2342
2343 #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua52"))]
2344 let searchers: Table = package.get("searchers")?;
2345 #[cfg(any(feature = "lua51", feature = "luajit"))]
2346 let searchers: Table = package.get("loaders")?;
2347
2348 let loader = self.create_function(|_, ()| Ok("\n\tcan't load C modules in safe mode"))?;
2349
2350 // The third and fourth searchers looks for a loader as a C library
2351 searchers.raw_set(3, loader)?;
2352 if searchers.raw_len() >= 4 {
2353 searchers.raw_remove(4)?;
2354 }
2355
2356 Ok(())
2357 }
2358
2359 #[inline(always)]
2360 pub(crate) fn lock(&self) -> ReentrantMutexGuard<'_, RawLua> {
2361 let rawlua = self.raw.lock();
2362 #[cfg(feature = "luau")]
2363 if unsafe { (*rawlua.extra.get()).running_gc } {
2364 panic!("Luau VM is suspended while GC is running");
2365 }
2366 rawlua
2367 }
2368
2369 #[inline(always)]
2370 pub(crate) fn lock_arc(&self) -> LuaGuard {
2371 LuaGuard(self.raw.lock_arc())
2372 }
2373
2374 /// Returns a handle to the unprotected Lua state without any synchronization.
2375 ///
2376 /// This is useful where we know that the lock is already held by the caller.
2377 #[cfg(feature = "async")]
2378 #[inline(always)]
2379 pub(crate) unsafe fn raw_lua(&self) -> &RawLua {
2380 &*self.raw.data_ptr()
2381 }
2382}
2383
2384impl WeakLua {
2385 #[track_caller]
2386 #[inline(always)]
2387 pub(crate) fn lock(&self) -> LuaGuard {
2388 let guard = LuaGuard::new(self.0.upgrade().expect("Lua instance is destroyed"));
2389 #[cfg(feature = "luau")]
2390 if unsafe { (*guard.extra.get()).running_gc } {
2391 panic!("Luau VM is suspended while GC is running");
2392 }
2393 guard
2394 }
2395
2396 #[inline(always)]
2397 pub(crate) fn try_lock(&self) -> Option<LuaGuard> {
2398 Some(LuaGuard::new(self.0.upgrade()?))
2399 }
2400
2401 /// Upgrades the weak Lua reference to a strong reference.
2402 ///
2403 /// # Panics
2404 ///
2405 /// Panics if the Lua instance is destroyed.
2406 #[track_caller]
2407 #[inline(always)]
2408 pub fn upgrade(&self) -> Lua {
2409 Lua {
2410 raw: self.0.upgrade().expect("Lua instance is destroyed"),
2411 collect_garbage: false,
2412 }
2413 }
2414
2415 /// Tries to upgrade the weak Lua reference to a strong reference.
2416 ///
2417 /// Returns `None` if the Lua instance is destroyed.
2418 #[inline(always)]
2419 pub fn try_upgrade(&self) -> Option<Lua> {
2420 Some(Lua {
2421 raw: self.0.upgrade()?,
2422 collect_garbage: false,
2423 })
2424 }
2425}
2426
2427impl PartialEq for WeakLua {
2428 fn eq(&self, other: &Self) -> bool {
2429 XWeak::ptr_eq(&self.0, &other.0)
2430 }
2431}
2432
2433impl Eq for WeakLua {}
2434
2435impl LuaGuard {
2436 #[cfg(feature = "send")]
2437 pub(crate) fn new(handle: XRc<ReentrantMutex<RawLua>>) -> Self {
2438 LuaGuard(handle.lock_arc())
2439 }
2440
2441 #[cfg(not(feature = "send"))]
2442 pub(crate) fn new(handle: XRc<ReentrantMutex<RawLua>>) -> Self {
2443 LuaGuard(handle.into_lock_arc())
2444 }
2445}
2446
2447impl Deref for LuaGuard {
2448 type Target = RawLua;
2449
2450 fn deref(&self) -> &Self::Target {
2451 &self.0
2452 }
2453}
2454
2455pub(crate) mod extra;
2456mod raw;
2457pub(crate) mod util;
2458
2459#[cfg(test)]
2460mod assertions {
2461 use super::*;
2462
2463 // Lua has lots of interior mutability, should not be RefUnwindSafe
2464 static_assertions::assert_not_impl_any!(Lua: std::panic::RefUnwindSafe);
2465
2466 #[cfg(not(feature = "send"))]
2467 static_assertions::assert_not_impl_any!(Lua: Send);
2468 #[cfg(feature = "send")]
2469 static_assertions::assert_impl_all!(Lua: Send, Sync);
2470}