1use std::any::TypeId;
2use std::cell::{RefCell, UnsafeCell};
3use std::ffi::{CStr, CString};
4use std::fmt;
5use std::marker::PhantomData;
6use std::mem::{self, MaybeUninit};
7use std::ops::Deref;
8use std::os::raw::{c_char, c_int, c_void};
9use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe, Location};
10use std::ptr;
11use std::result::Result as StdResult;
12use std::sync::atomic::{AtomicPtr, Ordering};
13use std::sync::{Arc, Mutex};
14
15use rustc_hash::FxHashMap;
16
17use crate::chunk::{AsChunk, Chunk, ChunkMode};
18use crate::error::{Error, Result};
19use crate::function::Function;
20use crate::hook::Debug;
21use crate::memory::{MemoryState, ALLOCATOR};
22use crate::scope::Scope;
23use crate::stdlib::StdLib;
24use crate::string::String;
25use crate::table::Table;
26use crate::thread::Thread;
27use crate::types::{
28 AppData, AppDataRef, AppDataRefMut, Callback, CallbackUpvalue, DestructedUserdata, Integer,
29 LightUserData, LuaRef, MaybeSend, Number, RegistryKey, SubtypeId,
30};
31use crate::userdata::{AnyUserData, MetaMethod, UserData, UserDataCell};
32use crate::userdata_impl::{UserDataProxy, UserDataRegistry};
33use crate::util::{
34 self, assert_stack, check_stack, error_traceback, get_destructed_userdata_metatable,
35 get_gc_metatable, get_gc_userdata, get_main_state, get_userdata, init_error_registry,
36 init_gc_metatable, init_userdata_metatable, pop_error, push_gc_userdata, push_string,
37 push_table, rawset_field, safe_pcall, safe_xpcall, short_type_name, StackGuard, WrappedFailure,
38};
39use crate::value::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, MultiValue, Nil, Value};
40
41#[cfg(not(feature = "lua54"))]
42use crate::util::push_userdata;
43#[cfg(feature = "lua54")]
44use crate::{types::WarnCallback, userdata::USER_VALUE_MAXSLOT, util::push_userdata_uv};
45
46#[cfg(not(feature = "luau"))]
47use crate::{hook::HookTriggers, types::HookCallback};
48
49#[cfg(feature = "luau")]
50use crate::types::InterruptCallback;
51#[cfg(any(feature = "luau", doc))]
52use crate::{
53 chunk::Compiler,
54 types::{Vector, VmState},
55};
56
57#[cfg(feature = "async")]
58use {
59 crate::types::{AsyncCallback, AsyncCallbackUpvalue, AsyncPollUpvalue},
60 futures_util::future::{self, Future},
61 futures_util::task::{noop_waker_ref, Context, Poll, Waker},
62 std::ptr::NonNull,
63};
64
65#[cfg(feature = "serialize")]
66use serde::Serialize;
67
68#[repr(transparent)]
70pub struct Lua(Arc<LuaInner>);
71
72pub struct LuaInner {
74 state: AtomicPtr<ffi::lua_State>,
76 main_state: *mut ffi::lua_State,
77 extra: Arc<UnsafeCell<ExtraData>>,
78}
79
80pub(crate) struct ExtraData {
82 inner: MaybeUninit<Arc<LuaInner>>,
84
85 registered_userdata: FxHashMap<TypeId, c_int>,
86 registered_userdata_mt: FxHashMap<*const c_void, Option<TypeId>>,
87 last_checked_userdata_mt: (*const c_void, Option<TypeId>),
88
89 registry_unref_list: Arc<Mutex<Option<Vec<c_int>>>>,
91
92 app_data: AppData,
94
95 safe: bool,
96 libs: StdLib,
97 #[cfg(feature = "module")]
98 skip_memory_check: bool,
99
100 ref_thread: *mut ffi::lua_State,
102 ref_stack_size: c_int,
103 ref_stack_top: c_int,
104 ref_free: Vec<c_int>,
105
106 wrapped_failure_pool: Vec<c_int>,
108 multivalue_pool: Vec<Vec<Value<'static>>>,
110 #[cfg(feature = "async")]
112 thread_pool: Vec<c_int>,
113
114 wrapped_failure_mt_ptr: *const c_void,
116
117 #[cfg(feature = "async")]
119 waker: NonNull<Waker>,
120
121 #[cfg(not(feature = "luau"))]
122 hook_callback: Option<HookCallback>,
123 #[cfg(not(feature = "luau"))]
124 hook_thread: *mut ffi::lua_State,
125 #[cfg(feature = "lua54")]
126 warn_callback: Option<WarnCallback>,
127 #[cfg(feature = "luau")]
128 interrupt_callback: Option<InterruptCallback>,
129
130 #[cfg(feature = "luau")]
131 sandboxed: bool,
132 #[cfg(feature = "luau")]
133 compiler: Option<Compiler>,
134 #[cfg(feature = "luau-jit")]
135 enable_jit: bool,
136}
137
138#[derive(Clone, Copy, Debug, PartialEq, Eq)]
147pub enum GCMode {
148 Incremental,
149 #[cfg(feature = "lua54")]
151 #[cfg_attr(docsrs, doc(cfg(feature = "lua54")))]
152 Generational,
153}
154
155#[derive(Clone, Debug)]
157#[non_exhaustive]
158pub struct LuaOptions {
159 pub catch_rust_panics: bool,
172
173 #[cfg(feature = "async")]
182 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
183 pub thread_pool_size: usize,
184}
185
186impl Default for LuaOptions {
187 fn default() -> Self {
188 LuaOptions::new()
189 }
190}
191
192impl LuaOptions {
193 pub const fn new() -> Self {
195 LuaOptions {
196 catch_rust_panics: true,
197 #[cfg(feature = "async")]
198 thread_pool_size: 0,
199 }
200 }
201
202 #[must_use]
206 pub const fn catch_rust_panics(mut self, enabled: bool) -> Self {
207 self.catch_rust_panics = enabled;
208 self
209 }
210
211 #[cfg(feature = "async")]
215 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
216 #[must_use]
217 pub const fn thread_pool_size(mut self, size: usize) -> Self {
218 self.thread_pool_size = size;
219 self
220 }
221}
222
223#[cfg(feature = "async")]
224pub(crate) static ASYNC_POLL_PENDING: u8 = 0;
225pub(crate) static EXTRA_REGISTRY_KEY: u8 = 0;
226
227const WRAPPED_FAILURE_POOL_SIZE: usize = 64;
228const MULTIVALUE_POOL_SIZE: usize = 64;
229const REF_STACK_RESERVE: c_int = 1;
230
231#[cfg(feature = "send")]
233#[cfg_attr(docsrs, doc(cfg(feature = "send")))]
234unsafe impl Send for Lua {}
235
236#[cfg(not(feature = "module"))]
237impl Drop for Lua {
238 fn drop(&mut self) {
239 let _ = self.gc_collect();
240 }
241}
242
243#[cfg(not(feature = "module"))]
244impl Drop for LuaInner {
245 fn drop(&mut self) {
246 unsafe {
247 let mem_state = MemoryState::get(self.main_state);
248
249 ffi::lua_close(self.main_state);
250
251 if !mem_state.is_null() {
253 drop(Box::from_raw(mem_state));
254 }
255 }
256 }
257}
258
259impl Drop for ExtraData {
260 fn drop(&mut self) {
261 #[cfg(feature = "module")]
262 unsafe {
263 self.inner.assume_init_drop();
264 }
265
266 *mlua_expect!(self.registry_unref_list.lock(), "unref list poisoned") = None;
267 }
268}
269
270impl fmt::Debug for Lua {
271 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
272 write!(f, "Lua({:p})", self.state())
273 }
274}
275
276impl Deref for Lua {
277 type Target = LuaInner;
278
279 #[inline]
280 fn deref(&self) -> &Self::Target {
281 &self.0
282 }
283}
284
285impl Default for Lua {
286 #[inline]
287 fn default() -> Self {
288 Lua::new()
289 }
290}
291
292impl Lua {
293 pub fn new() -> Lua {
303 mlua_expect!(
304 Self::new_with(StdLib::ALL_SAFE, LuaOptions::default()),
305 "Cannot create new safe Lua state"
306 )
307 }
308
309 pub unsafe fn unsafe_new() -> Lua {
314 Self::unsafe_new_with(StdLib::ALL, LuaOptions::default())
315 }
316
317 pub fn new_with(libs: StdLib, options: LuaOptions) -> Result<Lua> {
329 #[cfg(not(feature = "luau"))]
330 if libs.contains(StdLib::DEBUG) {
331 return Err(Error::SafetyError(
332 "The unsafe `debug` module can't be loaded using safe `new_with`".to_string(),
333 ));
334 }
335 #[cfg(feature = "luajit")]
336 if libs.contains(StdLib::FFI) {
337 return Err(Error::SafetyError(
338 "The unsafe `ffi` module can't be loaded using safe `new_with`".to_string(),
339 ));
340 }
341
342 let lua = unsafe { Self::inner_new(libs, options) };
343
344 if libs.contains(StdLib::PACKAGE) {
345 mlua_expect!(lua.disable_c_modules(), "Error during disabling C modules");
346 }
347 unsafe { (*lua.extra.get()).safe = true };
348
349 Ok(lua)
350 }
351
352 pub unsafe fn unsafe_new_with(libs: StdLib, options: LuaOptions) -> Lua {
361 let mut _symbols: Vec<*const extern "C-unwind" fn()> =
364 vec![ffi::lua_isuserdata as _, ffi::lua_tocfunction as _];
365
366 #[cfg(not(feature = "luau"))]
367 _symbols.extend_from_slice(&[
368 ffi::lua_atpanic as _,
369 ffi::luaL_loadstring as _,
370 ffi::luaL_openlibs as _,
371 ]);
372 #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
373 {
374 _symbols.push(ffi::lua_getglobal as _);
375 _symbols.push(ffi::lua_setglobal as _);
376 _symbols.push(ffi::luaL_setfuncs as _);
377 }
378
379 Self::inner_new(libs, options)
380 }
381
382 unsafe fn inner_new(libs: StdLib, options: LuaOptions) -> Lua {
384 let mem_state: *mut MemoryState = Box::into_raw(Box::default());
385 let mut state = ffi::lua_newstate(ALLOCATOR, mem_state as *mut c_void);
386 if state.is_null() {
388 drop(Box::from_raw(mem_state));
389 state = ffi::luaL_newstate();
390 }
391 assert!(!state.is_null(), "Failed to instantiate Lua VM");
392
393 ffi::luaL_requiref(state, cstr!("_G"), ffi::luaopen_base, 1);
394 ffi::lua_pop(state, 1);
395
396 #[cfg(feature = "luau-jit")]
398 if ffi::luau_codegen_supported() != 0 {
399 ffi::luau_codegen_create(state);
400 }
401
402 let lua = Lua::init_from_ptr(state);
403 let extra = lua.extra.get();
404
405 mlua_expect!(
406 load_from_std_lib(state, libs),
407 "Error during loading standard libraries"
408 );
409 (*extra).libs |= libs;
410
411 if !options.catch_rust_panics {
412 mlua_expect!(
413 (|| -> Result<()> {
414 let _sg = StackGuard::new(state);
415
416 #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
417 ffi::lua_rawgeti(state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS);
418 #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
419 ffi::lua_pushvalue(state, ffi::LUA_GLOBALSINDEX);
420
421 ffi::lua_pushcfunction(state, safe_pcall);
422 rawset_field(state, -2, "pcall")?;
423
424 ffi::lua_pushcfunction(state, safe_xpcall);
425 rawset_field(state, -2, "xpcall")?;
426
427 Ok(())
428 })(),
429 "Error during applying option `catch_rust_panics`"
430 )
431 }
432
433 #[cfg(feature = "async")]
434 if options.thread_pool_size > 0 {
435 (*extra).thread_pool.reserve_exact(options.thread_pool_size);
436 }
437
438 #[cfg(feature = "luau")]
439 mlua_expect!(lua.configure_luau(), "Error configuring Luau");
440
441 lua
442 }
443
444 #[allow(clippy::missing_safety_doc, clippy::arc_with_non_send_sync)]
449 pub unsafe fn init_from_ptr(state: *mut ffi::lua_State) -> Lua {
450 assert!(!state.is_null(), "Lua state is NULL");
451 if let Some(lua) = Lua::try_from_ptr(state) {
452 return lua;
453 }
454
455 let main_state = get_main_state(state).unwrap_or(state);
456 let main_state_top = ffi::lua_gettop(main_state);
457
458 mlua_expect!(
459 (|state| {
460 init_error_registry(state)?;
461
462 init_gc_metatable::<Arc<UnsafeCell<ExtraData>>>(state, None)?;
466 init_gc_metatable::<Callback>(state, None)?;
467 init_gc_metatable::<CallbackUpvalue>(state, None)?;
468 #[cfg(feature = "async")]
469 {
470 init_gc_metatable::<AsyncCallback>(state, None)?;
471 init_gc_metatable::<AsyncCallbackUpvalue>(state, None)?;
472 init_gc_metatable::<AsyncPollUpvalue>(state, None)?;
473 init_gc_metatable::<Option<Waker>>(state, None)?;
474 }
475
476 #[cfg(feature = "serialize")]
478 crate::serde::init_metatables(state)?;
479
480 Ok::<_, Error>(())
481 })(main_state),
482 "Error during Lua construction",
483 );
484
485 let ref_thread = mlua_expect!(
488 protect_lua!(main_state, 0, 0, |state| {
489 let thread = ffi::lua_newthread(state);
490 ffi::luaL_ref(state, ffi::LUA_REGISTRYINDEX);
491 thread
492 }),
493 "Error while creating ref thread",
494 );
495
496 let wrapped_failure_mt_ptr = {
497 get_gc_metatable::<WrappedFailure>(main_state);
498 let ptr = ffi::lua_topointer(main_state, -1);
499 ffi::lua_pop(main_state, 1);
500 ptr
501 };
502
503 #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
505 {
506 ffi::lua_pushcfunction(ref_thread, error_traceback);
507 assert_eq!(ffi::lua_gettop(ref_thread), ExtraData::ERROR_TRACEBACK_IDX);
508 }
509
510 let extra = Arc::new(UnsafeCell::new(ExtraData {
512 inner: MaybeUninit::uninit(),
513 registered_userdata: FxHashMap::default(),
514 registered_userdata_mt: FxHashMap::default(),
515 last_checked_userdata_mt: (ptr::null(), None),
516 registry_unref_list: Arc::new(Mutex::new(Some(Vec::new()))),
517 app_data: AppData::default(),
518 safe: false,
519 libs: StdLib::NONE,
520 #[cfg(feature = "module")]
521 skip_memory_check: false,
522 ref_thread,
523 ref_stack_size: ffi::LUA_MINSTACK - REF_STACK_RESERVE,
525 ref_stack_top: ffi::lua_gettop(ref_thread),
526 ref_free: Vec::new(),
527 wrapped_failure_pool: Vec::with_capacity(WRAPPED_FAILURE_POOL_SIZE),
528 multivalue_pool: Vec::with_capacity(MULTIVALUE_POOL_SIZE),
529 #[cfg(feature = "async")]
530 thread_pool: Vec::new(),
531 wrapped_failure_mt_ptr,
532 #[cfg(feature = "async")]
533 waker: NonNull::from(noop_waker_ref()),
534 #[cfg(not(feature = "luau"))]
535 hook_callback: None,
536 #[cfg(not(feature = "luau"))]
537 hook_thread: ptr::null_mut(),
538 #[cfg(feature = "lua54")]
539 warn_callback: None,
540 #[cfg(feature = "luau")]
541 interrupt_callback: None,
542 #[cfg(feature = "luau")]
543 sandboxed: false,
544 #[cfg(feature = "luau")]
545 compiler: None,
546 #[cfg(feature = "luau-jit")]
547 enable_jit: true,
548 }));
549
550 mlua_expect!(
552 set_extra_data(main_state, &extra),
553 "Error while storing extra data"
554 );
555
556 get_destructed_userdata_metatable(main_state);
558 let destructed_mt_ptr = ffi::lua_topointer(main_state, -1);
559 let destructed_ud_typeid = TypeId::of::<DestructedUserdata>();
560 (*extra.get())
561 .registered_userdata_mt
562 .insert(destructed_mt_ptr, Some(destructed_ud_typeid));
563 ffi::lua_pop(main_state, 1);
564
565 mlua_debug_assert!(
566 ffi::lua_gettop(main_state) == main_state_top,
567 "stack leak during creation"
568 );
569 assert_stack(main_state, ffi::LUA_MINSTACK);
570
571 let inner = Arc::new(LuaInner {
572 state: AtomicPtr::new(state),
573 main_state,
574 extra: Arc::clone(&extra),
575 });
576
577 (*extra.get()).inner.write(Arc::clone(&inner));
578 #[cfg(not(feature = "module"))]
579 Arc::decrement_strong_count(Arc::as_ptr(&inner));
580
581 Lua(inner)
582 }
583
584 pub fn load_from_std_lib(&self, libs: StdLib) -> Result<()> {
590 let is_safe = unsafe { (*self.extra.get()).safe };
591
592 #[cfg(not(feature = "luau"))]
593 if is_safe && libs.contains(StdLib::DEBUG) {
594 return Err(Error::SafetyError(
595 "the unsafe `debug` module can't be loaded in safe mode".to_string(),
596 ));
597 }
598 #[cfg(feature = "luajit")]
599 if is_safe && libs.contains(StdLib::FFI) {
600 return Err(Error::SafetyError(
601 "the unsafe `ffi` module can't be loaded in safe mode".to_string(),
602 ));
603 }
604
605 let res = unsafe { load_from_std_lib(self.main_state, libs) };
606
607 let curr_libs = unsafe { (*self.extra.get()).libs };
609 if is_safe && (curr_libs ^ (curr_libs | libs)).contains(StdLib::PACKAGE) {
610 mlua_expect!(self.disable_c_modules(), "Error during disabling C modules");
611 }
612 unsafe { (*self.extra.get()).libs |= libs };
613
614 res
615 }
616
617 pub fn load_from_function<'lua, T>(&'lua self, modname: &str, func: Function<'lua>) -> Result<T>
633 where
634 T: FromLua<'lua>,
635 {
636 let state = self.state();
637 let loaded = unsafe {
638 let _sg = StackGuard::new(state);
639 check_stack(state, 2)?;
640 protect_lua!(state, 0, 1, fn(state) {
641 ffi::luaL_getsubtable(state, ffi::LUA_REGISTRYINDEX, cstr!("_LOADED"));
642 })?;
643 Table(self.pop_ref())
644 };
645
646 let modname = self.create_string(modname)?;
647 let value = match loaded.raw_get(modname.clone())? {
648 Value::Nil => {
649 let result = match func.call(modname.clone())? {
650 Value::Nil => Value::Boolean(true),
651 res => res,
652 };
653 loaded.raw_set(modname, result.clone())?;
654 result
655 }
656 res => res,
657 };
658 T::from_lua(value, self)
659 }
660
661 pub fn unload(&self, modname: &str) -> Result<()> {
669 let state = self.state();
670 let loaded = unsafe {
671 let _sg = StackGuard::new(state);
672 check_stack(state, 2)?;
673 protect_lua!(state, 0, 1, fn(state) {
674 ffi::luaL_getsubtable(state, ffi::LUA_REGISTRYINDEX, cstr!("_LOADED"));
675 })?;
676 Table(self.pop_ref())
677 };
678
679 let modname = self.create_string(modname)?;
680 loaded.raw_remove(modname)?;
681 Ok(())
682 }
683
684 #[doc(hidden)]
695 pub fn into_static(self) -> &'static Self {
696 Box::leak(Box::new(self))
697 }
698
699 #[doc(hidden)]
704 pub unsafe fn from_static(lua: &'static Lua) -> Self {
705 *Box::from_raw(lua as *const Lua as *mut Lua)
706 }
707
708 #[doc(hidden)]
711 #[cfg(not(tarpaulin_include))]
712 pub unsafe fn entrypoint<'lua, A, R, F>(self, state: *mut ffi::lua_State, func: F) -> c_int
713 where
714 A: FromLuaMulti<'lua>,
715 R: IntoLua<'lua>,
716 F: Fn(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
717 {
718 let extra = self.extra.get();
719 drop(self);
722
723 callback_error_ext(state, extra, move |nargs| {
724 let lua: &Lua = mem::transmute((*extra).inner.assume_init_ref());
725 let _guard = StateGuard::new(&lua.0, state);
726 let args = A::from_stack_args(nargs, 1, None, lua)?;
727 func(lua, args)?.push_into_stack(lua)?;
728 Ok(1)
729 })
730 }
731
732 #[doc(hidden)]
734 #[cfg(not(tarpaulin_include))]
735 pub unsafe fn entrypoint1<'lua, R, F>(self, state: *mut ffi::lua_State, func: F) -> c_int
736 where
737 R: IntoLua<'lua>,
738 F: Fn(&'lua Lua) -> Result<R> + MaybeSend + 'static,
739 {
740 self.entrypoint(state, move |lua, _: ()| func(lua))
741 }
742
743 #[doc(hidden)]
745 #[cfg(feature = "module")]
746 pub fn skip_memory_check(&self, skip: bool) {
747 unsafe { (*self.extra.get()).skip_memory_check = skip };
748 }
749
750 #[cfg(any(feature = "luau", docsrs))]
779 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
780 pub fn sandbox(&self, enabled: bool) -> Result<()> {
781 unsafe {
782 if (*self.extra.get()).sandboxed != enabled {
783 let state = self.main_state;
784 check_stack(state, 3)?;
785 protect_lua!(state, 0, 0, |state| {
786 if enabled {
787 ffi::luaL_sandbox(state, 1);
788 ffi::luaL_sandboxthread(state);
789 } else {
790 ffi::lua_xpush(self.ref_thread(), state, ffi::LUA_GLOBALSINDEX);
792 ffi::lua_replace(state, ffi::LUA_GLOBALSINDEX);
793 ffi::luaL_sandbox(state, 0);
794 }
795 })?;
796 (*self.extra.get()).sandboxed = enabled;
797 }
798 Ok(())
799 }
800 }
801
802 #[cfg(not(feature = "luau"))]
841 #[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
842 pub fn set_hook<F>(&self, triggers: HookTriggers, callback: F)
843 where
844 F: Fn(&Lua, Debug) -> Result<()> + MaybeSend + 'static,
845 {
846 unsafe { self.set_thread_hook(self.state(), triggers, callback) };
847 }
848
849 #[cfg(not(feature = "luau"))]
851 pub(crate) unsafe fn set_thread_hook<F>(
852 &self,
853 state: *mut ffi::lua_State,
854 triggers: HookTriggers,
855 callback: F,
856 ) where
857 F: Fn(&Lua, Debug) -> Result<()> + MaybeSend + 'static,
858 {
859 unsafe extern "C-unwind" fn hook_proc(state: *mut ffi::lua_State, ar: *mut ffi::lua_Debug) {
860 let extra = extra_data(state);
861 if (*extra).hook_thread != state {
862 ffi::lua_sethook(state, None, 0, 0);
864 return;
865 }
866 callback_error_ext(state, extra, move |_| {
867 let hook_cb = (*extra).hook_callback.clone();
868 let hook_cb = mlua_expect!(hook_cb, "no hook callback set in hook_proc");
869 if Arc::strong_count(&hook_cb) > 2 {
870 return Ok(()); }
872 let lua: &Lua = mem::transmute((*extra).inner.assume_init_ref());
873 let _guard = StateGuard::new(&lua.0, state);
874 let debug = Debug::new(lua, ar);
875 hook_cb(lua, debug)
876 })
877 }
878
879 (*self.extra.get()).hook_callback = Some(Arc::new(callback));
880 (*self.extra.get()).hook_thread = state; ffi::lua_sethook(state, Some(hook_proc), triggers.mask(), triggers.count());
882 }
883
884 #[cfg(not(feature = "luau"))]
888 #[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
889 pub fn remove_hook(&self) {
890 unsafe {
891 let state = self.state();
892 ffi::lua_sethook(state, None, 0, 0);
893 match get_main_state(self.main_state) {
894 Some(main_state) if !ptr::eq(state, main_state) => {
895 ffi::lua_sethook(main_state, None, 0, 0);
897 }
898 _ => {}
899 };
900 (*self.extra.get()).hook_callback = None;
901 (*self.extra.get()).hook_thread = ptr::null_mut();
902 }
903 }
904
905 #[cfg(any(feature = "luau", docsrs))]
948 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
949 pub fn set_interrupt<F>(&self, callback: F)
950 where
951 F: Fn(&Lua) -> Result<VmState> + MaybeSend + 'static,
952 {
953 unsafe extern "C-unwind" fn interrupt_proc(state: *mut ffi::lua_State, gc: c_int) {
954 if gc >= 0 {
955 return;
957 }
958 let extra = extra_data(state);
959 let result = callback_error_ext(state, extra, move |_| {
960 let interrupt_cb = (*extra).interrupt_callback.clone();
961 let interrupt_cb =
962 mlua_expect!(interrupt_cb, "no interrupt callback set in interrupt_proc");
963 if Arc::strong_count(&interrupt_cb) > 2 {
964 return Ok(VmState::Continue); }
966 let lua: &Lua = mem::transmute((*extra).inner.assume_init_ref());
967 let _guard = StateGuard::new(&lua.0, state);
968 interrupt_cb(lua)
969 });
970 match result {
971 VmState::Continue => {}
972 VmState::Yield => {
973 ffi::lua_yield(state, 0);
974 }
975 }
976 }
977
978 unsafe {
979 (*self.extra.get()).interrupt_callback = Some(Arc::new(callback));
980 (*ffi::lua_callbacks(self.main_state)).interrupt = Some(interrupt_proc);
981 }
982 }
983
984 #[cfg(any(feature = "luau", docsrs))]
988 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
989 pub fn remove_interrupt(&self) {
990 unsafe {
991 (*self.extra.get()).interrupt_callback = None;
992 (*ffi::lua_callbacks(self.main_state)).interrupt = None;
993 }
994 }
995
996 #[cfg(feature = "lua54")]
1000 #[cfg_attr(docsrs, doc(cfg(feature = "lua54")))]
1001 pub fn set_warning_function<F>(&self, callback: F)
1002 where
1003 F: Fn(&Lua, &str, bool) -> Result<()> + MaybeSend + 'static,
1004 {
1005 unsafe extern "C-unwind" fn warn_proc(ud: *mut c_void, msg: *const c_char, tocont: c_int) {
1006 let extra = ud as *mut ExtraData;
1007 let lua: &Lua = mem::transmute((*extra).inner.assume_init_ref());
1008 callback_error_ext(lua.state(), extra, |_| {
1009 let cb = mlua_expect!(
1010 (*extra).warn_callback.as_ref(),
1011 "no warning callback set in warn_proc"
1012 );
1013 let msg = std::string::String::from_utf8_lossy(CStr::from_ptr(msg).to_bytes());
1014 cb(lua, &msg, tocont != 0)
1015 });
1016 }
1017
1018 let state = self.main_state;
1019 unsafe {
1020 (*self.extra.get()).warn_callback = Some(Box::new(callback));
1021 ffi::lua_setwarnf(state, Some(warn_proc), self.extra.get() as *mut c_void);
1022 }
1023 }
1024
1025 #[cfg(feature = "lua54")]
1031 #[cfg_attr(docsrs, doc(cfg(feature = "lua54")))]
1032 pub fn remove_warning_function(&self) {
1033 unsafe {
1034 (*self.extra.get()).warn_callback = None;
1035 ffi::lua_setwarnf(self.main_state, None, ptr::null_mut());
1036 }
1037 }
1038
1039 #[cfg(feature = "lua54")]
1046 #[cfg_attr(docsrs, doc(cfg(feature = "lua54")))]
1047 pub fn warning(&self, msg: impl AsRef<str>, incomplete: bool) {
1048 let msg = msg.as_ref();
1049 let mut bytes = vec![0; msg.len() + 1];
1050 bytes[..msg.len()].copy_from_slice(msg.as_bytes());
1051 let real_len = bytes.iter().position(|&c| c == 0).unwrap();
1052 bytes.truncate(real_len);
1053 unsafe {
1054 ffi::lua_warning(
1055 self.state(),
1056 bytes.as_ptr() as *const c_char,
1057 incomplete as c_int,
1058 );
1059 }
1060 }
1061
1062 pub fn inspect_stack(&self, level: usize) -> Option<Debug> {
1070 unsafe {
1071 let mut ar: ffi::lua_Debug = mem::zeroed();
1072 let level = level as c_int;
1073 #[cfg(not(feature = "luau"))]
1074 if ffi::lua_getstack(self.state(), level, &mut ar) == 0 {
1075 return None;
1076 }
1077 #[cfg(feature = "luau")]
1078 if ffi::lua_getinfo(self.state(), level, cstr!(""), &mut ar) == 0 {
1079 return None;
1080 }
1081 Some(Debug::new_owned(self, level, ar))
1082 }
1083 }
1084
1085 pub fn used_memory(&self) -> usize {
1087 unsafe {
1088 match MemoryState::get(self.main_state) {
1089 mem_state if !mem_state.is_null() => (*mem_state).used_memory(),
1090 _ => {
1091 let used_kbytes = ffi::lua_gc(self.main_state, ffi::LUA_GCCOUNT, 0);
1093 let used_kbytes_rem = ffi::lua_gc(self.main_state, ffi::LUA_GCCOUNTB, 0);
1094 (used_kbytes as usize) * 1024 + (used_kbytes_rem as usize)
1095 }
1096 }
1097 }
1098 }
1099
1100 pub fn set_memory_limit(&self, limit: usize) -> Result<usize> {
1108 unsafe {
1109 match MemoryState::get(self.main_state) {
1110 mem_state if !mem_state.is_null() => Ok((*mem_state).set_memory_limit(limit)),
1111 _ => Err(Error::MemoryLimitNotAvailable),
1112 }
1113 }
1114 }
1115
1116 #[cfg(any(
1120 feature = "lua54",
1121 feature = "lua53",
1122 feature = "lua52",
1123 feature = "luau"
1124 ))]
1125 pub fn gc_is_running(&self) -> bool {
1126 unsafe { ffi::lua_gc(self.main_state, ffi::LUA_GCISRUNNING, 0) != 0 }
1127 }
1128
1129 pub fn gc_stop(&self) {
1131 unsafe { ffi::lua_gc(self.main_state, ffi::LUA_GCSTOP, 0) };
1132 }
1133
1134 pub fn gc_restart(&self) {
1136 unsafe { ffi::lua_gc(self.main_state, ffi::LUA_GCRESTART, 0) };
1137 }
1138
1139 pub fn gc_collect(&self) -> Result<()> {
1144 unsafe {
1145 check_stack(self.main_state, 2)?;
1146 protect_lua!(self.main_state, 0, 0, fn(state) ffi::lua_gc(state, ffi::LUA_GCCOLLECT, 0))
1147 }
1148 }
1149
1150 pub fn gc_step(&self) -> Result<bool> {
1154 self.gc_step_kbytes(0)
1155 }
1156
1157 pub fn gc_step_kbytes(&self, kbytes: c_int) -> Result<bool> {
1162 unsafe {
1163 check_stack(self.main_state, 3)?;
1164 protect_lua!(self.main_state, 0, 0, |state| {
1165 ffi::lua_gc(state, ffi::LUA_GCSTEP, kbytes) != 0
1166 })
1167 }
1168 }
1169
1170 pub fn gc_set_pause(&self, pause: c_int) -> c_int {
1179 unsafe {
1180 #[cfg(not(feature = "luau"))]
1181 return ffi::lua_gc(self.main_state, ffi::LUA_GCSETPAUSE, pause);
1182 #[cfg(feature = "luau")]
1183 return ffi::lua_gc(self.main_state, ffi::LUA_GCSETGOAL, pause);
1184 }
1185 }
1186
1187 pub fn gc_set_step_multiplier(&self, step_multiplier: c_int) -> c_int {
1194 unsafe { ffi::lua_gc(self.main_state, ffi::LUA_GCSETSTEPMUL, step_multiplier) }
1195 }
1196
1197 pub fn gc_inc(&self, pause: c_int, step_multiplier: c_int, step_size: c_int) -> GCMode {
1204 let state = self.main_state;
1205
1206 #[cfg(any(
1207 feature = "lua53",
1208 feature = "lua52",
1209 feature = "lua51",
1210 feature = "luajit",
1211 feature = "luau"
1212 ))]
1213 unsafe {
1214 if pause > 0 {
1215 #[cfg(not(feature = "luau"))]
1216 ffi::lua_gc(state, ffi::LUA_GCSETPAUSE, pause);
1217 #[cfg(feature = "luau")]
1218 ffi::lua_gc(state, ffi::LUA_GCSETGOAL, pause);
1219 }
1220
1221 if step_multiplier > 0 {
1222 ffi::lua_gc(state, ffi::LUA_GCSETSTEPMUL, step_multiplier);
1223 }
1224
1225 #[cfg(feature = "luau")]
1226 if step_size > 0 {
1227 ffi::lua_gc(state, ffi::LUA_GCSETSTEPSIZE, step_size);
1228 }
1229 #[cfg(not(feature = "luau"))]
1230 let _ = step_size; GCMode::Incremental
1233 }
1234
1235 #[cfg(feature = "lua54")]
1236 let prev_mode =
1237 unsafe { ffi::lua_gc(state, ffi::LUA_GCINC, pause, step_multiplier, step_size) };
1238 #[cfg(feature = "lua54")]
1239 match prev_mode {
1240 ffi::LUA_GCINC => GCMode::Incremental,
1241 ffi::LUA_GCGEN => GCMode::Generational,
1242 _ => unreachable!(),
1243 }
1244 }
1245
1246 #[cfg(feature = "lua54")]
1255 #[cfg_attr(docsrs, doc(cfg(feature = "lua54")))]
1256 pub fn gc_gen(&self, minor_multiplier: c_int, major_multiplier: c_int) -> GCMode {
1257 let state = self.main_state;
1258 let prev_mode =
1259 unsafe { ffi::lua_gc(state, ffi::LUA_GCGEN, minor_multiplier, major_multiplier) };
1260 match prev_mode {
1261 ffi::LUA_GCGEN => GCMode::Generational,
1262 ffi::LUA_GCINC => GCMode::Incremental,
1263 _ => unreachable!(),
1264 }
1265 }
1266
1267 #[cfg(any(feature = "luau", doc))]
1276 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
1277 pub fn set_compiler(&self, compiler: Compiler) {
1278 unsafe { (*self.extra.get()).compiler = Some(compiler) };
1279 }
1280
1281 #[cfg(any(feature = "luau-jit", doc))]
1286 #[cfg_attr(docsrs, doc(cfg(feature = "luau-jit")))]
1287 pub fn enable_jit(&self, enable: bool) {
1288 unsafe { (*self.extra.get()).enable_jit = enable };
1289 }
1290
1291 #[cfg(feature = "luau")]
1295 #[doc(hidden)]
1296 #[allow(clippy::result_unit_err)]
1297 pub fn set_fflag(name: &str, enabled: bool) -> StdResult<(), ()> {
1298 if let Ok(name) = CString::new(name) {
1299 if unsafe { ffi::luau_setfflag(name.as_ptr(), enabled as c_int) != 0 } {
1300 return Ok(());
1301 }
1302 }
1303 Err(())
1304 }
1305
1306 #[track_caller]
1314 pub fn load<'lua, 'a>(&'lua self, chunk: impl AsChunk<'lua, 'a>) -> Chunk<'lua, 'a> {
1315 let caller = Location::caller();
1316 Chunk {
1317 lua: self,
1318 name: chunk.name().unwrap_or_else(|| caller.to_string()),
1319 env: chunk.environment(self),
1320 mode: chunk.mode(),
1321 source: chunk.source(),
1322 #[cfg(feature = "luau")]
1323 compiler: unsafe { (*self.extra.get()).compiler.clone() },
1324 }
1325 }
1326
1327 pub(crate) fn load_chunk<'lua>(
1328 &'lua self,
1329 name: Option<&CStr>,
1330 env: Option<Table>,
1331 mode: Option<ChunkMode>,
1332 source: &[u8],
1333 ) -> Result<Function<'lua>> {
1334 let state = self.state();
1335 unsafe {
1336 let _sg = StackGuard::new(state);
1337 check_stack(state, 1)?;
1338
1339 let mode_str = match mode {
1340 Some(ChunkMode::Binary) => cstr!("b"),
1341 Some(ChunkMode::Text) => cstr!("t"),
1342 None => cstr!("bt"),
1343 };
1344
1345 match ffi::luaL_loadbufferx(
1346 state,
1347 source.as_ptr() as *const c_char,
1348 source.len(),
1349 name.map(|n| n.as_ptr()).unwrap_or_else(ptr::null),
1350 mode_str,
1351 ) {
1352 ffi::LUA_OK => {
1353 if let Some(env) = env {
1354 self.push_ref(&env.0);
1355 #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
1356 ffi::lua_setupvalue(state, -2, 1);
1357 #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
1358 ffi::lua_setfenv(state, -2);
1359 }
1360
1361 #[cfg(feature = "luau-jit")]
1362 if (*self.extra.get()).enable_jit && ffi::luau_codegen_supported() != 0 {
1363 ffi::luau_codegen_compile(state, -1);
1364 }
1365
1366 Ok(Function(self.pop_ref()))
1367 }
1368 err => Err(pop_error(state, err)),
1369 }
1370 }
1371 }
1372
1373 pub fn create_string(&self, s: impl AsRef<[u8]>) -> Result<String> {
1377 let state = self.state();
1378 unsafe {
1379 if self.unlikely_memory_error() {
1380 push_string(self.ref_thread(), s.as_ref(), false)?;
1381 return Ok(String(self.pop_ref_thread()));
1382 }
1383
1384 let _sg = StackGuard::new(state);
1385 check_stack(state, 3)?;
1386 push_string(state, s.as_ref(), true)?;
1387 Ok(String(self.pop_ref()))
1388 }
1389 }
1390
1391 #[cfg(feature = "luau")]
1397 pub fn create_buffer(&self, buf: impl AsRef<[u8]>) -> Result<AnyUserData> {
1398 let state = self.state();
1399 unsafe {
1400 if self.unlikely_memory_error() {
1401 crate::util::push_buffer(self.ref_thread(), buf.as_ref(), false)?;
1402 return Ok(AnyUserData(self.pop_ref_thread(), SubtypeId::Buffer));
1403 }
1404
1405 let _sg = StackGuard::new(state);
1406 check_stack(state, 4)?;
1407 crate::util::push_buffer(state, buf.as_ref(), true)?;
1408 Ok(AnyUserData(self.pop_ref(), SubtypeId::Buffer))
1409 }
1410 }
1411
1412 pub fn create_table(&self) -> Result<Table> {
1414 self.create_table_with_capacity(0, 0)
1415 }
1416
1417 pub fn create_table_with_capacity(&self, narr: usize, nrec: usize) -> Result<Table> {
1422 let state = self.state();
1423 unsafe {
1424 if self.unlikely_memory_error() {
1425 push_table(self.ref_thread(), narr, nrec, false)?;
1426 return Ok(Table(self.pop_ref_thread()));
1427 }
1428
1429 let _sg = StackGuard::new(state);
1430 check_stack(state, 3)?;
1431 push_table(state, narr, nrec, true)?;
1432 Ok(Table(self.pop_ref()))
1433 }
1434 }
1435
1436 pub fn create_table_from<'lua, K, V, I>(&'lua self, iter: I) -> Result<Table<'lua>>
1438 where
1439 K: IntoLua<'lua>,
1440 V: IntoLua<'lua>,
1441 I: IntoIterator<Item = (K, V)>,
1442 {
1443 let state = self.state();
1444 unsafe {
1445 let _sg = StackGuard::new(state);
1446 check_stack(state, 6)?;
1447
1448 let iter = iter.into_iter();
1449 let lower_bound = iter.size_hint().0;
1450 let protect = !self.unlikely_memory_error();
1451 push_table(state, 0, lower_bound, protect)?;
1452 for (k, v) in iter {
1453 self.push(k)?;
1454 self.push(v)?;
1455 if protect {
1456 protect_lua!(state, 3, 1, fn(state) ffi::lua_rawset(state, -3))?;
1457 } else {
1458 ffi::lua_rawset(state, -3);
1459 }
1460 }
1461
1462 Ok(Table(self.pop_ref()))
1463 }
1464 }
1465
1466 pub fn create_sequence_from<'lua, T, I>(&'lua self, iter: I) -> Result<Table<'lua>>
1468 where
1469 T: IntoLua<'lua>,
1470 I: IntoIterator<Item = T>,
1471 {
1472 let state = self.state();
1473 unsafe {
1474 let _sg = StackGuard::new(state);
1475 check_stack(state, 5)?;
1476
1477 let iter = iter.into_iter();
1478 let lower_bound = iter.size_hint().0;
1479 let protect = !self.unlikely_memory_error();
1480 push_table(state, lower_bound, 0, protect)?;
1481 for (i, v) in iter.enumerate() {
1482 self.push(v)?;
1483 if protect {
1484 protect_lua!(state, 2, 1, |state| {
1485 ffi::lua_rawseti(state, -2, (i + 1) as Integer);
1486 })?;
1487 } else {
1488 ffi::lua_rawseti(state, -2, (i + 1) as Integer);
1489 }
1490 }
1491
1492 Ok(Table(self.pop_ref()))
1493 }
1494 }
1495
1496 pub fn create_function<'lua, A, R, F>(&'lua self, func: F) -> Result<Function<'lua>>
1542 where
1543 A: FromLuaMulti<'lua>,
1544 R: IntoLuaMulti<'lua>,
1545 F: Fn(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
1546 {
1547 self.create_callback(Box::new(move |lua, nargs| unsafe {
1548 let args = A::from_stack_args(nargs, 1, None, lua)?;
1549 func(lua, args)?.push_into_stack_multi(lua)
1550 }))
1551 }
1552
1553 pub fn create_function_mut<'lua, A, R, F>(&'lua self, func: F) -> Result<Function<'lua>>
1560 where
1561 A: FromLuaMulti<'lua>,
1562 R: IntoLuaMulti<'lua>,
1563 F: FnMut(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
1564 {
1565 let func = RefCell::new(func);
1566 self.create_function(move |lua, args| {
1567 (*func
1568 .try_borrow_mut()
1569 .map_err(|_| Error::RecursiveMutCallback)?)(lua, args)
1570 })
1571 }
1572
1573 pub unsafe fn create_c_function(&self, func: ffi::lua_CFunction) -> Result<Function> {
1578 let state = self.state();
1579 check_stack(state, 1)?;
1580 ffi::lua_pushcfunction(state, func);
1581 Ok(Function(self.pop_ref()))
1582 }
1583
1584 #[cfg(feature = "async")]
1624 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
1625 pub fn create_async_function<'lua, A, R, F, FR>(&'lua self, func: F) -> Result<Function<'lua>>
1626 where
1627 A: FromLuaMulti<'lua>,
1628 R: IntoLuaMulti<'lua>,
1629 F: Fn(&'lua Lua, A) -> FR + MaybeSend + 'static,
1630 FR: Future<Output = Result<R>> + 'lua,
1631 {
1632 self.create_async_callback(Box::new(move |lua, args| unsafe {
1633 let args = match A::from_lua_args(args, 1, None, lua) {
1634 Ok(args) => args,
1635 Err(e) => return Box::pin(future::err(e)),
1636 };
1637 let fut = func(lua, args);
1638 Box::pin(async move { fut.await?.push_into_stack_multi(lua) })
1639 }))
1640 }
1641
1642 pub fn create_thread<'lua>(&'lua self, func: Function) -> Result<Thread<'lua>> {
1646 self.create_thread_inner(&func)
1647 }
1648
1649 fn create_thread_inner<'lua>(&'lua self, func: &Function) -> Result<Thread<'lua>> {
1653 let state = self.state();
1654 unsafe {
1655 let _sg = StackGuard::new(state);
1656 check_stack(state, 3)?;
1657
1658 let thread_state = if self.unlikely_memory_error() {
1659 ffi::lua_newthread(state)
1660 } else {
1661 protect_lua!(state, 0, 1, |state| ffi::lua_newthread(state))?
1662 };
1663 self.push_ref(&func.0);
1664 ffi::lua_xmove(state, thread_state, 1);
1665
1666 Ok(Thread::new(self.pop_ref()))
1667 }
1668 }
1669
1670 #[cfg(feature = "async")]
1672 pub(crate) fn create_recycled_thread<'lua>(
1673 &'lua self,
1674 func: &Function,
1675 ) -> Result<Thread<'lua>> {
1676 #[cfg(any(feature = "lua54", feature = "luau"))]
1677 unsafe {
1678 let state = self.state();
1679 let _sg = StackGuard::new(state);
1680 check_stack(state, 1)?;
1681
1682 if let Some(index) = (*self.extra.get()).thread_pool.pop() {
1683 let thread_state = ffi::lua_tothread(self.ref_thread(), index);
1684 self.push_ref(&func.0);
1685 ffi::lua_xmove(state, thread_state, 1);
1686
1687 #[cfg(feature = "luau")]
1688 {
1689 ffi::lua_xpush(state, thread_state, ffi::LUA_GLOBALSINDEX);
1691 ffi::lua_replace(thread_state, ffi::LUA_GLOBALSINDEX);
1692 }
1693
1694 return Ok(Thread::new(LuaRef::new(self, index)));
1695 }
1696 };
1697 self.create_thread_inner(func)
1698 }
1699
1700 #[cfg(feature = "async")]
1702 #[cfg(any(feature = "lua54", feature = "luau"))]
1703 pub(crate) unsafe fn recycle_thread(&self, thread: &mut Thread) -> bool {
1704 let extra = &mut *self.extra.get();
1705 if extra.thread_pool.len() < extra.thread_pool.capacity() {
1706 let thread_state = ffi::lua_tothread(extra.ref_thread, thread.0.index);
1707 #[cfg(all(feature = "lua54", not(feature = "vendored")))]
1708 let status = ffi::lua_resetthread(thread_state);
1709 #[cfg(all(feature = "lua54", feature = "vendored"))]
1710 let status = ffi::lua_closethread(thread_state, self.state());
1711 #[cfg(feature = "lua54")]
1712 if status != ffi::LUA_OK {
1713 ffi::lua_settop(thread_state, 0);
1715 }
1716 #[cfg(feature = "luau")]
1717 ffi::lua_resetthread(thread_state);
1718 extra.thread_pool.push(thread.0.index);
1719 thread.0.drop = false;
1720 return true;
1721 }
1722 false
1723 }
1724
1725 #[inline]
1729 pub fn create_userdata<T>(&self, data: T) -> Result<AnyUserData>
1730 where
1731 T: UserData + MaybeSend + 'static,
1732 {
1733 unsafe { self.make_userdata(UserDataCell::new(data)) }
1734 }
1735
1736 #[cfg(feature = "serialize")]
1740 #[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
1741 #[inline]
1742 pub fn create_ser_userdata<T>(&self, data: T) -> Result<AnyUserData>
1743 where
1744 T: UserData + Serialize + MaybeSend + 'static,
1745 {
1746 unsafe { self.make_userdata(UserDataCell::new_ser(data)) }
1747 }
1748
1749 #[inline]
1757 pub fn create_any_userdata<T>(&self, data: T) -> Result<AnyUserData>
1758 where
1759 T: MaybeSend + 'static,
1760 {
1761 unsafe { self.make_any_userdata(UserDataCell::new(data)) }
1762 }
1763
1764 #[cfg(feature = "serialize")]
1770 #[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
1771 #[inline]
1772 pub fn create_ser_any_userdata<T>(&self, data: T) -> Result<AnyUserData>
1773 where
1774 T: Serialize + MaybeSend + 'static,
1775 {
1776 unsafe { self.make_any_userdata(UserDataCell::new_ser(data)) }
1777 }
1778
1779 pub fn register_userdata_type<T: 'static>(
1783 &self,
1784 f: impl FnOnce(&mut UserDataRegistry<T>),
1785 ) -> Result<()> {
1786 let mut registry = UserDataRegistry::new();
1787 f(&mut registry);
1788
1789 unsafe {
1790 let type_id = TypeId::of::<T>();
1792 if let Some(&table_id) = (*self.extra.get()).registered_userdata.get(&type_id) {
1793 ffi::luaL_unref(self.state(), ffi::LUA_REGISTRYINDEX, table_id);
1794 }
1795
1796 self.register_userdata_metatable(registry)?;
1798 Ok(())
1799 }
1800 }
1801
1802 #[inline]
1835 pub fn create_proxy<T>(&self) -> Result<AnyUserData>
1836 where
1837 T: UserData + 'static,
1838 {
1839 unsafe { self.make_userdata(UserDataCell::new(UserDataProxy::<T>(PhantomData))) }
1840 }
1841
1842 #[cfg(any(all(feature = "luau", feature = "unstable"), doc))]
1844 #[cfg_attr(docsrs, doc(cfg(all(feature = "luau", feature = "unstable"))))]
1845 pub fn set_vector_metatable(&self, metatable: Option<Table>) {
1846 unsafe {
1847 let state = self.state();
1848 let _sg = StackGuard::new(state);
1849 assert_stack(state, 2);
1850
1851 #[cfg(not(feature = "luau-vector4"))]
1852 ffi::lua_pushvector(state, 0., 0., 0.);
1853 #[cfg(feature = "luau-vector4")]
1854 ffi::lua_pushvector(state, 0., 0., 0., 0.);
1855 match metatable {
1856 Some(metatable) => self.push_ref(&metatable.0),
1857 None => ffi::lua_pushnil(state),
1858 };
1859 ffi::lua_setmetatable(state, -2);
1860 }
1861 }
1862
1863 pub fn globals(&self) -> Table {
1865 let state = self.state();
1866 unsafe {
1867 let _sg = StackGuard::new(state);
1868 assert_stack(state, 1);
1869 #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
1870 ffi::lua_rawgeti(state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS);
1871 #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
1872 ffi::lua_pushvalue(state, ffi::LUA_GLOBALSINDEX);
1873 Table(self.pop_ref())
1874 }
1875 }
1876
1877 pub fn current_thread(&self) -> Thread {
1880 let state = self.state();
1881 unsafe {
1882 let _sg = StackGuard::new(state);
1883 assert_stack(state, 1);
1884 ffi::lua_pushthread(state);
1885 Thread::new(self.pop_ref())
1886 }
1887 }
1888
1889 pub fn scope<'lua, 'scope, R>(
1910 &'lua self,
1911 f: impl FnOnce(&Scope<'lua, 'scope>) -> Result<R>,
1912 ) -> Result<R>
1913 where
1914 'lua: 'scope,
1915 {
1916 f(&Scope::new(self))
1917 }
1918
1919 pub fn coerce_string<'lua>(&'lua self, v: Value<'lua>) -> Result<Option<String<'lua>>> {
1925 Ok(match v {
1926 Value::String(s) => Some(s),
1927 v => unsafe {
1928 let state = self.state();
1929 let _sg = StackGuard::new(state);
1930 check_stack(state, 4)?;
1931
1932 self.push_value(v)?;
1933 let res = if self.unlikely_memory_error() {
1934 ffi::lua_tolstring(state, -1, ptr::null_mut())
1935 } else {
1936 protect_lua!(state, 1, 1, |state| {
1937 ffi::lua_tolstring(state, -1, ptr::null_mut())
1938 })?
1939 };
1940 if !res.is_null() {
1941 Some(String(self.pop_ref()))
1942 } else {
1943 None
1944 }
1945 },
1946 })
1947 }
1948
1949 pub fn coerce_integer(&self, v: Value) -> Result<Option<Integer>> {
1956 Ok(match v {
1957 Value::Integer(i) => Some(i),
1958 v => unsafe {
1959 let state = self.state();
1960 let _sg = StackGuard::new(state);
1961 check_stack(state, 2)?;
1962
1963 self.push_value(v)?;
1964 let mut isint = 0;
1965 let i = ffi::lua_tointegerx(state, -1, &mut isint);
1966 if isint == 0 {
1967 None
1968 } else {
1969 Some(i)
1970 }
1971 },
1972 })
1973 }
1974
1975 pub fn coerce_number(&self, v: Value) -> Result<Option<Number>> {
1981 Ok(match v {
1982 Value::Number(n) => Some(n),
1983 v => unsafe {
1984 let state = self.state();
1985 let _sg = StackGuard::new(state);
1986 check_stack(state, 2)?;
1987
1988 self.push_value(v)?;
1989 let mut isnum = 0;
1990 let n = ffi::lua_tonumberx(state, -1, &mut isnum);
1991 if isnum == 0 {
1992 None
1993 } else {
1994 Some(n)
1995 }
1996 },
1997 })
1998 }
1999
2000 pub fn pack<'lua, T: IntoLua<'lua>>(&'lua self, t: T) -> Result<Value<'lua>> {
2002 t.into_lua(self)
2003 }
2004
2005 pub fn unpack<'lua, T: FromLua<'lua>>(&'lua self, value: Value<'lua>) -> Result<T> {
2007 T::from_lua(value, self)
2008 }
2009
2010 pub fn pack_multi<'lua, T: IntoLuaMulti<'lua>>(&'lua self, t: T) -> Result<MultiValue<'lua>> {
2012 t.into_lua_multi(self)
2013 }
2014
2015 pub fn unpack_multi<'lua, T: FromLuaMulti<'lua>>(
2017 &'lua self,
2018 value: MultiValue<'lua>,
2019 ) -> Result<T> {
2020 T::from_lua_multi(value, self)
2021 }
2022
2023 pub fn set_named_registry_value<'lua, T>(&'lua self, name: &str, t: T) -> Result<()>
2028 where
2029 T: IntoLua<'lua>,
2030 {
2031 let state = self.state();
2032 unsafe {
2033 let _sg = StackGuard::new(state);
2034 check_stack(state, 5)?;
2035
2036 self.push(t)?;
2037 rawset_field(state, ffi::LUA_REGISTRYINDEX, name)
2038 }
2039 }
2040
2041 pub fn named_registry_value<'lua, T>(&'lua self, name: &str) -> Result<T>
2048 where
2049 T: FromLua<'lua>,
2050 {
2051 let state = self.state();
2052 unsafe {
2053 let _sg = StackGuard::new(state);
2054 check_stack(state, 3)?;
2055
2056 let protect = !self.unlikely_memory_error();
2057 push_string(state, name.as_bytes(), protect)?;
2058 ffi::lua_rawget(state, ffi::LUA_REGISTRYINDEX);
2059
2060 T::from_stack(-1, self)
2061 }
2062 }
2063
2064 pub fn unset_named_registry_value(&self, name: &str) -> Result<()> {
2070 self.set_named_registry_value(name, Nil)
2071 }
2072
2073 pub fn create_registry_value<'lua, T: IntoLua<'lua>>(&'lua self, t: T) -> Result<RegistryKey> {
2084 let state = self.state();
2085 unsafe {
2086 let _sg = StackGuard::new(state);
2087 check_stack(state, 4)?;
2088
2089 self.push(t)?;
2090
2091 let unref_list = (*self.extra.get()).registry_unref_list.clone();
2092
2093 if ffi::lua_isnil(state, -1) != 0 {
2095 return Ok(RegistryKey::new(ffi::LUA_REFNIL, unref_list));
2096 }
2097
2098 let free_registry_id = mlua_expect!(unref_list.lock(), "unref list poisoned")
2100 .as_mut()
2101 .and_then(|x| x.pop());
2102 if let Some(registry_id) = free_registry_id {
2103 ffi::lua_rawseti(state, ffi::LUA_REGISTRYINDEX, registry_id as Integer);
2105 return Ok(RegistryKey::new(registry_id, unref_list));
2106 }
2107
2108 let registry_id = if self.unlikely_memory_error() {
2110 ffi::luaL_ref(state, ffi::LUA_REGISTRYINDEX)
2111 } else {
2112 protect_lua!(state, 1, 0, |state| {
2113 ffi::luaL_ref(state, ffi::LUA_REGISTRYINDEX)
2114 })?
2115 };
2116 Ok(RegistryKey::new(registry_id, unref_list))
2117 }
2118 }
2119
2120 pub fn registry_value<'lua, T: FromLua<'lua>>(&'lua self, key: &RegistryKey) -> Result<T> {
2127 if !self.owns_registry_value(key) {
2128 return Err(Error::MismatchedRegistryKey);
2129 }
2130
2131 let state = self.state();
2132 match key.id() {
2133 ffi::LUA_REFNIL => T::from_lua(Value::Nil, self),
2134 registry_id => unsafe {
2135 let _sg = StackGuard::new(state);
2136 check_stack(state, 1)?;
2137
2138 ffi::lua_rawgeti(state, ffi::LUA_REGISTRYINDEX, registry_id as Integer);
2139 T::from_stack(-1, self)
2140 },
2141 }
2142 }
2143
2144 pub fn remove_registry_value(&self, key: RegistryKey) -> Result<()> {
2154 if !self.owns_registry_value(&key) {
2155 return Err(Error::MismatchedRegistryKey);
2156 }
2157
2158 unsafe {
2159 ffi::luaL_unref(self.state(), ffi::LUA_REGISTRYINDEX, key.take());
2160 }
2161 Ok(())
2162 }
2163
2164 pub fn replace_registry_value<'lua, T: IntoLua<'lua>>(
2170 &'lua self,
2171 key: &RegistryKey,
2172 t: T,
2173 ) -> Result<()> {
2174 if !self.owns_registry_value(key) {
2175 return Err(Error::MismatchedRegistryKey);
2176 }
2177
2178 let t = t.into_lua(self)?;
2179
2180 let state = self.state();
2181 unsafe {
2182 let _sg = StackGuard::new(state);
2183 check_stack(state, 2)?;
2184
2185 match (t, key.id()) {
2186 (Value::Nil, ffi::LUA_REFNIL) => {
2187 }
2189 (Value::Nil, registry_id) => {
2190 ffi::luaL_unref(state, ffi::LUA_REGISTRYINDEX, registry_id);
2192 key.set_id(ffi::LUA_REFNIL);
2193 }
2194 (value, ffi::LUA_REFNIL) => {
2195 let new_key = self.create_registry_value(value)?;
2197 key.set_id(new_key.take());
2198 }
2199 (value, registry_id) => {
2200 self.push_value(value)?;
2202 ffi::lua_rawseti(state, ffi::LUA_REGISTRYINDEX, registry_id as Integer);
2203 }
2204 }
2205 }
2206 Ok(())
2207 }
2208
2209 pub fn owns_registry_value(&self, key: &RegistryKey) -> bool {
2216 let registry_unref_list = unsafe { &(*self.extra.get()).registry_unref_list };
2217 Arc::ptr_eq(&key.unref_list, registry_unref_list)
2218 }
2219
2220 pub fn expire_registry_values(&self) {
2226 let state = self.state();
2227 unsafe {
2228 let mut unref_list = mlua_expect!(
2229 (*self.extra.get()).registry_unref_list.lock(),
2230 "unref list poisoned"
2231 );
2232 let unref_list = mem::replace(&mut *unref_list, Some(Vec::new()));
2233 for id in mlua_expect!(unref_list, "unref list not set") {
2234 ffi::luaL_unref(state, ffi::LUA_REGISTRYINDEX, id);
2235 }
2236 }
2237 }
2238
2239 #[track_caller]
2270 pub fn set_app_data<T: MaybeSend + 'static>(&self, data: T) -> Option<T> {
2271 let extra = unsafe { &*self.extra.get() };
2272 extra.app_data.insert(data)
2273 }
2274
2275 pub fn try_set_app_data<T: MaybeSend + 'static>(&self, data: T) -> StdResult<Option<T>, T> {
2284 let extra = unsafe { &*self.extra.get() };
2285 extra.app_data.try_insert(data)
2286 }
2287
2288 #[track_caller]
2295 pub fn app_data_ref<T: 'static>(&self) -> Option<AppDataRef<T>> {
2296 let extra = unsafe { &*self.extra.get() };
2297 extra.app_data.borrow()
2298 }
2299
2300 #[track_caller]
2306 pub fn app_data_mut<T: 'static>(&self) -> Option<AppDataRefMut<T>> {
2307 let extra = unsafe { &*self.extra.get() };
2308 extra.app_data.borrow_mut()
2309 }
2310
2311 #[track_caller]
2317 pub fn remove_app_data<T: 'static>(&self) -> Option<T> {
2318 let extra = unsafe { &*self.extra.get() };
2319 extra.app_data.remove()
2320 }
2321
2322 #[doc(hidden)]
2326 #[inline(always)]
2327 pub unsafe fn push<'lua>(&'lua self, value: impl IntoLua<'lua>) -> Result<()> {
2328 value.push_into_stack(self)
2329 }
2330
2331 #[doc(hidden)]
2335 pub unsafe fn push_value(&self, value: Value) -> Result<()> {
2336 if let Value::Error(err) = value {
2337 let protect = !self.unlikely_memory_error();
2338 return push_gc_userdata(self.state(), WrappedFailure::Error(err), protect);
2339 }
2340 self.push_value_ref(&value)
2341 }
2342
2343 pub(crate) unsafe fn push_value_ref(&self, value: &Value) -> Result<()> {
2347 let state = self.state();
2348 match value {
2349 Value::Nil => ffi::lua_pushnil(state),
2350 Value::Boolean(b) => ffi::lua_pushboolean(state, *b as c_int),
2351 Value::LightUserData(ud) => ffi::lua_pushlightuserdata(state, ud.0),
2352 Value::Integer(i) => ffi::lua_pushinteger(state, *i),
2353 Value::Number(n) => ffi::lua_pushnumber(state, *n),
2354 #[cfg(feature = "luau")]
2355 Value::Vector(v) => {
2356 #[cfg(not(feature = "luau-vector4"))]
2357 ffi::lua_pushvector(state, v.x(), v.y(), v.z());
2358 #[cfg(feature = "luau-vector4")]
2359 ffi::lua_pushvector(state, v.x(), v.y(), v.z(), v.w());
2360 }
2361 Value::String(s) => self.push_ref(&s.0),
2362 Value::Table(t) => self.push_ref(&t.0),
2363 Value::Function(f) => self.push_ref(&f.0),
2364 Value::Thread(t) => self.push_ref(&t.0),
2365 Value::UserData(ud) => self.push_ref(&ud.0),
2366 Value::Error(err) => {
2367 let protect = !self.unlikely_memory_error();
2368 push_gc_userdata(state, WrappedFailure::Error(err.clone()), protect)?;
2369 }
2370 }
2371 Ok(())
2372 }
2373
2374 #[doc(hidden)]
2378 pub unsafe fn pop_value(&self) -> Value {
2379 let state = self.state();
2380 match ffi::lua_type(state, -1) {
2381 ffi::LUA_TNIL => {
2382 ffi::lua_pop(state, 1);
2383 Nil
2384 }
2385
2386 ffi::LUA_TBOOLEAN => {
2387 let b = Value::Boolean(ffi::lua_toboolean(state, -1) != 0);
2388 ffi::lua_pop(state, 1);
2389 b
2390 }
2391
2392 ffi::LUA_TLIGHTUSERDATA => {
2393 let ud = Value::LightUserData(LightUserData(ffi::lua_touserdata(state, -1)));
2394 ffi::lua_pop(state, 1);
2395 ud
2396 }
2397
2398 #[cfg(any(feature = "lua54", feature = "lua53"))]
2399 ffi::LUA_TNUMBER => {
2400 let v = if ffi::lua_isinteger(state, -1) != 0 {
2401 Value::Integer(ffi::lua_tointeger(state, -1))
2402 } else {
2403 Value::Number(ffi::lua_tonumber(state, -1))
2404 };
2405 ffi::lua_pop(state, 1);
2406 v
2407 }
2408
2409 #[cfg(any(
2410 feature = "lua52",
2411 feature = "lua51",
2412 feature = "luajit",
2413 feature = "luau"
2414 ))]
2415 ffi::LUA_TNUMBER => {
2416 let n = ffi::lua_tonumber(state, -1);
2417 ffi::lua_pop(state, 1);
2418 match num_traits::cast(n) {
2419 Some(i) if (n - (i as Number)).abs() < Number::EPSILON => Value::Integer(i),
2420 _ => Value::Number(n),
2421 }
2422 }
2423
2424 #[cfg(feature = "luau")]
2425 ffi::LUA_TVECTOR => {
2426 let v = ffi::lua_tovector(state, -1);
2427 mlua_debug_assert!(!v.is_null(), "vector is null");
2428 #[cfg(not(feature = "luau-vector4"))]
2429 let vec = Value::Vector(Vector([*v, *v.add(1), *v.add(2)]));
2430 #[cfg(feature = "luau-vector4")]
2431 let vec = Value::Vector(Vector([*v, *v.add(1), *v.add(2), *v.add(3)]));
2432 ffi::lua_pop(state, 1);
2433 vec
2434 }
2435
2436 ffi::LUA_TSTRING => Value::String(String(self.pop_ref())),
2437
2438 ffi::LUA_TTABLE => Value::Table(Table(self.pop_ref())),
2439
2440 ffi::LUA_TFUNCTION => Value::Function(Function(self.pop_ref())),
2441
2442 ffi::LUA_TUSERDATA => {
2443 let wrapped_failure_mt_ptr = (*self.extra.get()).wrapped_failure_mt_ptr;
2444 match get_gc_userdata::<WrappedFailure>(state, -1, wrapped_failure_mt_ptr).as_mut()
2447 {
2448 Some(WrappedFailure::Error(err)) => {
2449 let err = err.clone();
2450 ffi::lua_pop(state, 1);
2451 Value::Error(err)
2452 }
2453 Some(WrappedFailure::Panic(panic)) => {
2454 if let Some(panic) = panic.take() {
2455 ffi::lua_pop(state, 1);
2456 resume_unwind(panic);
2457 }
2458 ffi::lua_pop(state, 1);
2460 Nil
2461 }
2462 _ => Value::UserData(AnyUserData(self.pop_ref(), SubtypeId::None)),
2463 }
2464 }
2465
2466 ffi::LUA_TTHREAD => Value::Thread(Thread::new(self.pop_ref())),
2467
2468 #[cfg(feature = "luau")]
2469 ffi::LUA_TBUFFER => {
2470 Value::UserData(AnyUserData(self.pop_ref(), SubtypeId::Buffer))
2472 }
2473
2474 #[cfg(feature = "luajit")]
2475 ffi::LUA_TCDATA => {
2476 Value::UserData(AnyUserData(self.pop_ref(), SubtypeId::CData))
2478 }
2479
2480 _ => mlua_panic!("LUA_TNONE in pop_value"),
2481 }
2482 }
2483
2484 pub(crate) unsafe fn stack_value(&self, idx: c_int) -> Value {
2488 let state = self.state();
2489 match ffi::lua_type(state, idx) {
2490 ffi::LUA_TNIL => Nil,
2491
2492 ffi::LUA_TBOOLEAN => Value::Boolean(ffi::lua_toboolean(state, idx) != 0),
2493
2494 ffi::LUA_TLIGHTUSERDATA => {
2495 Value::LightUserData(LightUserData(ffi::lua_touserdata(state, idx)))
2496 }
2497
2498 #[cfg(any(feature = "lua54", feature = "lua53"))]
2499 ffi::LUA_TNUMBER => {
2500 if ffi::lua_isinteger(state, idx) != 0 {
2501 Value::Integer(ffi::lua_tointeger(state, idx))
2502 } else {
2503 Value::Number(ffi::lua_tonumber(state, idx))
2504 }
2505 }
2506
2507 #[cfg(any(
2508 feature = "lua52",
2509 feature = "lua51",
2510 feature = "luajit",
2511 feature = "luau"
2512 ))]
2513 ffi::LUA_TNUMBER => {
2514 let n = ffi::lua_tonumber(state, idx);
2515 match num_traits::cast(n) {
2516 Some(i) if (n - (i as Number)).abs() < Number::EPSILON => Value::Integer(i),
2517 _ => Value::Number(n),
2518 }
2519 }
2520
2521 #[cfg(feature = "luau")]
2522 ffi::LUA_TVECTOR => {
2523 let v = ffi::lua_tovector(state, idx);
2524 mlua_debug_assert!(!v.is_null(), "vector is null");
2525 #[cfg(not(feature = "luau-vector4"))]
2526 return Value::Vector(Vector([*v, *v.add(1), *v.add(2)]));
2527 #[cfg(feature = "luau-vector4")]
2528 return Value::Vector(Vector([*v, *v.add(1), *v.add(2), *v.add(3)]));
2529 }
2530
2531 ffi::LUA_TSTRING => {
2532 ffi::lua_xpush(state, self.ref_thread(), idx);
2533 Value::String(String(self.pop_ref_thread()))
2534 }
2535
2536 ffi::LUA_TTABLE => {
2537 ffi::lua_xpush(state, self.ref_thread(), idx);
2538 Value::Table(Table(self.pop_ref_thread()))
2539 }
2540
2541 ffi::LUA_TFUNCTION => {
2542 ffi::lua_xpush(state, self.ref_thread(), idx);
2543 Value::Function(Function(self.pop_ref_thread()))
2544 }
2545
2546 ffi::LUA_TUSERDATA => {
2547 let wrapped_failure_mt_ptr = (*self.extra.get()).wrapped_failure_mt_ptr;
2548 match get_gc_userdata::<WrappedFailure>(state, idx, wrapped_failure_mt_ptr).as_mut()
2551 {
2552 Some(WrappedFailure::Error(err)) => Value::Error(err.clone()),
2553 Some(WrappedFailure::Panic(panic)) => {
2554 if let Some(panic) = panic.take() {
2555 resume_unwind(panic);
2556 }
2557 Value::Nil
2559 }
2560 _ => {
2561 ffi::lua_xpush(state, self.ref_thread(), idx);
2562 Value::UserData(AnyUserData(self.pop_ref_thread(), SubtypeId::None))
2563 }
2564 }
2565 }
2566
2567 ffi::LUA_TTHREAD => {
2568 ffi::lua_xpush(state, self.ref_thread(), idx);
2569 Value::Thread(Thread::new(self.pop_ref_thread()))
2570 }
2571
2572 #[cfg(feature = "luau")]
2573 ffi::LUA_TBUFFER => {
2574 ffi::lua_xpush(state, self.ref_thread(), idx);
2576 Value::UserData(AnyUserData(self.pop_ref_thread(), SubtypeId::Buffer))
2577 }
2578
2579 #[cfg(feature = "luajit")]
2580 ffi::LUA_TCDATA => {
2581 ffi::lua_xpush(state, self.ref_thread(), idx);
2583 Value::UserData(AnyUserData(self.pop_ref_thread(), SubtypeId::CData))
2584 }
2585
2586 _ => mlua_panic!("LUA_TNONE in pop_value"),
2587 }
2588 }
2589
2590 pub(crate) unsafe fn push_ref(&self, lref: &LuaRef) {
2592 assert!(
2593 Arc::ptr_eq(&lref.lua.0, &self.0),
2594 "Lua instance passed Value created from a different main Lua state"
2595 );
2596 ffi::lua_xpush(self.ref_thread(), self.state(), lref.index);
2597 }
2598
2599 #[cfg(all(feature = "unstable", not(feature = "send")))]
2600 pub(crate) unsafe fn push_owned_ref(&self, loref: &crate::types::LuaOwnedRef) {
2601 assert!(
2602 Arc::ptr_eq(&loref.inner, &self.0),
2603 "Lua instance passed Value created from a different main Lua state"
2604 );
2605 ffi::lua_xpush(self.ref_thread(), self.state(), loref.index);
2606 }
2607
2608 pub(crate) unsafe fn pop_ref(&self) -> LuaRef {
2618 ffi::lua_xmove(self.state(), self.ref_thread(), 1);
2619 let index = ref_stack_pop(self.extra.get());
2620 LuaRef::new(self, index)
2621 }
2622
2623 pub(crate) unsafe fn pop_ref_thread(&self) -> LuaRef {
2625 let index = ref_stack_pop(self.extra.get());
2626 LuaRef::new(self, index)
2627 }
2628
2629 pub(crate) fn clone_ref(&self, lref: &LuaRef) -> LuaRef {
2630 unsafe {
2631 ffi::lua_pushvalue(self.ref_thread(), lref.index);
2632 let index = ref_stack_pop(self.extra.get());
2633 LuaRef::new(self, index)
2634 }
2635 }
2636
2637 pub(crate) fn drop_ref_index(&self, index: c_int) {
2638 unsafe {
2639 let ref_thread = self.ref_thread();
2640 ffi::lua_pushnil(ref_thread);
2641 ffi::lua_replace(ref_thread, index);
2642 (*self.extra.get()).ref_free.push(index);
2643 }
2644 }
2645
2646 #[cfg(all(feature = "unstable", not(feature = "send")))]
2647 pub(crate) fn adopt_owned_ref(&self, loref: crate::types::LuaOwnedRef) -> LuaRef {
2648 assert!(
2649 Arc::ptr_eq(&loref.inner, &self.0),
2650 "Lua instance passed Value created from a different main Lua state"
2651 );
2652 let index = loref.index;
2653 unsafe {
2654 ptr::read(&loref.inner);
2655 mem::forget(loref);
2656 }
2657 LuaRef::new(self, index)
2658 }
2659
2660 #[inline]
2661 pub(crate) unsafe fn push_error_traceback(&self) {
2662 let state = self.state();
2663 #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
2664 ffi::lua_xpush(self.ref_thread(), state, ExtraData::ERROR_TRACEBACK_IDX);
2665 #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
2667 ffi::lua_pushcfunction(state, error_traceback);
2668 }
2669
2670 unsafe fn register_userdata_metatable<'lua, T: 'static>(
2671 &'lua self,
2672 mut registry: UserDataRegistry<'lua, T>,
2673 ) -> Result<Integer> {
2674 let state = self.state();
2675 let _sg = StackGuard::new(state);
2676 check_stack(state, 13)?;
2677
2678 let metatable_nrec = registry.meta_methods.len() + registry.meta_fields.len();
2680 #[cfg(feature = "async")]
2681 let metatable_nrec = metatable_nrec + registry.async_meta_methods.len();
2682 push_table(state, 0, metatable_nrec, true)?;
2683 for (k, m) in registry.meta_methods {
2684 self.push(self.create_callback(m)?)?;
2685 rawset_field(state, -2, MetaMethod::validate(&k)?)?;
2686 }
2687 #[cfg(feature = "async")]
2688 for (k, m) in registry.async_meta_methods {
2689 self.push(self.create_async_callback(m)?)?;
2690 rawset_field(state, -2, MetaMethod::validate(&k)?)?;
2691 }
2692 let mut has_name = false;
2693 for (k, f) in registry.meta_fields {
2694 has_name = has_name || k == MetaMethod::Type;
2695 mlua_assert!(f(self, 0)? == 1, "field function must return one value");
2696 rawset_field(state, -2, MetaMethod::validate(&k)?)?;
2697 }
2698 if !has_name {
2700 let type_name = short_type_name::<T>();
2701 push_string(state, type_name.as_bytes(), !self.unlikely_memory_error())?;
2702 rawset_field(state, -2, MetaMethod::Type.name())?;
2703 }
2704 let metatable_index = ffi::lua_absindex(state, -1);
2705
2706 let mut extra_tables_count = 0;
2707
2708 let fields_nrec = registry.fields.len();
2709 if fields_nrec > 0 {
2710 let index_type = ffi::lua_getfield(state, metatable_index, cstr!("__index"));
2712 match index_type {
2713 ffi::LUA_TNIL | ffi::LUA_TTABLE => {
2714 if index_type == ffi::LUA_TNIL {
2715 ffi::lua_pop(state, 1);
2717 push_table(state, 0, fields_nrec, true)?;
2718 }
2719 for (k, f) in registry.fields {
2720 mlua_assert!(f(self, 0)? == 1, "field function must return one value");
2721 rawset_field(state, -2, &k)?;
2722 }
2723 rawset_field(state, metatable_index, "__index")?;
2724 }
2725 _ => {
2726 ffi::lua_pop(state, 1);
2727 for (k, f) in registry.fields {
2729 registry.field_getters.push((k, f))
2730 }
2731 }
2732 }
2733 }
2734
2735 let mut field_getters_index = None;
2736 let field_getters_nrec = registry.field_getters.len();
2737 if field_getters_nrec > 0 {
2738 push_table(state, 0, field_getters_nrec, true)?;
2739 for (k, m) in registry.field_getters {
2740 self.push(self.create_callback(m)?)?;
2741 rawset_field(state, -2, &k)?;
2742 }
2743 field_getters_index = Some(ffi::lua_absindex(state, -1));
2744 extra_tables_count += 1;
2745 }
2746
2747 let mut field_setters_index = None;
2748 let field_setters_nrec = registry.field_setters.len();
2749 if field_setters_nrec > 0 {
2750 push_table(state, 0, field_setters_nrec, true)?;
2751 for (k, m) in registry.field_setters {
2752 self.push(self.create_callback(m)?)?;
2753 rawset_field(state, -2, &k)?;
2754 }
2755 field_setters_index = Some(ffi::lua_absindex(state, -1));
2756 extra_tables_count += 1;
2757 }
2758
2759 let mut methods_index = None;
2760 let methods_nrec = registry.methods.len();
2761 #[cfg(feature = "async")]
2762 let methods_nrec = methods_nrec + registry.async_methods.len();
2763 if methods_nrec > 0 {
2764 let index_type = ffi::lua_getfield(state, metatable_index, cstr!("__index"));
2766 match index_type {
2767 ffi::LUA_TTABLE => {} _ => {
2769 ffi::lua_pop(state, 1);
2771 push_table(state, 0, methods_nrec, true)?;
2772 }
2773 }
2774 for (k, m) in registry.methods {
2775 self.push(self.create_callback(m)?)?;
2776 rawset_field(state, -2, &k)?;
2777 }
2778 #[cfg(feature = "async")]
2779 for (k, m) in registry.async_methods {
2780 self.push(self.create_async_callback(m)?)?;
2781 rawset_field(state, -2, &k)?;
2782 }
2783 match index_type {
2784 ffi::LUA_TTABLE => {
2785 ffi::lua_pop(state, 1); }
2787 ffi::LUA_TNIL => {
2788 rawset_field(state, metatable_index, "__index")?; }
2790 _ => {
2791 methods_index = Some(ffi::lua_absindex(state, -1));
2792 extra_tables_count += 1;
2793 }
2794 }
2795 }
2796
2797 #[cfg(feature = "luau")]
2798 let extra_init = None;
2799 #[cfg(not(feature = "luau"))]
2800 let extra_init: Option<fn(*mut ffi::lua_State) -> Result<()>> = Some(|state| {
2801 ffi::lua_pushcfunction(state, util::userdata_destructor::<UserDataCell<T>>);
2802 rawset_field(state, -2, "__gc")
2803 });
2804
2805 init_userdata_metatable(
2806 state,
2807 metatable_index,
2808 field_getters_index,
2809 field_setters_index,
2810 methods_index,
2811 extra_init,
2812 )?;
2813
2814 ffi::lua_pop(state, extra_tables_count);
2816
2817 let mt_ptr = ffi::lua_topointer(state, -1);
2818 let id = protect_lua!(state, 1, 0, |state| {
2819 ffi::luaL_ref(state, ffi::LUA_REGISTRYINDEX)
2820 })?;
2821
2822 let type_id = TypeId::of::<T>();
2823 (*self.extra.get()).registered_userdata.insert(type_id, id);
2824 (*self.extra.get())
2825 .registered_userdata_mt
2826 .insert(mt_ptr, Some(type_id));
2827
2828 Ok(id as Integer)
2829 }
2830
2831 #[inline]
2832 pub(crate) unsafe fn register_raw_userdata_metatable(
2833 &self,
2834 ptr: *const c_void,
2835 type_id: Option<TypeId>,
2836 ) {
2837 (*self.extra.get())
2838 .registered_userdata_mt
2839 .insert(ptr, type_id);
2840 }
2841
2842 #[inline]
2843 pub(crate) unsafe fn deregister_raw_userdata_metatable(&self, ptr: *const c_void) {
2844 (*self.extra.get()).registered_userdata_mt.remove(&ptr);
2845 if (*self.extra.get()).last_checked_userdata_mt.0 == ptr {
2846 (*self.extra.get()).last_checked_userdata_mt = (ptr::null(), None);
2847 }
2848 }
2849
2850 pub(crate) unsafe fn get_userdata_ref_type_id(&self, lref: &LuaRef) -> Result<Option<TypeId>> {
2854 self.get_userdata_type_id_inner(self.ref_thread(), lref.index)
2855 }
2856
2857 pub(crate) unsafe fn get_userdata_type_id(&self, idx: c_int) -> Result<Option<TypeId>> {
2859 self.get_userdata_type_id_inner(self.state(), idx)
2860 }
2861
2862 unsafe fn get_userdata_type_id_inner(
2863 &self,
2864 state: *mut ffi::lua_State,
2865 idx: c_int,
2866 ) -> Result<Option<TypeId>> {
2867 if ffi::lua_getmetatable(state, idx) == 0 {
2868 return Err(Error::UserDataTypeMismatch);
2869 }
2870 let mt_ptr = ffi::lua_topointer(state, -1);
2871 ffi::lua_pop(state, 1);
2872
2873 let (last_mt, last_type_id) = (*self.extra.get()).last_checked_userdata_mt;
2875 if last_mt == mt_ptr {
2876 return Ok(last_type_id);
2877 }
2878
2879 match (*self.extra.get()).registered_userdata_mt.get(&mt_ptr) {
2880 Some(&type_id) if type_id == Some(TypeId::of::<DestructedUserdata>()) => {
2881 Err(Error::UserDataDestructed)
2882 }
2883 Some(&type_id) => {
2884 (*self.extra.get()).last_checked_userdata_mt = (mt_ptr, type_id);
2885 Ok(type_id)
2886 }
2887 None => Err(Error::UserDataTypeMismatch),
2888 }
2889 }
2890
2891 pub(crate) unsafe fn push_userdata_ref(&self, lref: &LuaRef) -> Result<Option<TypeId>> {
2894 let type_id = self.get_userdata_type_id_inner(self.ref_thread(), lref.index)?;
2895 self.push_ref(lref);
2896 Ok(type_id)
2897 }
2898
2899 pub(crate) fn create_callback<'lua>(
2908 &'lua self,
2909 func: Callback<'lua, 'static>,
2910 ) -> Result<Function<'lua>> {
2911 unsafe extern "C-unwind" fn call_callback(state: *mut ffi::lua_State) -> c_int {
2912 let (upvalue, extra) = match ffi::lua_type(state, ffi::lua_upvalueindex(1)) {
2915 ffi::LUA_TUSERDATA => {
2916 let upvalue = get_userdata::<CallbackUpvalue>(state, ffi::lua_upvalueindex(1));
2917 (upvalue, (*upvalue).extra.get())
2918 }
2919 _ => (ptr::null_mut(), ptr::null_mut()),
2920 };
2921 callback_error_ext(state, extra, |nargs| {
2922 if upvalue.is_null() {
2924 return Err(Error::CallbackDestructed);
2925 }
2926
2927 let lua: &Lua = mem::transmute((*extra).inner.assume_init_ref());
2928 let _guard = StateGuard::new(&lua.0, state);
2929 let func = &*(*upvalue).data;
2930
2931 func(lua, nargs)
2932 })
2933 }
2934
2935 let state = self.state();
2936 unsafe {
2937 let _sg = StackGuard::new(state);
2938 check_stack(state, 4)?;
2939
2940 let func = mem::transmute(func);
2941 let extra = Arc::clone(&self.extra);
2942 let protect = !self.unlikely_memory_error();
2943 push_gc_userdata(state, CallbackUpvalue { data: func, extra }, protect)?;
2944 if protect {
2945 protect_lua!(state, 1, 1, fn(state) {
2946 ffi::lua_pushcclosure(state, call_callback, 1);
2947 })?;
2948 } else {
2949 ffi::lua_pushcclosure(state, call_callback, 1);
2950 }
2951
2952 Ok(Function(self.pop_ref()))
2953 }
2954 }
2955
2956 #[cfg(feature = "async")]
2957 pub(crate) fn create_async_callback<'lua>(
2958 &'lua self,
2959 func: AsyncCallback<'lua, 'static>,
2960 ) -> Result<Function<'lua>> {
2961 #[cfg(any(
2962 feature = "lua54",
2963 feature = "lua53",
2964 feature = "lua52",
2965 feature = "luau"
2966 ))]
2967 unsafe {
2968 if !(*self.extra.get()).libs.contains(StdLib::COROUTINE) {
2969 load_from_std_lib(self.main_state, StdLib::COROUTINE)?;
2970 (*self.extra.get()).libs |= StdLib::COROUTINE;
2971 }
2972 }
2973
2974 unsafe extern "C-unwind" fn call_callback(state: *mut ffi::lua_State) -> c_int {
2975 let upvalue = get_userdata::<AsyncCallbackUpvalue>(state, ffi::lua_upvalueindex(1));
2978 let extra = (*upvalue).extra.get();
2979 callback_error_ext(state, extra, |nargs| {
2980 let lua: &Lua = mem::transmute((*extra).inner.assume_init_ref());
2982 let _guard = StateGuard::new(&lua.0, state);
2983
2984 let args = MultiValue::from_stack_multi(nargs, lua)?;
2985 let func = &*(*upvalue).data;
2986 let fut = func(lua, args);
2987 let extra = Arc::clone(&(*upvalue).extra);
2988 let protect = !lua.unlikely_memory_error();
2989 push_gc_userdata(state, AsyncPollUpvalue { data: fut, extra }, protect)?;
2990 if protect {
2991 protect_lua!(state, 1, 1, fn(state) {
2992 ffi::lua_pushcclosure(state, poll_future, 1);
2993 })?;
2994 } else {
2995 ffi::lua_pushcclosure(state, poll_future, 1);
2996 }
2997
2998 Ok(1)
2999 })
3000 }
3001
3002 unsafe extern "C-unwind" fn poll_future(state: *mut ffi::lua_State) -> c_int {
3003 let upvalue = get_userdata::<AsyncPollUpvalue>(state, ffi::lua_upvalueindex(1));
3004 let extra = (*upvalue).extra.get();
3005 callback_error_ext(state, extra, |_| {
3006 let lua: &Lua = mem::transmute((*extra).inner.assume_init_ref());
3008 let _guard = StateGuard::new(&lua.0, state);
3009
3010 let fut = &mut (*upvalue).data;
3011 let mut ctx = Context::from_waker(lua.waker());
3012 match fut.as_mut().poll(&mut ctx) {
3013 Poll::Pending => {
3014 ffi::lua_pushnil(state);
3015 ffi::lua_pushlightuserdata(state, Lua::poll_pending().0);
3016 Ok(2)
3017 }
3018 Poll::Ready(nresults) => {
3019 match nresults? {
3020 nresults @ 0..=2 => {
3021 ffi::lua_pushinteger(state, nresults as _);
3023 if nresults > 0 {
3024 ffi::lua_insert(state, -nresults - 1);
3025 }
3026 Ok(nresults + 1)
3027 }
3028 nresults => {
3029 let results = MultiValue::from_stack_multi(nresults, lua)?;
3030 ffi::lua_pushinteger(state, nresults as _);
3031 lua.push(lua.create_sequence_from(results)?)?;
3032 Ok(2)
3033 }
3034 }
3035 }
3036 }
3037 })
3038 }
3039
3040 let state = self.state();
3041 let get_poll = unsafe {
3042 let _sg = StackGuard::new(state);
3043 check_stack(state, 4)?;
3044
3045 let func = mem::transmute(func);
3046 let extra = Arc::clone(&self.extra);
3047 let protect = !self.unlikely_memory_error();
3048 let upvalue = AsyncCallbackUpvalue { data: func, extra };
3049 push_gc_userdata(state, upvalue, protect)?;
3050 if protect {
3051 protect_lua!(state, 1, 1, fn(state) {
3052 ffi::lua_pushcclosure(state, call_callback, 1);
3053 })?;
3054 } else {
3055 ffi::lua_pushcclosure(state, call_callback, 1);
3056 }
3057
3058 Function(self.pop_ref())
3059 };
3060
3061 unsafe extern "C-unwind" fn unpack(state: *mut ffi::lua_State) -> c_int {
3062 let len = ffi::lua_tointeger(state, 2);
3063 ffi::luaL_checkstack(state, len as c_int, ptr::null());
3064 for i in 1..=len {
3065 ffi::lua_rawgeti(state, 1, i);
3066 }
3067 len as c_int
3068 }
3069
3070 let coroutine = self.globals().get::<_, Table>("coroutine")?;
3071
3072 let env = self.create_table_with_capacity(0, 3)?;
3073 env.set("get_poll", get_poll)?;
3074 env.set("yield", coroutine.get::<_, Function>("yield")?)?;
3076 unsafe {
3077 env.set("unpack", self.create_c_function(unpack)?)?;
3078 }
3079
3080 self.load(
3081 r#"
3082 local poll = get_poll(...)
3083 while true do
3084 local nres, res, res2 = poll()
3085 if nres ~= nil then
3086 if nres == 0 then
3087 return
3088 elseif nres == 1 then
3089 return res
3090 elseif nres == 2 then
3091 return res, res2
3092 else
3093 return unpack(res, nres)
3094 end
3095 end
3096 yield(res) -- `res` is a "pending" value
3097 end
3098 "#,
3099 )
3100 .try_cache()
3101 .set_name("__mlua_async_poll")
3102 .set_environment(env)
3103 .into_function()
3104 }
3105
3106 #[cfg(feature = "async")]
3107 #[inline]
3108 pub(crate) unsafe fn waker(&self) -> &Waker {
3109 (*self.extra.get()).waker.as_ref()
3110 }
3111
3112 #[cfg(feature = "async")]
3113 #[inline]
3114 pub(crate) unsafe fn set_waker(&self, waker: NonNull<Waker>) -> NonNull<Waker> {
3115 mem::replace(&mut (*self.extra.get()).waker, waker)
3116 }
3117
3118 #[cfg(feature = "async")]
3120 #[doc(hidden)]
3121 #[inline]
3122 pub fn poll_pending() -> LightUserData {
3123 LightUserData(&ASYNC_POLL_PENDING as *const u8 as *mut c_void)
3124 }
3125
3126 pub(crate) unsafe fn make_userdata<T>(&self, data: UserDataCell<T>) -> Result<AnyUserData>
3127 where
3128 T: UserData + 'static,
3129 {
3130 self.make_userdata_with_metatable(data, || {
3131 let type_id = TypeId::of::<T>();
3133 if let Some(&table_id) = (*self.extra.get()).registered_userdata.get(&type_id) {
3134 return Ok(table_id as Integer);
3135 }
3136
3137 let mut registry = UserDataRegistry::new();
3139 T::add_fields(&mut registry);
3140 T::add_methods(&mut registry);
3141
3142 self.register_userdata_metatable(registry)
3143 })
3144 }
3145
3146 pub(crate) unsafe fn make_any_userdata<T>(&self, data: UserDataCell<T>) -> Result<AnyUserData>
3147 where
3148 T: 'static,
3149 {
3150 self.make_userdata_with_metatable(data, || {
3151 let type_id = TypeId::of::<T>();
3153 if let Some(&table_id) = (*self.extra.get()).registered_userdata.get(&type_id) {
3154 return Ok(table_id as Integer);
3155 }
3156
3157 let registry = UserDataRegistry::new();
3159 self.register_userdata_metatable::<T>(registry)
3160 })
3161 }
3162
3163 unsafe fn make_userdata_with_metatable<T>(
3164 &self,
3165 data: UserDataCell<T>,
3166 get_metatable_id: impl FnOnce() -> Result<Integer>,
3167 ) -> Result<AnyUserData> {
3168 let state = self.state();
3169 let _sg = StackGuard::new(state);
3170 check_stack(state, 3)?;
3171
3172 ffi::lua_pushnil(state);
3174 ffi::lua_rawgeti(state, ffi::LUA_REGISTRYINDEX, get_metatable_id()?);
3175 let protect = !self.unlikely_memory_error();
3176 #[cfg(not(feature = "lua54"))]
3177 push_userdata(state, data, protect)?;
3178 #[cfg(feature = "lua54")]
3179 push_userdata_uv(state, data, USER_VALUE_MAXSLOT as c_int, protect)?;
3180 ffi::lua_replace(state, -3);
3181 ffi::lua_setmetatable(state, -2);
3182
3183 #[cfg(any(feature = "lua51", feature = "luajit"))]
3185 if protect {
3186 protect_lua!(state, 1, 1, fn(state) {
3187 ffi::lua_newtable(state);
3188 ffi::lua_setuservalue(state, -2);
3189 })?;
3190 } else {
3191 ffi::lua_newtable(state);
3192 ffi::lua_setuservalue(state, -2);
3193 }
3194
3195 Ok(AnyUserData(self.pop_ref(), SubtypeId::None))
3196 }
3197
3198 #[cfg(not(feature = "luau"))]
3200 fn disable_c_modules(&self) -> Result<()> {
3201 let package: Table = self.globals().get("package")?;
3202
3203 package.set(
3204 "loadlib",
3205 self.create_function(|_, ()| -> Result<()> {
3206 Err(Error::SafetyError(
3207 "package.loadlib is disabled in safe mode".to_string(),
3208 ))
3209 })?,
3210 )?;
3211
3212 #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
3213 let searchers: Table = package.get("searchers")?;
3214 #[cfg(any(feature = "lua51", feature = "luajit"))]
3215 let searchers: Table = package.get("loaders")?;
3216
3217 let loader = self.create_function(|_, ()| Ok("\n\tcan't load C modules in safe mode"))?;
3218
3219 searchers.raw_set(3, loader.clone())?;
3221 searchers.raw_remove(4)?;
3222
3223 Ok(())
3224 }
3225
3226 pub(crate) unsafe fn try_from_ptr(state: *mut ffi::lua_State) -> Option<Self> {
3227 let extra = extra_data(state);
3228 if extra.is_null() {
3229 return None;
3230 }
3231 Some(Lua(Arc::clone((*extra).inner.assume_init_ref())))
3232 }
3233
3234 #[inline]
3235 pub(crate) unsafe fn unlikely_memory_error(&self) -> bool {
3236 match MemoryState::get(self.main_state) {
3238 mem_state if !mem_state.is_null() => (*mem_state).memory_limit() == 0,
3239 #[cfg(feature = "module")]
3240 _ => (*self.extra.get()).skip_memory_check, #[cfg(not(feature = "module"))]
3242 _ => false,
3243 }
3244 }
3245
3246 #[cfg(feature = "unstable")]
3247 #[inline]
3248 pub(crate) fn clone(&self) -> Arc<LuaInner> {
3249 Arc::clone(&self.0)
3250 }
3251}
3252
3253impl LuaInner {
3254 #[inline(always)]
3255 pub(crate) fn state(&self) -> *mut ffi::lua_State {
3256 self.state.load(Ordering::Relaxed)
3257 }
3258
3259 #[cfg(feature = "luau")]
3260 #[inline(always)]
3261 pub(crate) fn main_state(&self) -> *mut ffi::lua_State {
3262 self.main_state
3263 }
3264
3265 #[inline(always)]
3266 pub(crate) fn ref_thread(&self) -> *mut ffi::lua_State {
3267 unsafe { (*self.extra.get()).ref_thread }
3268 }
3269
3270 #[inline]
3271 pub(crate) fn pop_multivalue_from_pool(&self) -> Option<Vec<Value>> {
3272 let extra = unsafe { &mut *self.extra.get() };
3273 extra.multivalue_pool.pop()
3274 }
3275
3276 #[inline]
3277 pub(crate) fn push_multivalue_to_pool(&self, mut multivalue: Vec<Value>) {
3278 let extra = unsafe { &mut *self.extra.get() };
3279 if extra.multivalue_pool.len() < MULTIVALUE_POOL_SIZE {
3280 multivalue.clear();
3281 extra
3282 .multivalue_pool
3283 .push(unsafe { mem::transmute(multivalue) });
3284 }
3285 }
3286}
3287
3288impl ExtraData {
3289 #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
3291 const ERROR_TRACEBACK_IDX: c_int = 1;
3292}
3293
3294struct StateGuard<'a>(&'a LuaInner, *mut ffi::lua_State);
3295
3296impl<'a> StateGuard<'a> {
3297 fn new(inner: &'a LuaInner, mut state: *mut ffi::lua_State) -> Self {
3298 state = inner.state.swap(state, Ordering::Relaxed);
3299 Self(inner, state)
3300 }
3301}
3302
3303impl<'a> Drop for StateGuard<'a> {
3304 fn drop(&mut self) {
3305 self.0.state.store(self.1, Ordering::Relaxed);
3306 }
3307}
3308
3309unsafe fn extra_data(state: *mut ffi::lua_State) -> *mut ExtraData {
3310 #[cfg(feature = "luau")]
3311 if cfg!(not(feature = "module")) {
3312 return (*ffi::lua_callbacks(state)).userdata as *mut _;
3314 }
3315
3316 let extra_key = &EXTRA_REGISTRY_KEY as *const u8 as *const c_void;
3317 if ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, extra_key) != ffi::LUA_TUSERDATA {
3318 ffi::lua_pop(state, 1);
3321 return ptr::null_mut();
3322 }
3323 let extra_ptr = ffi::lua_touserdata(state, -1) as *mut Arc<UnsafeCell<ExtraData>>;
3324 ffi::lua_pop(state, 1);
3325 (*extra_ptr).get()
3326}
3327
3328unsafe fn set_extra_data(
3329 state: *mut ffi::lua_State,
3330 extra: &Arc<UnsafeCell<ExtraData>>,
3331) -> Result<()> {
3332 #[cfg(feature = "luau")]
3333 if cfg!(not(feature = "module")) {
3334 (*ffi::lua_callbacks(state)).userdata = extra.get() as *mut _;
3335 return Ok(());
3336 }
3337
3338 push_gc_userdata(state, Arc::clone(extra), true)?;
3339 protect_lua!(state, 1, 0, fn(state) {
3340 let extra_key = &EXTRA_REGISTRY_KEY as *const u8 as *const c_void;
3341 ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, extra_key);
3342 })
3343}
3344
3345pub(crate) fn init_metatable_cache(cache: &mut FxHashMap<TypeId, u8>) {
3347 cache.insert(TypeId::of::<Arc<UnsafeCell<ExtraData>>>(), 0);
3348 cache.insert(TypeId::of::<Callback>(), 0);
3349 cache.insert(TypeId::of::<CallbackUpvalue>(), 0);
3350
3351 #[cfg(feature = "async")]
3352 {
3353 cache.insert(TypeId::of::<AsyncCallback>(), 0);
3354 cache.insert(TypeId::of::<AsyncCallbackUpvalue>(), 0);
3355 cache.insert(TypeId::of::<AsyncPollUpvalue>(), 0);
3356 cache.insert(TypeId::of::<Option<Waker>>(), 0);
3357 }
3358}
3359
3360unsafe fn callback_error_ext<F, R>(state: *mut ffi::lua_State, mut extra: *mut ExtraData, f: F) -> R
3363where
3364 F: FnOnce(c_int) -> Result<R>,
3365{
3366 if extra.is_null() {
3367 extra = extra_data(state);
3368 }
3369
3370 let nargs = ffi::lua_gettop(state);
3371
3372 enum PreallocatedFailure {
3373 New(*mut WrappedFailure),
3374 Existing(i32),
3375 }
3376
3377 impl PreallocatedFailure {
3378 unsafe fn reserve(state: *mut ffi::lua_State, extra: *mut ExtraData) -> Self {
3379 match (*extra).wrapped_failure_pool.pop() {
3380 Some(index) => PreallocatedFailure::Existing(index),
3381 None => {
3382 #[cfg(feature = "luau")]
3385 ffi::lua_rawcheckstack(state, 2);
3386 let ud = WrappedFailure::new_userdata(state);
3388 ffi::lua_insert(state, 1);
3389 PreallocatedFailure::New(ud)
3390 }
3391 }
3392 }
3393
3394 unsafe fn r#use(
3395 &self,
3396 state: *mut ffi::lua_State,
3397 extra: *mut ExtraData,
3398 ) -> *mut WrappedFailure {
3399 let ref_thread = (*extra).ref_thread;
3400 match *self {
3401 PreallocatedFailure::New(ud) => {
3402 ffi::lua_settop(state, 1);
3403 ud
3404 }
3405 PreallocatedFailure::Existing(index) => {
3406 ffi::lua_settop(state, 0);
3407 #[cfg(feature = "luau")]
3408 ffi::lua_rawcheckstack(state, 2);
3409 ffi::lua_pushvalue(ref_thread, index);
3410 ffi::lua_xmove(ref_thread, state, 1);
3411 ffi::lua_pushnil(ref_thread);
3412 ffi::lua_replace(ref_thread, index);
3413 (*extra).ref_free.push(index);
3414 ffi::lua_touserdata(state, -1) as *mut WrappedFailure
3415 }
3416 }
3417 }
3418
3419 unsafe fn release(self, state: *mut ffi::lua_State, extra: *mut ExtraData) {
3420 let ref_thread = (*extra).ref_thread;
3421 match self {
3422 PreallocatedFailure::New(_) => {
3423 if (*extra).wrapped_failure_pool.len() < WRAPPED_FAILURE_POOL_SIZE {
3424 ffi::lua_rotate(state, 1, -1);
3425 ffi::lua_xmove(state, ref_thread, 1);
3426 let index = ref_stack_pop(extra);
3427 (*extra).wrapped_failure_pool.push(index);
3428 } else {
3429 ffi::lua_remove(state, 1);
3430 }
3431 }
3432 PreallocatedFailure::Existing(index) => {
3433 if (*extra).wrapped_failure_pool.len() < WRAPPED_FAILURE_POOL_SIZE {
3434 (*extra).wrapped_failure_pool.push(index);
3435 } else {
3436 ffi::lua_pushnil(ref_thread);
3437 ffi::lua_replace(ref_thread, index);
3438 (*extra).ref_free.push(index);
3439 }
3440 }
3441 }
3442 }
3443 }
3444
3445 let prealloc_failure = PreallocatedFailure::reserve(state, extra);
3448
3449 match catch_unwind(AssertUnwindSafe(|| f(nargs))) {
3450 Ok(Ok(r)) => {
3451 prealloc_failure.release(state, extra);
3453 r
3454 }
3455 Ok(Err(err)) => {
3456 let wrapped_error = prealloc_failure.r#use(state, extra);
3457
3458 let traceback = if ffi::lua_checkstack(state, ffi::LUA_TRACEBACK_STACK) != 0 {
3460 ffi::luaL_traceback(state, state, ptr::null(), 0);
3461 let traceback = util::to_string(state, -1);
3462 ffi::lua_pop(state, 1);
3463 traceback
3464 } else {
3465 "<not enough stack space for traceback>".to_string()
3466 };
3467 let cause = Arc::new(err);
3468 ptr::write(
3469 wrapped_error,
3470 WrappedFailure::Error(Error::CallbackError { traceback, cause }),
3471 );
3472 get_gc_metatable::<WrappedFailure>(state);
3473 ffi::lua_setmetatable(state, -2);
3474
3475 ffi::lua_error(state)
3476 }
3477 Err(p) => {
3478 let wrapped_panic = prealloc_failure.r#use(state, extra);
3479 ptr::write(wrapped_panic, WrappedFailure::Panic(Some(p)));
3480 get_gc_metatable::<WrappedFailure>(state);
3481 ffi::lua_setmetatable(state, -2);
3482 ffi::lua_error(state)
3483 }
3484 }
3485}
3486
3487unsafe fn load_from_std_lib(state: *mut ffi::lua_State, libs: StdLib) -> Result<()> {
3489 #[inline(always)]
3490 pub unsafe fn requiref(
3491 state: *mut ffi::lua_State,
3492 modname: &str,
3493 openf: ffi::lua_CFunction,
3494 glb: c_int,
3495 ) -> Result<()> {
3496 let modname = mlua_expect!(CString::new(modname), "modname contains nil byte");
3497 protect_lua!(state, 0, 1, |state| {
3498 ffi::luaL_requiref(state, modname.as_ptr() as *const c_char, openf, glb)
3499 })
3500 }
3501
3502 #[cfg(feature = "luajit")]
3503 struct GcGuard(*mut ffi::lua_State);
3504
3505 #[cfg(feature = "luajit")]
3506 impl GcGuard {
3507 fn new(state: *mut ffi::lua_State) -> Self {
3508 unsafe { ffi::lua_gc(state, ffi::LUA_GCSTOP, 0) };
3510 GcGuard(state)
3511 }
3512 }
3513
3514 #[cfg(feature = "luajit")]
3515 impl Drop for GcGuard {
3516 fn drop(&mut self) {
3517 unsafe { ffi::lua_gc(self.0, ffi::LUA_GCRESTART, -1) };
3518 }
3519 }
3520
3521 #[cfg(feature = "luajit")]
3523 let _gc_guard = GcGuard::new(state);
3524
3525 #[cfg(any(
3526 feature = "lua54",
3527 feature = "lua53",
3528 feature = "lua52",
3529 feature = "luau"
3530 ))]
3531 {
3532 if libs.contains(StdLib::COROUTINE) {
3533 requiref(state, ffi::LUA_COLIBNAME, ffi::luaopen_coroutine, 1)?;
3534 ffi::lua_pop(state, 1);
3535 }
3536 }
3537
3538 if libs.contains(StdLib::TABLE) {
3539 requiref(state, ffi::LUA_TABLIBNAME, ffi::luaopen_table, 1)?;
3540 ffi::lua_pop(state, 1);
3541 }
3542
3543 #[cfg(not(feature = "luau"))]
3544 if libs.contains(StdLib::IO) {
3545 requiref(state, ffi::LUA_IOLIBNAME, ffi::luaopen_io, 1)?;
3546 ffi::lua_pop(state, 1);
3547 }
3548
3549 if libs.contains(StdLib::OS) {
3550 requiref(state, ffi::LUA_OSLIBNAME, ffi::luaopen_os, 1)?;
3551 ffi::lua_pop(state, 1);
3552 }
3553
3554 if libs.contains(StdLib::STRING) {
3555 requiref(state, ffi::LUA_STRLIBNAME, ffi::luaopen_string, 1)?;
3556 ffi::lua_pop(state, 1);
3557 }
3558
3559 #[cfg(any(feature = "lua54", feature = "lua53", feature = "luau"))]
3560 {
3561 if libs.contains(StdLib::UTF8) {
3562 requiref(state, ffi::LUA_UTF8LIBNAME, ffi::luaopen_utf8, 1)?;
3563 ffi::lua_pop(state, 1);
3564 }
3565 }
3566
3567 #[cfg(any(feature = "lua52", feature = "luau"))]
3568 {
3569 if libs.contains(StdLib::BIT) {
3570 requiref(state, ffi::LUA_BITLIBNAME, ffi::luaopen_bit32, 1)?;
3571 ffi::lua_pop(state, 1);
3572 }
3573 }
3574
3575 #[cfg(feature = "luajit")]
3576 {
3577 if libs.contains(StdLib::BIT) {
3578 requiref(state, ffi::LUA_BITLIBNAME, ffi::luaopen_bit, 1)?;
3579 ffi::lua_pop(state, 1);
3580 }
3581 }
3582
3583 #[cfg(feature = "luau")]
3584 if libs.contains(StdLib::BUFFER) {
3585 requiref(state, ffi::LUA_BUFFERLIBNAME, ffi::luaopen_buffer, 1)?;
3586 ffi::lua_pop(state, 1);
3587 }
3588
3589 if libs.contains(StdLib::MATH) {
3590 requiref(state, ffi::LUA_MATHLIBNAME, ffi::luaopen_math, 1)?;
3591 ffi::lua_pop(state, 1);
3592 }
3593
3594 if libs.contains(StdLib::DEBUG) {
3595 requiref(state, ffi::LUA_DBLIBNAME, ffi::luaopen_debug, 1)?;
3596 ffi::lua_pop(state, 1);
3597 }
3598
3599 #[cfg(not(feature = "luau"))]
3600 if libs.contains(StdLib::PACKAGE) {
3601 requiref(state, ffi::LUA_LOADLIBNAME, ffi::luaopen_package, 1)?;
3602 ffi::lua_pop(state, 1);
3603 }
3604 #[cfg(feature = "luau")]
3605 if libs.contains(StdLib::PACKAGE) {
3606 let lua: &Lua = mem::transmute((*extra_data(state)).inner.assume_init_ref());
3607 crate::luau::register_package_module(lua)?;
3608 }
3609
3610 #[cfg(feature = "luajit")]
3611 {
3612 if libs.contains(StdLib::JIT) {
3613 requiref(state, ffi::LUA_JITLIBNAME, ffi::luaopen_jit, 1)?;
3614 ffi::lua_pop(state, 1);
3615 }
3616
3617 if libs.contains(StdLib::FFI) {
3618 requiref(state, ffi::LUA_FFILIBNAME, ffi::luaopen_ffi, 1)?;
3619 ffi::lua_pop(state, 1);
3620 }
3621 }
3622
3623 Ok(())
3624}
3625
3626unsafe fn ref_stack_pop(extra: *mut ExtraData) -> c_int {
3627 let extra = &mut *extra;
3628 if let Some(free) = extra.ref_free.pop() {
3629 ffi::lua_replace(extra.ref_thread, free);
3630 return free;
3631 }
3632
3633 if extra.ref_stack_top >= extra.ref_stack_size {
3635 let mut inc = extra.ref_stack_size; while inc > 0 && ffi::lua_checkstack(extra.ref_thread, inc) == 0 {
3637 inc /= 2;
3638 }
3639 if inc == 0 {
3640 ffi::lua_pop(extra.ref_thread, 1);
3643 let top = extra.ref_stack_top;
3644 panic!(
3647 "cannot create a Lua reference, out of auxiliary stack space (used {top} slots)"
3648 );
3649 }
3650 extra.ref_stack_size += inc;
3651 }
3652 extra.ref_stack_top += 1;
3653 extra.ref_stack_top
3654}
3655
3656#[cfg(test)]
3657mod assertions {
3658 use super::*;
3659
3660 static_assertions::assert_not_impl_any!(Lua: std::panic::RefUnwindSafe);
3662
3663 #[cfg(not(feature = "send"))]
3664 static_assertions::assert_not_impl_any!(Lua: Send);
3665 #[cfg(feature = "send")]
3666 static_assertions::assert_impl_all!(Lua: Send);
3667}