1use std::any::{Any, TypeId};
2use std::cell::{Ref, RefCell, RefMut, UnsafeCell};
3use std::collections::HashMap;
4use std::ffi::{CStr, CString};
5use std::fmt;
6use std::marker::PhantomData;
7use std::mem::ManuallyDrop;
8use std::ops::{Deref, DerefMut};
9use std::os::raw::{c_char, c_int, c_void};
10use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe, Location};
11use std::ptr::NonNull;
12use std::sync::{Arc, Mutex};
13use std::{mem, ptr, str};
14
15use rustc_hash::FxHashMap;
16
17use crate::chunk::{AsChunk, Chunk, ChunkMode};
18use crate::error::{Error, Result};
19use crate::ffi;
20use crate::function::Function;
21use crate::hook::Debug;
22use crate::scope::Scope;
23use crate::stdlib::StdLib;
24use crate::string::String;
25use crate::table::Table;
26use crate::thread::Thread;
27use crate::types::{
28 Callback, CallbackUpvalue, DestructedUserdataMT, Integer, LightUserData, LuaRef, MaybeSend,
29 Number, RegistryKey,
30};
31use crate::userdata::{AnyUserData, UserData, UserDataCell};
32use crate::userdata_impl::{StaticUserDataFields, StaticUserDataMethods};
33use crate::util::{
34 self, assert_stack, callback_error, check_stack, 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, StackGuard, WrappedFailure,
38};
39use crate::value::{FromLua, FromLuaMulti, MultiValue, Nil, ToLua, ToLuaMulti, 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::{chunk::Compiler, types::VmState};
53
54#[cfg(feature = "async")]
55use {
56 crate::types::{AsyncCallback, AsyncCallbackUpvalue, AsyncPollUpvalue},
57 futures_core::{
58 future::{Future, LocalBoxFuture},
59 task::{Context, Poll, Waker},
60 },
61 futures_task::noop_waker,
62 futures_util::future::{self, TryFutureExt},
63};
64
65#[cfg(feature = "serialize")]
66use serde::Serialize;
67
68#[repr(transparent)]
70pub struct Lua(Arc<UnsafeCell<LuaInner>>);
71
72pub struct LuaInner {
74 pub(crate) state: *mut ffi::lua_State,
75 main_state: *mut ffi::lua_State,
76 extra: Arc<UnsafeCell<ExtraData>>,
77 safe: bool,
78 #[cfg(feature = "luau")]
79 compiler: Option<Compiler>,
80 _no_ref_unwind_safe: PhantomData<UnsafeCell<()>>,
82}
83
84pub(crate) struct ExtraData {
86 inner: Option<ManuallyDrop<Arc<UnsafeCell<LuaInner>>>>,
88
89 registered_userdata: FxHashMap<TypeId, c_int>,
90 registered_userdata_mt: FxHashMap<*const c_void, Option<TypeId>>,
91 registry_unref_list: Arc<Mutex<Option<Vec<c_int>>>>,
92
93 #[cfg(not(feature = "send"))]
94 app_data: RefCell<HashMap<TypeId, Box<dyn Any>>>,
95 #[cfg(feature = "send")]
96 app_data: RefCell<HashMap<TypeId, Box<dyn Any + Send>>>,
97
98 libs: StdLib,
99 mem_info: Option<NonNull<MemoryInfo>>,
100
101 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_failures_cache: Vec<c_int>,
108 multivalue_cache: Vec<MultiValue<'static>>,
110 #[cfg(feature = "async")]
112 recycled_thread_cache: Vec<c_int>,
113
114 #[cfg(feature = "async")]
116 ref_waker_idx: c_int,
117
118 #[cfg(not(feature = "luau"))]
119 hook_callback: Option<HookCallback>,
120 #[cfg(feature = "lua54")]
121 warn_callback: Option<WarnCallback>,
122 #[cfg(feature = "luau")]
123 interrupt_callback: Option<InterruptCallback>,
124
125 #[cfg(feature = "luau")]
126 sandboxed: bool,
127}
128
129#[cfg_attr(any(feature = "lua51", feature = "luajit"), allow(dead_code))]
130struct MemoryInfo {
131 used_memory: isize,
132 memory_limit: isize,
133}
134
135#[derive(Clone, Copy, Debug, PartialEq, Eq)]
144pub enum GCMode {
145 Incremental,
146 #[cfg(any(feature = "lua54"))]
148 #[cfg_attr(docsrs, doc(cfg(feature = "lua54")))]
149 Generational,
150}
151
152#[derive(Clone, Debug)]
154#[non_exhaustive]
155pub struct LuaOptions {
156 pub catch_rust_panics: bool,
169
170 #[cfg(feature = "async")]
179 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
180 pub thread_cache_size: usize,
181}
182
183impl Default for LuaOptions {
184 fn default() -> Self {
185 LuaOptions::new()
186 }
187}
188
189impl LuaOptions {
190 pub const fn new() -> Self {
192 LuaOptions {
193 catch_rust_panics: true,
194 #[cfg(feature = "async")]
195 thread_cache_size: 0,
196 }
197 }
198
199 #[must_use]
203 pub const fn catch_rust_panics(mut self, enabled: bool) -> Self {
204 self.catch_rust_panics = enabled;
205 self
206 }
207
208 #[cfg(feature = "async")]
212 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
213 #[must_use]
214 pub const fn thread_cache_size(mut self, size: usize) -> Self {
215 self.thread_cache_size = size;
216 self
217 }
218}
219
220#[cfg(feature = "async")]
221pub(crate) static ASYNC_POLL_PENDING: u8 = 0;
222pub(crate) static EXTRA_REGISTRY_KEY: u8 = 0;
223
224const WRAPPED_FAILURES_CACHE_SIZE: usize = 32;
225const MULTIVALUE_CACHE_SIZE: usize = 32;
226
227#[cfg(feature = "send")]
229#[cfg_attr(docsrs, doc(cfg(feature = "send")))]
230unsafe impl Send for Lua {}
231
232#[cfg(not(feature = "module"))]
233impl Drop for LuaInner {
234 fn drop(&mut self) {
235 unsafe {
236 let extra = &mut *self.extra.get();
237 let drain_iter = extra.wrapped_failures_cache.drain(..);
238 #[cfg(feature = "async")]
239 let drain_iter = drain_iter.chain(extra.recycled_thread_cache.drain(..));
240 for index in drain_iter {
241 ffi::lua_pushnil(extra.ref_thread);
242 ffi::lua_replace(extra.ref_thread, index);
243 extra.ref_free.push(index);
244 }
245 #[cfg(feature = "async")]
246 {
247 ffi::lua_pushnil(extra.ref_thread);
249 ffi::lua_replace(extra.ref_thread, extra.ref_waker_idx);
250 extra.ref_free.push(extra.ref_waker_idx);
251 }
252 #[cfg(feature = "luau")]
253 {
254 let callbacks = ffi::lua_callbacks(self.state);
255 let extra_ptr = (*callbacks).userdata as *mut Arc<UnsafeCell<ExtraData>>;
256 drop(Box::from_raw(extra_ptr));
257 (*callbacks).userdata = ptr::null_mut();
258 }
259 mlua_debug_assert!(
260 ffi::lua_gettop(extra.ref_thread) == extra.ref_stack_top
261 && extra.ref_stack_top as usize == extra.ref_free.len(),
262 "reference leak detected"
263 );
264 ffi::lua_close(self.main_state);
265 }
266 }
267}
268
269impl Drop for ExtraData {
270 fn drop(&mut self) {
271 #[cfg(feature = "module")]
272 unsafe {
273 ManuallyDrop::drop(&mut self.inner.take().unwrap())
274 };
275
276 *mlua_expect!(self.registry_unref_list.lock(), "unref list poisoned") = None;
277 if let Some(mem_info) = self.mem_info {
278 drop(unsafe { Box::from_raw(mem_info.as_ptr()) });
279 }
280 }
281}
282
283impl fmt::Debug for Lua {
284 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
285 write!(f, "Lua({:p})", self.state)
286 }
287}
288
289impl Deref for Lua {
290 type Target = LuaInner;
291
292 fn deref(&self) -> &Self::Target {
293 unsafe { &*(*self.0).get() }
294 }
295}
296
297impl DerefMut for Lua {
298 fn deref_mut(&mut self) -> &mut Self::Target {
299 unsafe { &mut *(*self.0).get() }
300 }
301}
302
303impl Lua {
304 #[allow(clippy::new_without_default)]
314 pub fn new() -> Lua {
315 mlua_expect!(
316 Self::new_with(StdLib::ALL_SAFE, LuaOptions::default()),
317 "can't create new safe Lua state"
318 )
319 }
320
321 pub unsafe fn unsafe_new() -> Lua {
326 Self::unsafe_new_with(StdLib::ALL, LuaOptions::default())
327 }
328
329 pub fn new_with(libs: StdLib, options: LuaOptions) -> Result<Lua> {
341 #[cfg(not(feature = "luau"))]
342 if libs.contains(StdLib::DEBUG) {
343 return Err(Error::SafetyError(
344 "the unsafe `debug` module can't be loaded using safe `new_with`".to_string(),
345 ));
346 }
347 #[cfg(feature = "luajit")]
348 {
349 if libs.contains(StdLib::FFI) {
350 return Err(Error::SafetyError(
351 "the unsafe `ffi` module can't be loaded using safe `new_with`".to_string(),
352 ));
353 }
354 }
355
356 let mut lua = unsafe { Self::inner_new(libs, options) };
357
358 #[cfg(not(feature = "luau"))]
359 if libs.contains(StdLib::PACKAGE) {
360 mlua_expect!(lua.disable_c_modules(), "Error during disabling C modules");
361 }
362 lua.safe = true;
363
364 Ok(lua)
365 }
366
367 pub unsafe fn unsafe_new_with(libs: StdLib, options: LuaOptions) -> Lua {
376 #[cfg(not(feature = "luau"))]
377 ffi::keep_lua_symbols();
378 Self::inner_new(libs, options)
379 }
380
381 unsafe fn inner_new(libs: StdLib, options: LuaOptions) -> Lua {
382 unsafe extern "C" fn allocator(
383 extra_data: *mut c_void,
384 ptr: *mut c_void,
385 osize: usize,
386 nsize: usize,
387 ) -> *mut c_void {
388 use std::alloc::{self, Layout};
389
390 let mem_info = &mut *(extra_data as *mut MemoryInfo);
391
392 if nsize == 0 {
393 if !ptr.is_null() {
395 let layout = Layout::from_size_align_unchecked(osize, ffi::SYS_MIN_ALIGN);
396 alloc::dealloc(ptr as *mut u8, layout);
397 mem_info.used_memory -= osize as isize;
398 }
399 return ptr::null_mut();
400 }
401
402 let mut mem_diff = nsize as isize;
404 if !ptr.is_null() {
405 mem_diff -= osize as isize;
406 }
407 let new_used_memory = mem_info.used_memory + mem_diff;
408 if mem_info.memory_limit > 0 && new_used_memory > mem_info.memory_limit {
409 return ptr::null_mut();
410 }
411
412 let new_layout = Layout::from_size_align_unchecked(nsize, ffi::SYS_MIN_ALIGN);
413 mem_info.used_memory += mem_diff;
414
415 if ptr.is_null() {
416 let new_ptr = alloc::alloc(new_layout) as *mut c_void;
418 if new_ptr.is_null() {
419 alloc::handle_alloc_error(new_layout);
420 }
421 return new_ptr;
422 }
423
424 let old_layout = Layout::from_size_align_unchecked(osize, ffi::SYS_MIN_ALIGN);
426 let new_ptr = alloc::realloc(ptr as *mut u8, old_layout, nsize) as *mut c_void;
427 if new_ptr.is_null() {
428 alloc::handle_alloc_error(new_layout);
429 }
430 new_ptr
431 }
432
433 let mem_info = Box::into_raw(Box::new(MemoryInfo {
434 used_memory: 0,
435 memory_limit: 0,
436 }));
437
438 let state = ffi::lua_newstate(allocator, mem_info as *mut c_void);
439
440 ffi::luaL_requiref(state, cstr!("_G"), ffi::luaopen_base, 1);
441 ffi::lua_pop(state, 1);
442
443 let lua = Lua::init_from_ptr(state);
444 let extra = &mut *lua.extra.get();
445 extra.mem_info = NonNull::new(mem_info);
446
447 mlua_expect!(
448 load_from_std_lib(state, libs),
449 "Error during loading standard libraries"
450 );
451 extra.libs |= libs;
452
453 if !options.catch_rust_panics {
454 mlua_expect!(
455 (|| -> Result<()> {
456 let _sg = StackGuard::new(lua.state);
457
458 #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "lua-factorio"))]
459 ffi::lua_rawgeti(lua.state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS);
460 #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
461 ffi::lua_pushvalue(lua.state, ffi::LUA_GLOBALSINDEX);
462
463 ffi::lua_pushcfunction(lua.state, safe_pcall);
464 rawset_field(lua.state, -2, "pcall")?;
465
466 ffi::lua_pushcfunction(lua.state, safe_xpcall);
467 rawset_field(lua.state, -2, "xpcall")?;
468
469 Ok(())
470 })(),
471 "Error during applying option `catch_rust_panics`"
472 )
473 }
474
475 #[cfg(feature = "async")]
476 if options.thread_cache_size > 0 {
477 extra.recycled_thread_cache = Vec::with_capacity(options.thread_cache_size);
478 }
479
480 #[cfg(feature = "luau")]
481 mlua_expect!(lua.prepare_luau_state(), "Error preparing Luau state");
482
483 lua
484 }
485
486 #[allow(clippy::missing_safety_doc)]
491 pub unsafe fn init_from_ptr(state: *mut ffi::lua_State) -> Lua {
492 let main_state = get_main_state(state).unwrap_or(state);
493 let main_state_top = ffi::lua_gettop(main_state);
494
495 if let Some(lua) = Lua::make_from_ptr(state) {
496 return lua;
497 }
498
499 mlua_expect!(
500 (|state| {
501 init_error_registry(state)?;
502
503 init_gc_metatable::<Arc<UnsafeCell<ExtraData>>>(state, None)?;
507 init_gc_metatable::<Callback>(state, None)?;
508 init_gc_metatable::<CallbackUpvalue>(state, None)?;
509 #[cfg(feature = "async")]
510 {
511 init_gc_metatable::<AsyncCallback>(state, None)?;
512 init_gc_metatable::<AsyncCallbackUpvalue>(state, None)?;
513 init_gc_metatable::<AsyncPollUpvalue>(state, None)?;
514 init_gc_metatable::<Option<Waker>>(state, None)?;
515 }
516
517 #[cfg(feature = "serialize")]
519 crate::serde::init_metatables(state)?;
520
521 Ok::<_, Error>(())
522 })(main_state),
523 "Error during Lua construction",
524 );
525
526 let ref_thread = mlua_expect!(
529 protect_lua!(state, 0, 0, |state| {
530 let thread = ffi::lua_newthread(state);
531 ffi::luaL_ref(state, ffi::LUA_REGISTRYINDEX);
532 thread
533 }),
534 "Error while creating ref thread",
535 );
536
537 #[cfg(feature = "async")]
539 let ref_waker_idx = {
540 mlua_expect!(
541 push_gc_userdata::<Option<Waker>>(ref_thread, None, true),
542 "Error while creating Waker slot"
543 );
544 ffi::lua_gettop(ref_thread)
545 };
546 let ref_stack_top = ffi::lua_gettop(ref_thread);
547
548 let extra = Arc::new(UnsafeCell::new(ExtraData {
551 inner: None,
552 registered_userdata: FxHashMap::default(),
553 registered_userdata_mt: FxHashMap::default(),
554 registry_unref_list: Arc::new(Mutex::new(Some(Vec::new()))),
555 app_data: RefCell::new(HashMap::new()),
556 ref_thread,
557 libs: StdLib::NONE,
558 mem_info: None,
559 ref_stack_size: ffi::LUA_MINSTACK - 1,
561 ref_stack_top,
562 ref_free: Vec::new(),
563 wrapped_failures_cache: Vec::with_capacity(WRAPPED_FAILURES_CACHE_SIZE),
564 multivalue_cache: Vec::with_capacity(MULTIVALUE_CACHE_SIZE),
565 #[cfg(feature = "async")]
566 recycled_thread_cache: Vec::new(),
567 #[cfg(feature = "async")]
568 ref_waker_idx,
569 #[cfg(not(feature = "luau"))]
570 hook_callback: None,
571 #[cfg(feature = "lua54")]
572 warn_callback: None,
573 #[cfg(feature = "luau")]
574 interrupt_callback: None,
575 #[cfg(feature = "luau")]
576 sandboxed: false,
577 }));
578
579 mlua_expect!(
580 (|state| {
581 push_gc_userdata(state, Arc::clone(&extra), true)?;
582 protect_lua!(state, 1, 0, fn(state) {
583 let extra_key = &EXTRA_REGISTRY_KEY as *const u8 as *const c_void;
584 ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, extra_key);
585 })
586 })(main_state),
587 "Error while storing extra data",
588 );
589
590 get_destructed_userdata_metatable(main_state);
592 let destructed_mt_ptr = ffi::lua_topointer(main_state, -1);
593 let destructed_mt_typeid = Some(TypeId::of::<DestructedUserdataMT>());
594 (*extra.get())
595 .registered_userdata_mt
596 .insert(destructed_mt_ptr, destructed_mt_typeid);
597 ffi::lua_pop(main_state, 1);
598
599 mlua_debug_assert!(
600 ffi::lua_gettop(main_state) == main_state_top,
601 "stack leak during creation"
602 );
603 assert_stack(main_state, ffi::LUA_MINSTACK);
604
605 #[cfg(feature = "luau")]
608 {
609 let extra_raw = Box::into_raw(Box::new(Arc::clone(&extra)));
610 (*ffi::lua_callbacks(main_state)).userdata = extra_raw as *mut c_void;
611 }
612
613 let inner = Arc::new(UnsafeCell::new(LuaInner {
614 state,
615 main_state,
616 extra: Arc::clone(&extra),
617 safe: false,
618 #[cfg(feature = "luau")]
619 compiler: None,
620 _no_ref_unwind_safe: PhantomData,
621 }));
622
623 (*extra.get()).inner = Some(ManuallyDrop::new(Arc::clone(&inner)));
624 #[cfg(not(feature = "module"))]
625 Arc::decrement_strong_count(Arc::as_ptr(&inner));
626
627 Lua(inner)
628 }
629
630 pub fn load_from_std_lib(&self, libs: StdLib) -> Result<()> {
636 #[cfg(not(feature = "luau"))]
637 if self.safe && libs.contains(StdLib::DEBUG) {
638 return Err(Error::SafetyError(
639 "the unsafe `debug` module can't be loaded in safe mode".to_string(),
640 ));
641 }
642 #[cfg(feature = "luajit")]
643 {
644 if self.safe && libs.contains(StdLib::FFI) {
645 return Err(Error::SafetyError(
646 "the unsafe `ffi` module can't be loaded in safe mode".to_string(),
647 ));
648 }
649 }
650
651 let res = unsafe { load_from_std_lib(self.main_state, libs) };
652
653 let extra = unsafe { &mut *self.extra.get() };
655 #[cfg(not(feature = "luau"))]
656 {
657 let curr_libs = extra.libs;
658 if self.safe && (curr_libs ^ (curr_libs | libs)).contains(StdLib::PACKAGE) {
659 mlua_expect!(self.disable_c_modules(), "Error during disabling C modules");
660 }
661 }
662 extra.libs |= libs;
663
664 res
665 }
666
667 pub fn load_from_function<'lua, S, T>(
683 &'lua self,
684 modname: &S,
685 func: Function<'lua>,
686 ) -> Result<T>
687 where
688 S: AsRef<[u8]> + ?Sized,
689 T: FromLua<'lua>,
690 {
691 let loaded = unsafe {
692 let _sg = StackGuard::new(self.state);
693 check_stack(self.state, 2)?;
694 protect_lua!(self.state, 0, 1, fn(state) {
695 ffi::luaL_getsubtable(state, ffi::LUA_REGISTRYINDEX, cstr!("_LOADED"));
696 })?;
697 Table(self.pop_ref())
698 };
699
700 let modname = self.create_string(modname)?;
701 let value = match loaded.raw_get(modname.clone())? {
702 Value::Nil => {
703 let result = match func.call(modname.clone())? {
704 Value::Nil => Value::Boolean(true),
705 res => res,
706 };
707 loaded.raw_set(modname, result.clone())?;
708 result
709 }
710 res => res,
711 };
712 T::from_lua(value, self)
713 }
714
715 pub fn unload<S>(&self, modname: &S) -> Result<()>
723 where
724 S: AsRef<[u8]> + ?Sized,
725 {
726 let loaded = unsafe {
727 let _sg = StackGuard::new(self.state);
728 check_stack(self.state, 2)?;
729 protect_lua!(self.state, 0, 1, fn(state) {
730 ffi::luaL_getsubtable(state, ffi::LUA_REGISTRYINDEX, cstr!("_LOADED"));
731 })?;
732 Table(self.pop_ref())
733 };
734
735 let modname = self.create_string(modname)?;
736 loaded.raw_remove(modname)?;
737 Ok(())
738 }
739
740 #[doc(hidden)]
753 pub fn into_static(self) -> &'static Self {
754 Box::leak(Box::new(self))
755 }
756
757 #[doc(hidden)]
762 pub unsafe fn from_static(lua: &'static Lua) -> Self {
763 *Box::from_raw(lua as *const Lua as *mut Lua)
764 }
765
766 #[doc(hidden)]
769 #[cfg(not(tarpaulin_include))]
770 pub unsafe fn entrypoint<'lua, A, R, F>(self, func: F) -> Result<c_int>
771 where
772 A: FromLuaMulti<'lua>,
773 R: ToLua<'lua>,
774 F: 'static + MaybeSend + Fn(&'lua Lua, A) -> Result<R>,
775 {
776 let entrypoint_inner = |lua: &'lua Lua, func: F| {
777 let nargs = ffi::lua_gettop(lua.state);
778 check_stack(lua.state, 3)?;
779
780 let mut args = MultiValue::new();
781 args.reserve(nargs as usize);
782 for _ in 0..nargs {
783 args.push_front(lua.pop_value());
784 }
785
786 let callback = lua.create_callback(Box::new(move |lua, args| {
789 func(lua, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
790 }))?;
791 callback.call(args)
792 };
793
794 match entrypoint_inner(mem::transmute(&self), func) {
795 Ok(res) => {
796 self.push_value(res)?;
797 Ok(1)
798 }
799 Err(err) => {
800 self.push_value(Value::Error(err))?;
801 let state = self.state;
802 drop(self);
804 ffi::lua_error(state)
805 }
806 }
807 }
808
809 #[doc(hidden)]
811 #[cfg(not(tarpaulin_include))]
812 pub unsafe fn entrypoint1<'lua, R, F>(self, func: F) -> Result<c_int>
813 where
814 R: ToLua<'lua>,
815 F: 'static + MaybeSend + Fn(&'lua Lua) -> Result<R>,
816 {
817 self.entrypoint(move |lua, _: ()| func(lua))
818 }
819
820 #[cfg(any(feature = "luau", docsrs))]
849 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
850 pub fn sandbox(&self, enabled: bool) -> Result<()> {
851 unsafe {
852 let extra = &mut *self.extra.get();
853 if extra.sandboxed != enabled {
854 let state = self.main_state;
855 check_stack(state, 3)?;
856 protect_lua!(state, 0, 0, |state| {
857 if enabled {
858 ffi::luaL_sandbox(state, 1);
859 ffi::luaL_sandboxthread(state);
860 } else {
861 self.ref_thread_exec(|ref_thread| {
863 ffi::lua_xpush(ref_thread, state, ffi::LUA_GLOBALSINDEX);
864 ffi::lua_replace(state, ffi::LUA_GLOBALSINDEX);
865 });
866 ffi::luaL_sandbox(state, 0);
867 }
868 })?;
869 extra.sandboxed = enabled;
870 }
871 Ok(())
872 }
873 }
874
875 #[cfg(not(feature = "luau"))]
909 #[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
910 pub fn set_hook<F>(&self, triggers: HookTriggers, callback: F) -> Result<()>
911 where
912 F: 'static + MaybeSend + Fn(&Lua, Debug) -> Result<()>,
913 {
914 unsafe extern "C" fn hook_proc(state: *mut ffi::lua_State, ar: *mut ffi::lua_Debug) {
915 let lua = match Lua::make_from_ptr(state) {
916 Some(lua) => lua,
917 None => return,
918 };
919 let extra = lua.extra.get();
920 callback_error_ext(state, extra, move |_| {
921 let debug = Debug::new(&lua, ar);
922 let hook_cb = (*lua.extra.get()).hook_callback.clone();
923 let hook_cb = mlua_expect!(hook_cb, "no hook callback set in hook_proc");
924 if Arc::strong_count(&hook_cb) > 2 {
925 return Ok(()); }
927 hook_cb(&lua, debug)
928 })
929 }
930
931 unsafe {
932 let state = get_main_state(self.main_state).ok_or(Error::MainThreadNotAvailable)?;
933 (*self.extra.get()).hook_callback = Some(Arc::new(callback));
934 ffi::lua_sethook(state, Some(hook_proc), triggers.mask(), triggers.count());
935 }
936 Ok(())
937 }
938
939 #[cfg(not(feature = "luau"))]
943 #[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
944 pub fn remove_hook(&self) {
945 unsafe {
946 let state = match get_main_state(self.main_state) {
948 Some(state) => state,
949 None => return,
950 };
951 (*self.extra.get()).hook_callback = None;
952 ffi::lua_sethook(state, None, 0, 0);
953 }
954 }
955
956 #[cfg(any(feature = "luau", docsrs))]
999 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
1000 pub fn set_interrupt<F>(&self, callback: F)
1001 where
1002 F: 'static + MaybeSend + Fn() -> Result<VmState>,
1003 {
1004 unsafe extern "C" fn interrupt_proc(state: *mut ffi::lua_State, gc: c_int) {
1005 if gc >= 0 {
1006 return;
1008 }
1009 let extra = match extra_data(state) {
1010 Some(e) => e.get(),
1011 None => return,
1012 };
1013 let result = callback_error_ext(state, extra, move |_| {
1014 let interrupt_cb = (*extra).interrupt_callback.clone();
1015 let interrupt_cb =
1016 mlua_expect!(interrupt_cb, "no interrupt callback set in interrupt_proc");
1017 if Arc::strong_count(&interrupt_cb) > 2 {
1018 return Ok(VmState::Continue); }
1020 interrupt_cb()
1021 });
1022 match result {
1023 VmState::Continue => {}
1024 VmState::Yield => {
1025 ffi::lua_yield(state, 0);
1026 }
1027 }
1028 }
1029
1030 unsafe {
1031 (*self.extra.get()).interrupt_callback = Some(Arc::new(callback));
1032 (*ffi::lua_callbacks(self.main_state)).interrupt = Some(interrupt_proc);
1033 }
1034 }
1035
1036 #[cfg(any(feature = "luau", docsrs))]
1040 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
1041 pub fn remove_interrupt(&self) {
1042 unsafe {
1043 (*self.extra.get()).interrupt_callback = None;
1044 (*ffi::lua_callbacks(self.main_state)).interrupt = None;
1045 }
1046 }
1047
1048 #[cfg(feature = "lua54")]
1052 #[cfg_attr(docsrs, doc(cfg(feature = "lua54")))]
1053 pub fn set_warning_function<F>(&self, callback: F)
1054 where
1055 F: 'static + MaybeSend + Fn(&Lua, &CStr, bool) -> Result<()>,
1056 {
1057 unsafe extern "C" fn warn_proc(ud: *mut c_void, msg: *const c_char, tocont: c_int) {
1058 let state = ud as *mut ffi::lua_State;
1059 let lua = match Lua::make_from_ptr(state) {
1060 Some(lua) => lua,
1061 None => return,
1062 };
1063 let extra = lua.extra.get();
1064 callback_error_ext(state, extra, move |_| {
1065 let cb = mlua_expect!(
1066 (*lua.extra.get()).warn_callback.as_ref(),
1067 "no warning callback set in warn_proc"
1068 );
1069 let msg = CStr::from_ptr(msg);
1070 cb(&lua, msg, tocont != 0)
1071 });
1072 }
1073
1074 let state = self.main_state;
1075 unsafe {
1076 (*self.extra.get()).warn_callback = Some(Box::new(callback));
1077 ffi::lua_setwarnf(state, Some(warn_proc), state as *mut c_void);
1078 }
1079 }
1080
1081 #[cfg(feature = "lua54")]
1087 #[cfg_attr(docsrs, doc(cfg(feature = "lua54")))]
1088 pub fn remove_warning_function(&self) {
1089 unsafe {
1090 (*self.extra.get()).warn_callback = None;
1091 ffi::lua_setwarnf(self.main_state, None, ptr::null_mut());
1092 }
1093 }
1094
1095 #[cfg(feature = "lua54")]
1101 #[cfg_attr(docsrs, doc(cfg(feature = "lua54")))]
1102 pub fn warning<S: Into<Vec<u8>>>(&self, msg: S, tocont: bool) -> Result<()> {
1103 let msg = CString::new(msg).map_err(|err| Error::RuntimeError(err.to_string()))?;
1104 unsafe { ffi::lua_warning(self.state, msg.as_ptr(), if tocont { 1 } else { 0 }) };
1105 Ok(())
1106 }
1107
1108 pub fn inspect_stack(&self, level: usize) -> Option<Debug> {
1116 unsafe {
1117 let mut ar: ffi::lua_Debug = mem::zeroed();
1118 let level = level as c_int;
1119 #[cfg(not(feature = "luau"))]
1120 if ffi::lua_getstack(self.state, level, &mut ar) == 0 {
1121 return None;
1122 }
1123 #[cfg(feature = "luau")]
1124 if ffi::lua_getinfo(self.state, level, cstr!(""), &mut ar) == 0 {
1125 return None;
1126 }
1127 Some(Debug::new_owned(self, level, ar))
1128 }
1129 }
1130
1131 pub fn used_memory(&self) -> usize {
1133 unsafe {
1134 match (*self.extra.get()).mem_info.map(|x| x.as_ref()) {
1135 Some(mem_info) => mem_info.used_memory as usize,
1136 None => {
1137 let used_kbytes = ffi::lua_gc(self.main_state, ffi::LUA_GCCOUNT, 0);
1139 let used_kbytes_rem = ffi::lua_gc(self.main_state, ffi::LUA_GCCOUNTB, 0);
1140 (used_kbytes as usize) * 1024 + (used_kbytes_rem as usize)
1141 }
1142 }
1143 }
1144 }
1145
1146 #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "lua-factorio"))]
1156 pub fn set_memory_limit(&self, memory_limit: usize) -> Result<usize> {
1157 unsafe {
1158 match (*self.extra.get()).mem_info.map(|mut x| x.as_mut()) {
1159 Some(mem_info) => {
1160 let prev_limit = mem_info.memory_limit as usize;
1161 mem_info.memory_limit = memory_limit as isize;
1162 Ok(prev_limit)
1163 }
1164 None => Err(Error::MemoryLimitNotAvailable),
1165 }
1166 }
1167 }
1168
1169 #[cfg(any(
1173 feature = "lua54",
1174 feature = "lua53",
1175 feature = "lua52",
1176 feature = "luau",
1177 feature = "lua-factorio"
1178 ))]
1179 pub fn gc_is_running(&self) -> bool {
1180 unsafe { ffi::lua_gc(self.main_state, ffi::LUA_GCISRUNNING, 0) != 0 }
1181 }
1182
1183 pub fn gc_stop(&self) {
1185 unsafe { ffi::lua_gc(self.main_state, ffi::LUA_GCSTOP, 0) };
1186 }
1187
1188 pub fn gc_restart(&self) {
1190 unsafe { ffi::lua_gc(self.main_state, ffi::LUA_GCRESTART, 0) };
1191 }
1192
1193 pub fn gc_collect(&self) -> Result<()> {
1198 unsafe {
1199 check_stack(self.main_state, 2)?;
1200 protect_lua!(self.main_state, 0, 0, fn(state) ffi::lua_gc(state, ffi::LUA_GCCOLLECT, 0))
1201 }
1202 }
1203
1204 pub fn gc_step(&self) -> Result<bool> {
1208 self.gc_step_kbytes(0)
1209 }
1210
1211 pub fn gc_step_kbytes(&self, kbytes: c_int) -> Result<bool> {
1216 unsafe {
1217 check_stack(self.main_state, 3)?;
1218 protect_lua!(self.main_state, 0, 0, |state| {
1219 ffi::lua_gc(state, ffi::LUA_GCSTEP, kbytes) != 0
1220 })
1221 }
1222 }
1223
1224 pub fn gc_set_pause(&self, pause: c_int) -> c_int {
1233 unsafe {
1234 #[cfg(not(feature = "luau"))]
1235 return ffi::lua_gc(self.main_state, ffi::LUA_GCSETPAUSE, pause);
1236 #[cfg(feature = "luau")]
1237 return ffi::lua_gc(self.main_state, ffi::LUA_GCSETGOAL, pause);
1238 }
1239 }
1240
1241 pub fn gc_set_step_multiplier(&self, step_multiplier: c_int) -> c_int {
1248 unsafe { ffi::lua_gc(self.main_state, ffi::LUA_GCSETSTEPMUL, step_multiplier) }
1249 }
1250
1251 pub fn gc_inc(&self, pause: c_int, step_multiplier: c_int, step_size: c_int) -> GCMode {
1258 let state = self.main_state;
1259
1260 #[cfg(any(
1261 feature = "lua53",
1262 feature = "lua52",
1263 feature = "lua-factorio",
1264 feature = "lua51",
1265 feature = "luajit",
1266 feature = "luau"
1267 ))]
1268 unsafe {
1269 if pause > 0 {
1270 #[cfg(not(feature = "luau"))]
1271 ffi::lua_gc(state, ffi::LUA_GCSETPAUSE, pause);
1272 #[cfg(feature = "luau")]
1273 ffi::lua_gc(state, ffi::LUA_GCSETGOAL, pause);
1274 }
1275
1276 if step_multiplier > 0 {
1277 ffi::lua_gc(state, ffi::LUA_GCSETSTEPMUL, step_multiplier);
1278 }
1279
1280 #[cfg(feature = "luau")]
1281 if step_size > 0 {
1282 ffi::lua_gc(state, ffi::LUA_GCSETSTEPSIZE, step_size);
1283 }
1284 #[cfg(not(feature = "luau"))]
1285 let _ = step_size; GCMode::Incremental
1288 }
1289
1290 #[cfg(feature = "lua54")]
1291 let prev_mode =
1292 unsafe { ffi::lua_gc(state, ffi::LUA_GCINC, pause, step_multiplier, step_size) };
1293 #[cfg(feature = "lua54")]
1294 match prev_mode {
1295 ffi::LUA_GCINC => GCMode::Incremental,
1296 ffi::LUA_GCGEN => GCMode::Generational,
1297 _ => unreachable!(),
1298 }
1299 }
1300
1301 #[cfg(any(feature = "lua54"))]
1310 #[cfg_attr(docsrs, doc(cfg(feature = "lua54")))]
1311 pub fn gc_gen(&self, minor_multiplier: c_int, major_multiplier: c_int) -> GCMode {
1312 let state = self.main_state;
1313 let prev_mode =
1314 unsafe { ffi::lua_gc(state, ffi::LUA_GCGEN, minor_multiplier, major_multiplier) };
1315 match prev_mode {
1316 ffi::LUA_GCGEN => GCMode::Generational,
1317 ffi::LUA_GCINC => GCMode::Incremental,
1318 _ => unreachable!(),
1319 }
1320 }
1321
1322 #[cfg(any(feature = "luau", doc))]
1331 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
1332 pub fn set_compiler(&self, compiler: Compiler) {
1333 unsafe { (*self.0.get()).compiler = Some(compiler) };
1334 }
1335
1336 #[track_caller]
1344 pub fn load<'lua, 'a, S>(&'lua self, chunk: &'a S) -> Chunk<'lua, 'a>
1345 where
1346 S: AsChunk<'lua> + ?Sized,
1347 {
1348 let name = chunk
1349 .name()
1350 .unwrap_or_else(|| Location::caller().to_string());
1351
1352 Chunk {
1353 lua: self,
1354 source: chunk.source(),
1355 name: Some(name),
1356 env: chunk.env(self),
1357 mode: chunk.mode(),
1358 #[cfg(feature = "luau")]
1359 compiler: self.compiler.clone(),
1360 }
1361 }
1362
1363 pub(crate) fn load_chunk<'lua>(
1364 &'lua self,
1365 source: &[u8],
1366 name: Option<&CStr>,
1367 env: Option<Value<'lua>>,
1368 mode: Option<ChunkMode>,
1369 ) -> Result<Function<'lua>> {
1370 unsafe {
1371 let _sg = StackGuard::new(self.state);
1372 check_stack(self.state, 1)?;
1373
1374 let mode_str = match mode {
1375 Some(ChunkMode::Binary) => cstr!("b"),
1376 Some(ChunkMode::Text) => cstr!("t"),
1377 None => cstr!("bt"),
1378 };
1379
1380 match ffi::luaL_loadbufferx(
1381 self.state,
1382 source.as_ptr() as *const c_char,
1383 source.len(),
1384 name.map(|n| n.as_ptr()).unwrap_or_else(ptr::null),
1385 mode_str,
1386 ) {
1387 ffi::LUA_OK => {
1388 if let Some(env) = env {
1389 self.push_value(env)?;
1390 #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "lua-factorio"))]
1391 ffi::lua_setupvalue(self.state, -2, 1);
1392 #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
1393 ffi::lua_setfenv(self.state, -2);
1394 }
1395 Ok(Function(self.pop_ref()))
1396 }
1397 err => Err(pop_error(self.state, err)),
1398 }
1399 }
1400 }
1401
1402 pub fn create_string<S>(&self, s: &S) -> Result<String>
1406 where
1407 S: AsRef<[u8]> + ?Sized,
1408 {
1409 unsafe {
1410 let _sg = StackGuard::new(self.state);
1411 check_stack(self.state, 3)?;
1412
1413 let protect = !self.unlikely_memory_error();
1414 push_string(self.state, s, protect)?;
1415 Ok(String(self.pop_ref()))
1416 }
1417 }
1418
1419 pub fn create_table(&self) -> Result<Table> {
1421 self.create_table_with_capacity(0, 0)
1422 }
1423
1424 pub fn create_table_with_capacity(&self, narr: c_int, nrec: c_int) -> Result<Table> {
1429 unsafe {
1430 let _sg = StackGuard::new(self.state);
1431 check_stack(self.state, 3)?;
1432
1433 let protect = !self.unlikely_memory_error();
1434 push_table(self.state, narr, nrec, protect)?;
1435 Ok(Table(self.pop_ref()))
1436 }
1437 }
1438
1439 pub fn create_table_from<'lua, K, V, I>(&'lua self, iter: I) -> Result<Table<'lua>>
1441 where
1442 K: ToLua<'lua>,
1443 V: ToLua<'lua>,
1444 I: IntoIterator<Item = (K, V)>,
1445 {
1446 unsafe {
1447 let _sg = StackGuard::new(self.state);
1448 check_stack(self.state, 6)?;
1449
1450 let iter = iter.into_iter();
1451 let lower_bound = iter.size_hint().0;
1452 let protect = !self.unlikely_memory_error();
1453 push_table(self.state, 0, lower_bound as c_int, protect)?;
1454 for (k, v) in iter {
1455 self.push_value(k.to_lua(self)?)?;
1456 self.push_value(v.to_lua(self)?)?;
1457 if protect {
1458 protect_lua!(self.state, 3, 1, fn(state) ffi::lua_rawset(state, -3))?;
1459 } else {
1460 ffi::lua_rawset(self.state, -3);
1461 }
1462 }
1463
1464 Ok(Table(self.pop_ref()))
1465 }
1466 }
1467
1468 pub fn create_sequence_from<'lua, T, I>(&'lua self, iter: I) -> Result<Table<'lua>>
1470 where
1471 T: ToLua<'lua>,
1472 I: IntoIterator<Item = T>,
1473 {
1474 unsafe {
1475 let _sg = StackGuard::new(self.state);
1476 check_stack(self.state, 5)?;
1477
1478 let iter = iter.into_iter();
1479 let lower_bound = iter.size_hint().0;
1480 let protect = !self.unlikely_memory_error();
1481 push_table(self.state, lower_bound as c_int, 0, protect)?;
1482 for (i, v) in iter.enumerate() {
1483 self.push_value(v.to_lua(self)?)?;
1484 if protect {
1485 protect_lua!(self.state, 2, 1, |state| {
1486 ffi::lua_rawseti(state, -2, (i + 1) as Integer);
1487 })?;
1488 } else {
1489 ffi::lua_rawseti(self.state, -2, (i + 1) as Integer);
1490 }
1491 }
1492
1493 Ok(Table(self.pop_ref()))
1494 }
1495 }
1496
1497 pub fn create_function<'lua, A, R, F>(&'lua self, func: F) -> Result<Function<'lua>>
1543 where
1544 A: FromLuaMulti<'lua>,
1545 R: ToLuaMulti<'lua>,
1546 F: 'static + MaybeSend + Fn(&'lua Lua, A) -> Result<R>,
1547 {
1548 self.create_callback(Box::new(move |lua, args| {
1549 func(lua, A::from_lua_multi(args, lua)?)?.to_lua_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: ToLuaMulti<'lua>,
1563 F: 'static + MaybeSend + FnMut(&'lua Lua, A) -> Result<R>,
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 check_stack(self.state, 1)?;
1579 ffi::lua_pushcfunction(self.state, func);
1580 Ok(Function(self.pop_ref()))
1581 }
1582
1583 #[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: ToLuaMulti<'lua>,
1629 F: 'static + MaybeSend + Fn(&'lua Lua, A) -> FR,
1630 FR: 'lua + Future<Output = Result<R>>,
1631 {
1632 self.create_async_callback(Box::new(move |lua, args| {
1633 let args = match A::from_lua_multi(args, lua) {
1634 Ok(args) => args,
1635 Err(e) => return Box::pin(future::err(e)),
1636 };
1637 Box::pin(func(lua, args).and_then(move |ret| future::ready(ret.to_lua_multi(lua))))
1638 }))
1639 }
1640
1641 pub fn create_thread<'lua>(&'lua self, func: Function<'lua>) -> Result<Thread<'lua>> {
1645 unsafe {
1646 let _sg = StackGuard::new(self.state);
1647 check_stack(self.state, 3)?;
1648
1649 let thread_state = if self.unlikely_memory_error() {
1650 ffi::lua_newthread(self.state)
1651 } else {
1652 protect_lua!(self.state, 0, 1, |state| ffi::lua_newthread(state))?
1653 };
1654 self.push_ref(&func.0);
1655 ffi::lua_xmove(self.state, thread_state, 1);
1656
1657 Ok(Thread(self.pop_ref()))
1658 }
1659 }
1660
1661 #[cfg(feature = "async")]
1663 pub(crate) fn create_recycled_thread<'lua>(
1664 &'lua self,
1665 func: Function<'lua>,
1666 ) -> Result<Thread<'lua>> {
1667 #[cfg(any(
1668 feature = "lua54",
1669 all(feature = "luajit", feature = "vendored"),
1670 feature = "luau",
1671 ))]
1672 unsafe {
1673 let _sg = StackGuard::new(self.state);
1674 check_stack(self.state, 1)?;
1675
1676 let extra = &mut *self.extra.get();
1677 if let Some(index) = extra.recycled_thread_cache.pop() {
1678 let thread_state = ffi::lua_tothread(extra.ref_thread, index);
1679 self.push_ref(&func.0);
1680 ffi::lua_xmove(self.state, thread_state, 1);
1681
1682 #[cfg(feature = "luau")]
1683 {
1684 ffi::lua_xpush(self.state, thread_state, ffi::LUA_GLOBALSINDEX);
1686 ffi::lua_replace(thread_state, ffi::LUA_GLOBALSINDEX);
1687 }
1688
1689 return Ok(Thread(LuaRef { lua: self, index }));
1690 }
1691 };
1692 self.create_thread(func)
1693 }
1694
1695 #[cfg(feature = "async")]
1697 #[cfg(any(
1698 feature = "lua54",
1699 all(feature = "luajit", feature = "vendored"),
1700 feature = "luau",
1701 ))]
1702 pub(crate) unsafe fn recycle_thread(&self, thread: &mut Thread) {
1703 let extra = &mut *self.extra.get();
1704 let thread_state = ffi::lua_tothread(extra.ref_thread, thread.0.index);
1705 if extra.recycled_thread_cache.len() < extra.recycled_thread_cache.capacity() {
1706 #[cfg(feature = "lua54")]
1707 let status = ffi::lua_resetthread(thread_state);
1708 #[cfg(feature = "lua54")]
1709 if status != ffi::LUA_OK {
1710 return;
1711 }
1712 #[cfg(all(feature = "luajit", feature = "vendored"))]
1713 ffi::lua_resetthread(self.state, thread_state);
1714 #[cfg(feature = "luau")]
1715 ffi::lua_resetthread(thread_state);
1716 extra.recycled_thread_cache.push(thread.0.index);
1717 thread.0.index = 0;
1718 }
1719 }
1720
1721 pub fn create_userdata<T>(&self, data: T) -> Result<AnyUserData>
1723 where
1724 T: 'static + MaybeSend + UserData,
1725 {
1726 unsafe { self.make_userdata(UserDataCell::new(data)) }
1727 }
1728
1729 #[cfg(feature = "serialize")]
1733 #[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
1734 pub fn create_ser_userdata<T>(&self, data: T) -> Result<AnyUserData>
1735 where
1736 T: 'static + MaybeSend + UserData + Serialize,
1737 {
1738 unsafe { self.make_userdata(UserDataCell::new_ser(data)) }
1739 }
1740
1741 pub fn globals(&self) -> Table {
1743 unsafe {
1744 let _sg = StackGuard::new(self.state);
1745 assert_stack(self.state, 1);
1746 #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "lua-factorio"))]
1747 ffi::lua_rawgeti(self.state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS);
1748 #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
1749 ffi::lua_pushvalue(self.state, ffi::LUA_GLOBALSINDEX);
1750 Table(self.pop_ref())
1751 }
1752 }
1753
1754 pub fn current_thread(&self) -> Thread {
1757 unsafe {
1758 let _sg = StackGuard::new(self.state);
1759 assert_stack(self.state, 1);
1760 ffi::lua_pushthread(self.state);
1761 Thread(self.pop_ref())
1762 }
1763 }
1764
1765 pub fn scope<'lua, 'scope, R, F>(&'lua self, f: F) -> Result<R>
1786 where
1787 'lua: 'scope,
1788 R: 'static,
1789 F: FnOnce(&Scope<'lua, 'scope>) -> Result<R>,
1790 {
1791 f(&Scope::new(self))
1792 }
1793
1794 #[cfg(feature = "async")]
1801 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
1802 pub fn async_scope<'lua, 'scope, R, F, FR>(
1803 &'lua self,
1804 f: F,
1805 ) -> LocalBoxFuture<'scope, Result<R>>
1806 where
1807 'lua: 'scope,
1808 R: 'static,
1809 F: FnOnce(Scope<'lua, 'scope>) -> FR,
1810 FR: 'scope + Future<Output = Result<R>>,
1811 {
1812 Box::pin(f(Scope::new(self)))
1813 }
1814
1815 pub fn coerce_string<'lua>(&'lua self, v: Value<'lua>) -> Result<Option<String<'lua>>> {
1821 Ok(match v {
1822 Value::String(s) => Some(s),
1823 v => unsafe {
1824 let _sg = StackGuard::new(self.state);
1825 check_stack(self.state, 4)?;
1826
1827 self.push_value(v)?;
1828 let res = if self.unlikely_memory_error() {
1829 ffi::lua_tolstring(self.state, -1, ptr::null_mut())
1830 } else {
1831 protect_lua!(self.state, 1, 1, |state| {
1832 ffi::lua_tolstring(state, -1, ptr::null_mut())
1833 })?
1834 };
1835 if !res.is_null() {
1836 Some(String(self.pop_ref()))
1837 } else {
1838 None
1839 }
1840 },
1841 })
1842 }
1843
1844 pub fn coerce_integer(&self, v: Value) -> Result<Option<Integer>> {
1851 Ok(match v {
1852 Value::Integer(i) => Some(i),
1853 v => unsafe {
1854 let _sg = StackGuard::new(self.state);
1855 check_stack(self.state, 2)?;
1856
1857 self.push_value(v)?;
1858 let mut isint = 0;
1859 let i = ffi::lua_tointegerx(self.state, -1, &mut isint);
1860 if isint == 0 {
1861 None
1862 } else {
1863 Some(i)
1864 }
1865 },
1866 })
1867 }
1868
1869 pub fn coerce_number(&self, v: Value) -> Result<Option<Number>> {
1875 Ok(match v {
1876 Value::Number(n) => Some(n),
1877 v => unsafe {
1878 let _sg = StackGuard::new(self.state);
1879 check_stack(self.state, 2)?;
1880
1881 self.push_value(v)?;
1882 let mut isnum = 0;
1883 let n = ffi::lua_tonumberx(self.state, -1, &mut isnum);
1884 if isnum == 0 {
1885 None
1886 } else {
1887 Some(n)
1888 }
1889 },
1890 })
1891 }
1892
1893 pub fn pack<'lua, T: ToLua<'lua>>(&'lua self, t: T) -> Result<Value<'lua>> {
1895 t.to_lua(self)
1896 }
1897
1898 pub fn unpack<'lua, T: FromLua<'lua>>(&'lua self, value: Value<'lua>) -> Result<T> {
1900 T::from_lua(value, self)
1901 }
1902
1903 pub fn pack_multi<'lua, T: ToLuaMulti<'lua>>(&'lua self, t: T) -> Result<MultiValue<'lua>> {
1905 t.to_lua_multi(self)
1906 }
1907
1908 pub fn unpack_multi<'lua, T: FromLuaMulti<'lua>>(
1910 &'lua self,
1911 value: MultiValue<'lua>,
1912 ) -> Result<T> {
1913 T::from_lua_multi(value, self)
1914 }
1915
1916 pub fn set_named_registry_value<'lua, S, T>(&'lua self, name: &S, t: T) -> Result<()>
1921 where
1922 S: AsRef<[u8]> + ?Sized,
1923 T: ToLua<'lua>,
1924 {
1925 let t = t.to_lua(self)?;
1926 unsafe {
1927 let _sg = StackGuard::new(self.state);
1928 check_stack(self.state, 5)?;
1929
1930 self.push_value(t)?;
1931 rawset_field(self.state, ffi::LUA_REGISTRYINDEX, name)
1932 }
1933 }
1934
1935 pub fn named_registry_value<'lua, S, T>(&'lua self, name: &S) -> Result<T>
1942 where
1943 S: AsRef<[u8]> + ?Sized,
1944 T: FromLua<'lua>,
1945 {
1946 let value = unsafe {
1947 let _sg = StackGuard::new(self.state);
1948 check_stack(self.state, 3)?;
1949
1950 let protect = !self.unlikely_memory_error();
1951 push_string(self.state, name, protect)?;
1952 ffi::lua_rawget(self.state, ffi::LUA_REGISTRYINDEX);
1953
1954 self.pop_value()
1955 };
1956 T::from_lua(value, self)
1957 }
1958
1959 pub fn unset_named_registry_value<S>(&self, name: &S) -> Result<()>
1965 where
1966 S: AsRef<[u8]> + ?Sized,
1967 {
1968 self.set_named_registry_value(name, Nil)
1969 }
1970
1971 pub fn create_registry_value<'lua, T: ToLua<'lua>>(&'lua self, t: T) -> Result<RegistryKey> {
1982 let t = t.to_lua(self)?;
1983 unsafe {
1984 let _sg = StackGuard::new(self.state);
1985 check_stack(self.state, 4)?;
1986
1987 let unref_list = (*self.extra.get()).registry_unref_list.clone();
1988 self.push_value(t)?;
1989
1990 let unref_list2 = unref_list.clone();
1992 let mut unref_list2 = mlua_expect!(unref_list2.lock(), "unref list poisoned");
1993 if let Some(registry_id) = unref_list2.as_mut().and_then(|x| x.pop()) {
1994 ffi::lua_rawseti(self.state, ffi::LUA_REGISTRYINDEX, registry_id as Integer);
1996 return Ok(RegistryKey {
1997 registry_id,
1998 unref_list,
1999 });
2000 }
2001
2002 let registry_id = protect_lua!(self.state, 1, 0, |state| {
2004 ffi::luaL_ref(state, ffi::LUA_REGISTRYINDEX)
2005 })?;
2006
2007 Ok(RegistryKey {
2008 registry_id,
2009 unref_list,
2010 })
2011 }
2012 }
2013
2014 pub fn registry_value<'lua, T: FromLua<'lua>>(&'lua self, key: &RegistryKey) -> Result<T> {
2021 if !self.owns_registry_value(key) {
2022 return Err(Error::MismatchedRegistryKey);
2023 }
2024
2025 let value = unsafe {
2026 let _sg = StackGuard::new(self.state);
2027 check_stack(self.state, 1)?;
2028
2029 ffi::lua_rawgeti(
2030 self.state,
2031 ffi::LUA_REGISTRYINDEX,
2032 key.registry_id as Integer,
2033 );
2034 self.pop_value()
2035 };
2036 T::from_lua(value, self)
2037 }
2038
2039 pub fn remove_registry_value(&self, key: RegistryKey) -> Result<()> {
2049 if !self.owns_registry_value(&key) {
2050 return Err(Error::MismatchedRegistryKey);
2051 }
2052 unsafe {
2053 ffi::luaL_unref(self.state, ffi::LUA_REGISTRYINDEX, key.take());
2054 }
2055 Ok(())
2056 }
2057
2058 pub fn replace_registry_value<'lua, T: ToLua<'lua>>(
2064 &'lua self,
2065 key: &RegistryKey,
2066 t: T,
2067 ) -> Result<()> {
2068 if !self.owns_registry_value(key) {
2069 return Err(Error::MismatchedRegistryKey);
2070 }
2071
2072 let t = t.to_lua(self)?;
2073 unsafe {
2074 let _sg = StackGuard::new(self.state);
2075 check_stack(self.state, 2)?;
2076
2077 self.push_value(t)?;
2078 ffi::lua_rawseti(
2080 self.state,
2081 ffi::LUA_REGISTRYINDEX,
2082 key.registry_id as Integer,
2083 );
2084
2085 Ok(())
2086 }
2087 }
2088
2089 pub fn owns_registry_value(&self, key: &RegistryKey) -> bool {
2096 let registry_unref_list = unsafe { &(*self.extra.get()).registry_unref_list };
2097 Arc::ptr_eq(&key.unref_list, registry_unref_list)
2098 }
2099
2100 pub fn expire_registry_values(&self) {
2106 unsafe {
2107 let mut unref_list = mlua_expect!(
2108 (*self.extra.get()).registry_unref_list.lock(),
2109 "unref list poisoned"
2110 );
2111 let unref_list = mem::replace(&mut *unref_list, Some(Vec::new()));
2112 for id in mlua_expect!(unref_list, "unref list not set") {
2113 ffi::luaL_unref(self.state, ffi::LUA_REGISTRYINDEX, id);
2114 }
2115 }
2116 }
2117
2118 #[track_caller]
2145 pub fn set_app_data<T: 'static + MaybeSend>(&self, data: T) {
2146 let extra = unsafe { &mut (*self.extra.get()) };
2147 extra
2148 .app_data
2149 .try_borrow_mut()
2150 .expect("cannot borrow mutably app data container")
2151 .insert(TypeId::of::<T>(), Box::new(data));
2152 }
2153
2154 #[track_caller]
2156 pub fn app_data_ref<T: 'static>(&self) -> Option<Ref<T>> {
2157 let extra = unsafe { &(*self.extra.get()) };
2158 let app_data = extra
2159 .app_data
2160 .try_borrow()
2161 .expect("cannot borrow app data container");
2162 let value = app_data.get(&TypeId::of::<T>())?.downcast_ref::<T>()? as *const _;
2163 Some(Ref::map(app_data, |_| unsafe { &*value }))
2164 }
2165
2166 #[track_caller]
2168 pub fn app_data_mut<T: 'static>(&self) -> Option<RefMut<T>> {
2169 let extra = unsafe { &(*self.extra.get()) };
2170 let mut app_data = extra
2171 .app_data
2172 .try_borrow_mut()
2173 .expect("cannot mutably borrow app data container");
2174 let value = app_data.get_mut(&TypeId::of::<T>())?.downcast_mut::<T>()? as *mut _;
2175 Some(RefMut::map(app_data, |_| unsafe { &mut *value }))
2176 }
2177
2178 #[track_caller]
2180 pub fn remove_app_data<T: 'static>(&self) -> Option<T> {
2181 let extra = unsafe { &mut (*self.extra.get()) };
2182 extra
2183 .app_data
2184 .try_borrow_mut()
2185 .expect("cannot mutably borrow app data container")
2186 .remove(&TypeId::of::<T>())
2187 .and_then(|data| data.downcast().ok().map(|data| *data))
2188 }
2189
2190 pub(crate) unsafe fn push_value(&self, value: Value) -> Result<()> {
2192 match value {
2193 Value::Nil => {
2194 ffi::lua_pushnil(self.state);
2195 }
2196
2197 Value::Boolean(b) => {
2198 ffi::lua_pushboolean(self.state, if b { 1 } else { 0 });
2199 }
2200
2201 Value::LightUserData(ud) => {
2202 ffi::lua_pushlightuserdata(self.state, ud.0);
2203 }
2204
2205 Value::Integer(i) => {
2206 ffi::lua_pushinteger(self.state, i);
2207 }
2208
2209 Value::Number(n) => {
2210 ffi::lua_pushnumber(self.state, n);
2211 }
2212
2213 #[cfg(feature = "luau")]
2214 Value::Vector(x, y, z) => {
2215 ffi::lua_pushvector(self.state, x, y, z);
2216 }
2217
2218 Value::String(s) => {
2219 self.push_ref(&s.0);
2220 }
2221
2222 Value::Table(t) => {
2223 self.push_ref(&t.0);
2224 }
2225
2226 Value::Function(f) => {
2227 self.push_ref(&f.0);
2228 }
2229
2230 Value::Thread(t) => {
2231 self.push_ref(&t.0);
2232 }
2233
2234 Value::UserData(ud) => {
2235 self.push_ref(&ud.0);
2236 }
2237
2238 Value::Error(err) => {
2239 let protect = !self.unlikely_memory_error();
2240 push_gc_userdata(self.state, WrappedFailure::Error(err), protect)?;
2241 }
2242 }
2243
2244 Ok(())
2245 }
2246
2247 pub(crate) unsafe fn pop_value(&self) -> Value {
2249 let state = self.state;
2250 match ffi::lua_type(state, -1) {
2251 ffi::LUA_TNIL => {
2252 ffi::lua_pop(state, 1);
2253 Nil
2254 }
2255
2256 ffi::LUA_TBOOLEAN => {
2257 let b = Value::Boolean(ffi::lua_toboolean(state, -1) != 0);
2258 ffi::lua_pop(state, 1);
2259 b
2260 }
2261
2262 ffi::LUA_TLIGHTUSERDATA => {
2263 let ud = Value::LightUserData(LightUserData(ffi::lua_touserdata(state, -1)));
2264 ffi::lua_pop(state, 1);
2265 ud
2266 }
2267
2268 #[cfg(any(feature = "lua54", feature = "lua53"))]
2269 ffi::LUA_TNUMBER => {
2270 let v = if ffi::lua_isinteger(state, -1) != 0 {
2271 Value::Integer(ffi::lua_tointeger(state, -1))
2272 } else {
2273 Value::Number(ffi::lua_tonumber(state, -1))
2274 };
2275 ffi::lua_pop(state, 1);
2276 v
2277 }
2278
2279 #[cfg(any(
2280 feature = "lua52",
2281 feature = "lua51",
2282 feature = "luajit",
2283 feature = "luau"
2284 ))]
2285 ffi::LUA_TNUMBER => {
2286 let n = ffi::lua_tonumber(state, -1);
2287 ffi::lua_pop(state, 1);
2288 match num_traits::cast(n) {
2289 Some(i) if (n - (i as Number)).abs() < Number::EPSILON => Value::Integer(i),
2290 _ => Value::Number(n),
2291 }
2292 }
2293
2294 #[cfg(feature = "luau")]
2295 ffi::LUA_TVECTOR => {
2296 let v = ffi::lua_tovector(state, -1);
2297 mlua_debug_assert!(!v.is_null(), "vector is null");
2298 let vec = Value::Vector(*v, *v.add(1), *v.add(2));
2299 ffi::lua_pop(state, 1);
2300 vec
2301 }
2302
2303 ffi::LUA_TSTRING => Value::String(String(self.pop_ref())),
2304
2305 ffi::LUA_TTABLE => Value::Table(Table(self.pop_ref())),
2306
2307 ffi::LUA_TFUNCTION => Value::Function(Function(self.pop_ref())),
2308
2309 ffi::LUA_TUSERDATA => {
2310 match get_gc_userdata::<WrappedFailure>(state, -1).as_mut() {
2313 Some(WrappedFailure::Error(err)) => {
2314 let err = err.clone();
2315 ffi::lua_pop(state, 1);
2316 Value::Error(err)
2317 }
2318 Some(WrappedFailure::Panic(panic)) => {
2319 if let Some(panic) = panic.take() {
2320 ffi::lua_pop(state, 1);
2321 resume_unwind(panic);
2322 }
2323 ffi::lua_pop(state, 1);
2325 Nil
2326 }
2327 _ => Value::UserData(AnyUserData(self.pop_ref())),
2328 }
2329 }
2330
2331 ffi::LUA_TTHREAD => Value::Thread(Thread(self.pop_ref())),
2332
2333 #[cfg(feature = "luajit")]
2334 ffi::LUA_TCDATA => {
2335 ffi::lua_pop(state, 1);
2336 panic!("cdata objects cannot be handled by mlua yet");
2338 }
2339
2340 _ => mlua_panic!("LUA_TNONE in pop_value"),
2341 }
2342 }
2343
2344 pub(crate) unsafe fn push_ref(&self, lref: &LuaRef) {
2346 assert!(
2347 Arc::ptr_eq(&lref.lua.extra, &self.extra),
2348 "Lua instance passed Value created from a different main Lua state"
2349 );
2350 let extra = &*self.extra.get();
2351 #[cfg(not(feature = "luau"))]
2352 {
2353 ffi::lua_pushvalue(extra.ref_thread, lref.index);
2354 ffi::lua_xmove(extra.ref_thread, self.state, 1);
2355 }
2356 #[cfg(feature = "luau")]
2357 ffi::lua_xpush(extra.ref_thread, self.state, lref.index);
2358 }
2359
2360 pub(crate) unsafe fn pop_ref(&self) -> LuaRef {
2370 let extra = &mut *self.extra.get();
2371 ffi::lua_xmove(self.state, extra.ref_thread, 1);
2372 let index = ref_stack_pop(extra);
2373 LuaRef { lua: self, index }
2374 }
2375
2376 pub(crate) fn clone_ref<'lua>(&'lua self, lref: &LuaRef<'lua>) -> LuaRef<'lua> {
2377 unsafe {
2378 let extra = &mut *self.extra.get();
2379 ffi::lua_pushvalue(extra.ref_thread, lref.index);
2380 let index = ref_stack_pop(extra);
2381 LuaRef { lua: self, index }
2382 }
2383 }
2384
2385 pub(crate) fn drop_ref(&self, lref: &LuaRef) {
2386 unsafe {
2387 let extra = &mut *self.extra.get();
2388 ffi::lua_pushnil(extra.ref_thread);
2389 ffi::lua_replace(extra.ref_thread, lref.index);
2390 extra.ref_free.push(lref.index);
2391 }
2392 }
2393
2394 #[inline]
2396 pub(crate) unsafe fn ref_thread_exec<F, R>(&self, f: F) -> R
2397 where
2398 F: FnOnce(*mut ffi::lua_State) -> R,
2399 {
2400 let ref_thread = (*self.extra.get()).ref_thread;
2401 f(ref_thread)
2402 }
2403
2404 unsafe fn push_userdata_metatable<T: 'static + UserData>(&self) -> Result<()> {
2405 let extra = &mut *self.extra.get();
2406
2407 let type_id = TypeId::of::<T>();
2408 if let Some(&table_id) = extra.registered_userdata.get(&type_id) {
2409 ffi::lua_rawgeti(self.state, ffi::LUA_REGISTRYINDEX, table_id as Integer);
2410 return Ok(());
2411 }
2412
2413 let _sg = StackGuard::new_extra(self.state, 1);
2414 check_stack(self.state, 13)?;
2415
2416 let mut fields = StaticUserDataFields::default();
2417 let mut methods = StaticUserDataMethods::default();
2418 T::add_fields(&mut fields);
2419 T::add_methods(&mut methods);
2420
2421 let metatable_nrec = methods.meta_methods.len() + fields.meta_fields.len();
2423 #[cfg(feature = "async")]
2424 let metatable_nrec = metatable_nrec + methods.async_meta_methods.len();
2425 push_table(self.state, 0, metatable_nrec as c_int, true)?;
2426 for (k, m) in methods.meta_methods {
2427 self.push_value(Value::Function(self.create_callback(m)?))?;
2428 rawset_field(self.state, -2, k.validate()?.name())?;
2429 }
2430 #[cfg(feature = "async")]
2431 for (k, m) in methods.async_meta_methods {
2432 self.push_value(Value::Function(self.create_async_callback(m)?))?;
2433 rawset_field(self.state, -2, k.validate()?.name())?;
2434 }
2435 for (k, f) in fields.meta_fields {
2436 self.push_value(f(self)?)?;
2437 rawset_field(self.state, -2, k.validate()?.name())?;
2438 }
2439 let metatable_index = ffi::lua_absindex(self.state, -1);
2440
2441 let mut extra_tables_count = 0;
2442
2443 let mut field_getters_index = None;
2444 let field_getters_nrec = fields.field_getters.len();
2445 if field_getters_nrec > 0 {
2446 push_table(self.state, 0, field_getters_nrec as c_int, true)?;
2447 for (k, m) in fields.field_getters {
2448 self.push_value(Value::Function(self.create_callback(m)?))?;
2449 rawset_field(self.state, -2, &k)?;
2450 }
2451 field_getters_index = Some(ffi::lua_absindex(self.state, -1));
2452 extra_tables_count += 1;
2453 }
2454
2455 let mut field_setters_index = None;
2456 let field_setters_nrec = fields.field_setters.len();
2457 if field_setters_nrec > 0 {
2458 push_table(self.state, 0, field_setters_nrec as c_int, true)?;
2459 for (k, m) in fields.field_setters {
2460 self.push_value(Value::Function(self.create_callback(m)?))?;
2461 rawset_field(self.state, -2, &k)?;
2462 }
2463 field_setters_index = Some(ffi::lua_absindex(self.state, -1));
2464 extra_tables_count += 1;
2465 }
2466
2467 let mut methods_index = None;
2468 let methods_nrec = methods.methods.len();
2469 #[cfg(feature = "async")]
2470 let methods_nrec = methods_nrec + methods.async_methods.len();
2471 if methods_nrec > 0 {
2472 push_table(self.state, 0, methods_nrec as c_int, true)?;
2473 for (k, m) in methods.methods {
2474 self.push_value(Value::Function(self.create_callback(m)?))?;
2475 rawset_field(self.state, -2, &k)?;
2476 }
2477 #[cfg(feature = "async")]
2478 for (k, m) in methods.async_methods {
2479 self.push_value(Value::Function(self.create_async_callback(m)?))?;
2480 rawset_field(self.state, -2, &k)?;
2481 }
2482 methods_index = Some(ffi::lua_absindex(self.state, -1));
2483 extra_tables_count += 1;
2484 }
2485
2486 init_userdata_metatable::<UserDataCell<T>>(
2487 self.state,
2488 metatable_index,
2489 field_getters_index,
2490 field_setters_index,
2491 methods_index,
2492 )?;
2493
2494 ffi::lua_pop(self.state, extra_tables_count);
2496
2497 let mt_ptr = ffi::lua_topointer(self.state, -1);
2498 ffi::lua_pushvalue(self.state, -1);
2499 let id = protect_lua!(self.state, 1, 0, |state| {
2500 ffi::luaL_ref(state, ffi::LUA_REGISTRYINDEX)
2501 })?;
2502
2503 extra.registered_userdata.insert(type_id, id);
2504 extra.registered_userdata_mt.insert(mt_ptr, Some(type_id));
2505
2506 Ok(())
2507 }
2508
2509 pub(crate) unsafe fn register_userdata_metatable(
2510 &self,
2511 ptr: *const c_void,
2512 type_id: Option<TypeId>,
2513 ) {
2514 let extra = &mut *self.extra.get();
2515 extra.registered_userdata_mt.insert(ptr, type_id);
2516 }
2517
2518 pub(crate) unsafe fn deregister_userdata_metatable(&self, ptr: *const c_void) {
2519 (*self.extra.get()).registered_userdata_mt.remove(&ptr);
2520 }
2521
2522 pub(crate) unsafe fn push_userdata_ref(&self, lref: &LuaRef) -> Result<Option<TypeId>> {
2526 self.push_ref(lref);
2527 if ffi::lua_getmetatable(self.state, -1) == 0 {
2528 return Err(Error::UserDataTypeMismatch);
2529 }
2530 let mt_ptr = ffi::lua_topointer(self.state, -1);
2531 ffi::lua_pop(self.state, 1);
2532
2533 let extra = &*self.extra.get();
2534 match extra.registered_userdata_mt.get(&mt_ptr) {
2535 Some(&type_id) if type_id == Some(TypeId::of::<DestructedUserdataMT>()) => {
2536 Err(Error::UserDataDestructed)
2537 }
2538 Some(&type_id) => Ok(type_id),
2539 None => Err(Error::UserDataTypeMismatch),
2540 }
2541 }
2542
2543 pub(crate) fn create_callback<'lua>(
2552 &'lua self,
2553 func: Callback<'lua, 'static>,
2554 ) -> Result<Function<'lua>> {
2555 unsafe extern "C" fn call_callback(state: *mut ffi::lua_State) -> c_int {
2556 let extra = match ffi::lua_type(state, ffi::lua_upvalueindex(1)) {
2557 ffi::LUA_TUSERDATA => {
2558 let upvalue = get_userdata::<CallbackUpvalue>(state, ffi::lua_upvalueindex(1));
2559 (*upvalue).extra.get()
2560 }
2561 _ => ptr::null_mut(),
2562 };
2563 callback_error_ext(state, extra, |nargs| {
2564 let upvalue_idx = ffi::lua_upvalueindex(1);
2565 if ffi::lua_type(state, upvalue_idx) == ffi::LUA_TNIL {
2566 return Err(Error::CallbackDestructed);
2567 }
2568 let upvalue = get_userdata::<CallbackUpvalue>(state, upvalue_idx);
2569
2570 if nargs < ffi::LUA_MINSTACK {
2571 check_stack(state, ffi::LUA_MINSTACK - nargs)?;
2572 }
2573
2574 let lua: &Lua = mem::transmute((*extra).inner.as_ref().unwrap());
2575 let _guard = StateGuard::new(&mut *lua.0.get(), state);
2576
2577 let mut args = MultiValue::new_or_cached(lua);
2578 args.reserve(nargs as usize);
2579 for _ in 0..nargs {
2580 args.push_front(lua.pop_value());
2581 }
2582
2583 let func = &*(*upvalue).data;
2584 let mut results = func(lua, args)?;
2585 let nresults = results.len() as c_int;
2586
2587 check_stack(state, nresults)?;
2588 for r in results.drain_all() {
2589 lua.push_value(r)?;
2590 }
2591 lua.cache_multivalue(results);
2592
2593 Ok(nresults)
2594 })
2595 }
2596
2597 unsafe {
2598 let _sg = StackGuard::new(self.state);
2599 check_stack(self.state, 4)?;
2600
2601 let func = mem::transmute(func);
2602 let extra = Arc::clone(&self.extra);
2603 let protect = !self.unlikely_memory_error();
2604 push_gc_userdata(self.state, CallbackUpvalue { data: func, extra }, protect)?;
2605 if protect {
2606 protect_lua!(self.state, 1, 1, fn(state) {
2607 ffi::lua_pushcclosure(state, call_callback, 1);
2608 })?;
2609 } else {
2610 ffi::lua_pushcclosure(self.state, call_callback, 1);
2611 }
2612
2613 Ok(Function(self.pop_ref()))
2614 }
2615 }
2616
2617 #[cfg(feature = "async")]
2618 pub(crate) fn create_async_callback<'lua>(
2619 &'lua self,
2620 func: AsyncCallback<'lua, 'static>,
2621 ) -> Result<Function<'lua>> {
2622 #[cfg(any(
2623 feature = "lua54",
2624 feature = "lua53",
2625 feature = "lua52",
2626 feature = "luau",
2627 feature = "lua-factorio"
2628 ))]
2629 unsafe {
2630 let libs = (*self.extra.get()).libs;
2631 if !libs.contains(StdLib::COROUTINE) {
2632 self.load_from_std_lib(StdLib::COROUTINE)?;
2633 }
2634 }
2635
2636 unsafe extern "C" fn call_callback(state: *mut ffi::lua_State) -> c_int {
2637 let extra = match ffi::lua_type(state, ffi::lua_upvalueindex(1)) {
2638 ffi::LUA_TUSERDATA => {
2639 let upvalue =
2640 get_userdata::<AsyncCallbackUpvalue>(state, ffi::lua_upvalueindex(1));
2641 (*upvalue).extra.get()
2642 }
2643 _ => ptr::null_mut(),
2644 };
2645 callback_error_ext(state, extra, |nargs| {
2646 let upvalue_idx = ffi::lua_upvalueindex(1);
2647 if ffi::lua_type(state, upvalue_idx) == ffi::LUA_TNIL {
2648 return Err(Error::CallbackDestructed);
2649 }
2650 let upvalue = get_userdata::<AsyncCallbackUpvalue>(state, upvalue_idx);
2651
2652 if nargs < ffi::LUA_MINSTACK {
2653 check_stack(state, ffi::LUA_MINSTACK - nargs)?;
2654 }
2655
2656 let lua: &Lua = mem::transmute((*extra).inner.as_ref().unwrap());
2657 let _guard = StateGuard::new(&mut *lua.0.get(), state);
2658
2659 let mut args = MultiValue::new_or_cached(lua);
2660 args.reserve(nargs as usize);
2661 for _ in 0..nargs {
2662 args.push_front(lua.pop_value());
2663 }
2664
2665 let func = &*(*upvalue).data;
2666 let fut = func(lua, args);
2667 let extra = Arc::clone(&(*upvalue).extra);
2668 let protect = !lua.unlikely_memory_error();
2669 push_gc_userdata(state, AsyncPollUpvalue { data: fut, extra }, protect)?;
2670 if protect {
2671 protect_lua!(state, 1, 1, fn(state) {
2672 ffi::lua_pushcclosure(state, poll_future, 1);
2673 })?;
2674 } else {
2675 ffi::lua_pushcclosure(state, poll_future, 1);
2676 }
2677
2678 Ok(1)
2679 })
2680 }
2681
2682 unsafe extern "C" fn poll_future(state: *mut ffi::lua_State) -> c_int {
2683 let extra = match ffi::lua_type(state, ffi::lua_upvalueindex(1)) {
2684 ffi::LUA_TUSERDATA => {
2685 let upvalue = get_userdata::<AsyncPollUpvalue>(state, ffi::lua_upvalueindex(1));
2686 (*upvalue).extra.get()
2687 }
2688 _ => ptr::null_mut(),
2689 };
2690 callback_error_ext(state, extra, |nargs| {
2691 let upvalue_idx = ffi::lua_upvalueindex(1);
2692 if ffi::lua_type(state, upvalue_idx) == ffi::LUA_TNIL {
2693 return Err(Error::CallbackDestructed);
2694 }
2695 let upvalue = get_userdata::<AsyncPollUpvalue>(state, upvalue_idx);
2696
2697 if nargs < ffi::LUA_MINSTACK {
2698 check_stack(state, ffi::LUA_MINSTACK - nargs)?;
2699 }
2700
2701 let lua: &Lua = mem::transmute((*extra).inner.as_ref().unwrap());
2702 let _guard = StateGuard::new(&mut *lua.0.get(), state);
2703
2704 let waker = lua.waker().unwrap_or_else(noop_waker);
2706 let mut ctx = Context::from_waker(&waker);
2707
2708 let fut = &mut (*upvalue).data;
2709 match fut.as_mut().poll(&mut ctx) {
2710 Poll::Pending => {
2711 check_stack(state, 1)?;
2712 ffi::lua_pushboolean(state, 0);
2713 Ok(1)
2714 }
2715 Poll::Ready(results) => {
2716 let results = results?;
2717 let nresults = results.len() as Integer;
2718 let results = lua.create_sequence_from(results)?;
2719 check_stack(state, 3)?;
2720 ffi::lua_pushboolean(state, 1);
2721 lua.push_value(Value::Table(results))?;
2722 lua.push_value(Value::Integer(nresults))?;
2723 Ok(3)
2724 }
2725 }
2726 })
2727 }
2728
2729 let get_poll = unsafe {
2730 let _sg = StackGuard::new(self.state);
2731 check_stack(self.state, 4)?;
2732
2733 let func = mem::transmute(func);
2734 let extra = Arc::clone(&self.extra);
2735 let protect = !self.unlikely_memory_error();
2736 let upvalue = AsyncCallbackUpvalue { data: func, extra };
2737 push_gc_userdata(self.state, upvalue, protect)?;
2738 if protect {
2739 protect_lua!(self.state, 1, 1, fn(state) {
2740 ffi::lua_pushcclosure(state, call_callback, 1);
2741 })?;
2742 } else {
2743 ffi::lua_pushcclosure(self.state, call_callback, 1);
2744 }
2745
2746 Function(self.pop_ref())
2747 };
2748
2749 unsafe extern "C" fn unpack(state: *mut ffi::lua_State) -> c_int {
2750 let len = ffi::lua_tointeger(state, 2);
2751 ffi::luaL_checkstack(state, len as c_int, ptr::null());
2752 for i in 1..=len {
2753 ffi::lua_rawgeti(state, 1, i);
2754 }
2755 len as c_int
2756 }
2757
2758 let coroutine = self.globals().get::<_, Table>("coroutine")?;
2759
2760 let env = self.create_table_with_capacity(0, 4)?;
2761 env.set("get_poll", get_poll)?;
2762 env.set("yield", coroutine.get::<_, Function>("yield")?)?;
2763 unsafe {
2764 env.set("unpack", self.create_c_function(unpack)?)?;
2765 }
2766 env.set("pending", {
2767 LightUserData(&ASYNC_POLL_PENDING as *const u8 as *mut c_void)
2768 })?;
2769
2770 self.load(
2772 r#"
2773 poll = get_poll(...)
2774 local poll, pending, yield, unpack = poll, pending, yield, unpack
2775 while true do
2776 local ready, res, nres = poll()
2777 if ready then
2778 return unpack(res, nres)
2779 end
2780 yield(pending)
2781 end
2782 "#,
2783 )
2784 .try_cache()
2785 .set_name("_mlua_async_poll")?
2786 .set_environment(env)?
2787 .into_function()
2788 }
2789
2790 #[cfg(feature = "async")]
2791 #[inline]
2792 pub(crate) unsafe fn waker(&self) -> Option<Waker> {
2793 let extra = &*self.extra.get();
2794 (*get_userdata::<Option<Waker>>(extra.ref_thread, extra.ref_waker_idx)).clone()
2795 }
2796
2797 #[cfg(feature = "async")]
2798 #[inline]
2799 pub(crate) unsafe fn set_waker(&self, waker: Option<Waker>) -> Option<Waker> {
2800 let extra = &*self.extra.get();
2801 let waker_slot = &mut *get_userdata::<Option<Waker>>(extra.ref_thread, extra.ref_waker_idx);
2802 match waker {
2803 Some(waker) => waker_slot.replace(waker),
2804 None => waker_slot.take(),
2805 }
2806 }
2807
2808 pub(crate) unsafe fn make_userdata<T>(&self, data: UserDataCell<T>) -> Result<AnyUserData>
2809 where
2810 T: 'static + UserData,
2811 {
2812 let _sg = StackGuard::new(self.state);
2813 check_stack(self.state, 3)?;
2814
2815 ffi::lua_pushnil(self.state);
2817 self.push_userdata_metatable::<T>()?;
2818 let protect = !self.unlikely_memory_error();
2819 #[cfg(not(feature = "lua54"))]
2820 push_userdata(self.state, data, protect)?;
2821 #[cfg(feature = "lua54")]
2822 push_userdata_uv(self.state, data, USER_VALUE_MAXSLOT as c_int, protect)?;
2823 ffi::lua_replace(self.state, -3);
2824 ffi::lua_setmetatable(self.state, -2);
2825
2826 #[cfg(any(feature = "lua51", feature = "luajit"))]
2828 if protect {
2829 protect_lua!(self.state, 1, 1, fn(state) {
2830 ffi::lua_newtable(state);
2831 ffi::lua_setuservalue(state, -2);
2832 })?;
2833 } else {
2834 ffi::lua_newtable(self.state);
2835 ffi::lua_setuservalue(self.state, -2);
2836 }
2837
2838 Ok(AnyUserData(self.pop_ref()))
2839 }
2840
2841 #[cfg(not(feature = "luau"))]
2842 fn disable_c_modules(&self) -> Result<()> {
2843 let package: Table = self.globals().get("package")?;
2844
2845 package.set(
2846 "loadlib",
2847 self.create_function(|_, ()| -> Result<()> {
2848 Err(Error::SafetyError(
2849 "package.loadlib is disabled in safe mode".to_string(),
2850 ))
2851 })?,
2852 )?;
2853
2854 #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "lua-factorio"))]
2855 let searchers: Table = package.get("searchers")?;
2856 #[cfg(any(feature = "lua51", feature = "luajit"))]
2857 let searchers: Table = package.get("loaders")?;
2858
2859 let loader = self.create_function(|_, ()| Ok("\n\tcan't load C modules in safe mode"))?;
2860
2861 searchers.raw_set(3, loader.clone())?;
2863 searchers.raw_remove(4)?;
2864
2865 Ok(())
2866 }
2867
2868 pub(crate) unsafe fn make_from_ptr(state: *mut ffi::lua_State) -> Option<Self> {
2869 let _sg = StackGuard::new(state);
2870 assert_stack(state, 1);
2871 let extra = extra_data(state)?;
2872 let inner = &*(*extra.get()).inner.as_ref().unwrap();
2873 Some(Lua(Arc::clone(inner)))
2874 }
2875
2876 #[inline]
2877 pub(crate) fn new_or_cached_multivalue(&self) -> MultiValue {
2878 unsafe {
2879 let extra = &mut *self.extra.get();
2880 extra.multivalue_cache.pop().unwrap_or_default()
2881 }
2882 }
2883
2884 #[inline]
2885 pub(crate) fn cache_multivalue(&self, mut multivalue: MultiValue) {
2886 unsafe {
2887 let extra = &mut *self.extra.get();
2888 if extra.multivalue_cache.len() < MULTIVALUE_CACHE_SIZE {
2889 multivalue.clear();
2890 extra.multivalue_cache.push(mem::transmute(multivalue));
2891 }
2892 }
2893 }
2894
2895 #[inline]
2896 pub(crate) unsafe fn unlikely_memory_error(&self) -> bool {
2897 let extra = &mut *self.extra.get();
2898 extra
2900 .mem_info
2901 .map(|x| x.as_ref().memory_limit == 0)
2902 .unwrap_or_default()
2903 }
2904}
2905
2906struct StateGuard<'a>(&'a mut LuaInner, *mut ffi::lua_State);
2907
2908impl<'a> StateGuard<'a> {
2909 fn new(inner: &'a mut LuaInner, mut state: *mut ffi::lua_State) -> Self {
2910 mem::swap(&mut (*inner).state, &mut state);
2911 Self(inner, state)
2912 }
2913}
2914
2915impl<'a> Drop for StateGuard<'a> {
2916 fn drop(&mut self) {
2917 mem::swap(&mut (*self.0).state, &mut self.1);
2918 }
2919}
2920
2921#[cfg(feature = "luau")]
2922unsafe fn extra_data(state: *mut ffi::lua_State) -> Option<Arc<UnsafeCell<ExtraData>>> {
2923 let extra_ptr = (*ffi::lua_callbacks(state)).userdata as *mut Arc<UnsafeCell<ExtraData>>;
2924 if extra_ptr.is_null() {
2925 return None;
2926 }
2927 Some(Arc::clone(&*extra_ptr))
2928}
2929
2930#[cfg(not(feature = "luau"))]
2931unsafe fn extra_data(state: *mut ffi::lua_State) -> Option<Arc<UnsafeCell<ExtraData>>> {
2932 let extra_key = &EXTRA_REGISTRY_KEY as *const u8 as *const c_void;
2933 if ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, extra_key) != ffi::LUA_TUSERDATA {
2934 return None;
2935 }
2936 let extra_ptr = ffi::lua_touserdata(state, -1) as *mut Arc<UnsafeCell<ExtraData>>;
2937 let extra = Arc::clone(&*extra_ptr);
2938 ffi::lua_pop(state, 1);
2939 Some(extra)
2940}
2941
2942pub(crate) fn init_metatable_cache(cache: &mut FxHashMap<TypeId, u8>) {
2944 cache.insert(TypeId::of::<Arc<UnsafeCell<ExtraData>>>(), 0);
2945 cache.insert(TypeId::of::<Callback>(), 0);
2946 cache.insert(TypeId::of::<CallbackUpvalue>(), 0);
2947
2948 #[cfg(feature = "async")]
2949 {
2950 cache.insert(TypeId::of::<AsyncCallback>(), 0);
2951 cache.insert(TypeId::of::<AsyncCallbackUpvalue>(), 0);
2952 cache.insert(TypeId::of::<AsyncPollUpvalue>(), 0);
2953 cache.insert(TypeId::of::<Option<Waker>>(), 0);
2954 }
2955}
2956
2957unsafe fn callback_error_ext<F, R>(state: *mut ffi::lua_State, extra: *mut ExtraData, f: F) -> R
2960where
2961 F: FnOnce(c_int) -> Result<R>,
2962{
2963 if extra.is_null() {
2964 return callback_error(state, f);
2965 }
2966 let extra = &mut *extra;
2967
2968 let nargs = ffi::lua_gettop(state);
2969
2970 if !cfg!(feature = "luau") || extra.wrapped_failures_cache.is_empty() {
2974 let extra_stack = if nargs < 2 { 2 - nargs } else { 1 };
2975 ffi::luaL_checkstack(
2976 state,
2977 extra_stack,
2978 cstr!("not enough stack space for callback error handling"),
2979 );
2980 }
2981
2982 enum PreallocatedFailure {
2983 New(*mut WrappedFailure),
2984 Cached(i32),
2985 }
2986
2987 let prealloc_failure = match extra.wrapped_failures_cache.pop() {
2990 Some(index) => PreallocatedFailure::Cached(index),
2991 None => {
2992 let ud = WrappedFailure::new_userdata(state);
2993 ffi::lua_rotate(state, 1, 1);
2994 PreallocatedFailure::New(ud)
2995 }
2996 };
2997
2998 let mut get_wrapped_failure = || match prealloc_failure {
2999 PreallocatedFailure::New(ud) => {
3000 ffi::lua_settop(state, 1);
3001 ud
3002 }
3003 PreallocatedFailure::Cached(index) => {
3004 ffi::lua_settop(state, 0);
3005 #[cfg(feature = "luau")]
3006 assert_stack(state, 2);
3007 ffi::lua_pushvalue(extra.ref_thread, index);
3008 ffi::lua_xmove(extra.ref_thread, state, 1);
3009 ffi::lua_pushnil(extra.ref_thread);
3010 ffi::lua_replace(extra.ref_thread, index);
3011 extra.ref_free.push(index);
3012 ffi::lua_touserdata(state, -1) as *mut WrappedFailure
3013 }
3014 };
3015
3016 match catch_unwind(AssertUnwindSafe(|| f(nargs))) {
3017 Ok(Ok(r)) => {
3018 match prealloc_failure {
3020 PreallocatedFailure::New(_)
3021 if extra.wrapped_failures_cache.len() < WRAPPED_FAILURES_CACHE_SIZE =>
3022 {
3023 ffi::lua_rotate(state, 1, -1);
3024 ffi::lua_xmove(state, extra.ref_thread, 1);
3025 let index = ref_stack_pop(extra);
3026 extra.wrapped_failures_cache.push(index);
3027 }
3028 PreallocatedFailure::New(_) => {
3029 ffi::lua_remove(state, 1);
3030 }
3031 PreallocatedFailure::Cached(index)
3032 if extra.wrapped_failures_cache.len() < WRAPPED_FAILURES_CACHE_SIZE =>
3033 {
3034 extra.wrapped_failures_cache.push(index);
3035 }
3036 PreallocatedFailure::Cached(index) => {
3037 ffi::lua_pushnil(extra.ref_thread);
3038 ffi::lua_replace(extra.ref_thread, index);
3039 extra.ref_free.push(index);
3040 }
3041 }
3042 r
3043 }
3044 Ok(Err(err)) => {
3045 let wrapped_error = get_wrapped_failure();
3046
3047 let traceback = if ffi::lua_checkstack(state, ffi::LUA_TRACEBACK_STACK) != 0 {
3049 ffi::luaL_traceback(state, state, ptr::null(), 0);
3050 let traceback = util::to_string(state, -1);
3051 ffi::lua_pop(state, 1);
3052 traceback
3053 } else {
3054 "<not enough stack space for traceback>".to_string()
3055 };
3056 let cause = Arc::new(err);
3057 ptr::write(
3058 wrapped_error,
3059 WrappedFailure::Error(Error::CallbackError { traceback, cause }),
3060 );
3061 get_gc_metatable::<WrappedFailure>(state);
3062 ffi::lua_setmetatable(state, -2);
3063
3064 ffi::lua_error(state)
3065 }
3066 Err(p) => {
3067 let wrapped_panic = get_wrapped_failure();
3068 ptr::write(wrapped_panic, WrappedFailure::Panic(Some(p)));
3069 get_gc_metatable::<WrappedFailure>(state);
3070 ffi::lua_setmetatable(state, -2);
3071 ffi::lua_error(state)
3072 }
3073 }
3074}
3075
3076unsafe fn load_from_std_lib(state: *mut ffi::lua_State, libs: StdLib) -> Result<()> {
3078 #[inline(always)]
3079 pub unsafe fn requiref<S: AsRef<[u8]> + ?Sized>(
3080 state: *mut ffi::lua_State,
3081 modname: &S,
3082 openf: ffi::lua_CFunction,
3083 glb: c_int,
3084 ) -> Result<()> {
3085 let modname = mlua_expect!(CString::new(modname.as_ref()), "modname contains nil byte");
3086 protect_lua!(state, 0, 1, |state| {
3087 ffi::luaL_requiref(state, modname.as_ptr() as *const c_char, openf, glb)
3088 })
3089 }
3090
3091 #[cfg(feature = "luajit")]
3092 struct GcGuard(*mut ffi::lua_State);
3093
3094 #[cfg(feature = "luajit")]
3095 impl GcGuard {
3096 fn new(state: *mut ffi::lua_State) -> Self {
3097 unsafe { ffi::lua_gc(state, ffi::LUA_GCSTOP, 0) };
3099 GcGuard(state)
3100 }
3101 }
3102
3103 #[cfg(feature = "luajit")]
3104 impl Drop for GcGuard {
3105 fn drop(&mut self) {
3106 unsafe { ffi::lua_gc(self.0, ffi::LUA_GCRESTART, -1) };
3107 }
3108 }
3109
3110 #[cfg(feature = "luajit")]
3112 let _gc_guard = GcGuard::new(state);
3113
3114 #[cfg(any(
3115 feature = "lua54",
3116 feature = "lua53",
3117 feature = "lua52",
3118 feature = "luau"
3119 ))]
3120 {
3121 if libs.contains(StdLib::COROUTINE) {
3122 requiref(state, ffi::LUA_COLIBNAME, ffi::luaopen_coroutine, 1)?;
3123 ffi::lua_pop(state, 1);
3124 }
3125 }
3126
3127 if libs.contains(StdLib::TABLE) {
3128 requiref(state, ffi::LUA_TABLIBNAME, ffi::luaopen_table, 1)?;
3129 ffi::lua_pop(state, 1);
3130 }
3131
3132 #[cfg(not(any(feature = "luau", feature = "lua-factorio")))]
3133 if libs.contains(StdLib::IO) {
3134 requiref(state, ffi::LUA_IOLIBNAME, ffi::luaopen_io, 1)?;
3135 ffi::lua_pop(state, 1);
3136 }
3137
3138 #[cfg(not(feature = "lua-factorio"))]
3139 if libs.contains(StdLib::OS) {
3140 requiref(state, ffi::LUA_OSLIBNAME, ffi::luaopen_os, 1)?;
3141 ffi::lua_pop(state, 1);
3142 }
3143
3144 if libs.contains(StdLib::STRING) {
3145 requiref(state, ffi::LUA_STRLIBNAME, ffi::luaopen_string, 1)?;
3146 ffi::lua_pop(state, 1);
3147 }
3148
3149 #[cfg(any(feature = "lua54", feature = "lua53", feature = "luau"))]
3150 {
3151 if libs.contains(StdLib::UTF8) {
3152 requiref(state, ffi::LUA_UTF8LIBNAME, ffi::luaopen_utf8, 1)?;
3153 ffi::lua_pop(state, 1);
3154 }
3155 }
3156
3157 #[cfg(any(feature = "lua52", feature = "luau", feature = "lua-factorio"))]
3158 {
3159 if libs.contains(StdLib::BIT) {
3160 requiref(state, ffi::LUA_BITLIBNAME, ffi::luaopen_bit32, 1)?;
3161 ffi::lua_pop(state, 1);
3162 }
3163 }
3164
3165 #[cfg(feature = "luajit")]
3166 {
3167 if libs.contains(StdLib::BIT) {
3168 requiref(state, ffi::LUA_BITLIBNAME, ffi::luaopen_bit, 1)?;
3169 ffi::lua_pop(state, 1);
3170 }
3171 }
3172
3173 if libs.contains(StdLib::MATH) {
3174 requiref(state, ffi::LUA_MATHLIBNAME, ffi::luaopen_math, 1)?;
3175 ffi::lua_pop(state, 1);
3176 }
3177
3178 if libs.contains(StdLib::DEBUG) {
3179 requiref(state, ffi::LUA_DBLIBNAME, ffi::luaopen_debug, 1)?;
3180 ffi::lua_pop(state, 1);
3181 }
3182
3183 #[cfg(not(feature = "luau"))]
3184 if libs.contains(StdLib::PACKAGE) {
3185 requiref(state, ffi::LUA_LOADLIBNAME, ffi::luaopen_package, 1)?;
3186 ffi::lua_pop(state, 1);
3187 }
3188
3189 #[cfg(feature = "luajit")]
3190 {
3191 if libs.contains(StdLib::JIT) {
3192 requiref(state, ffi::LUA_JITLIBNAME, ffi::luaopen_jit, 1)?;
3193 ffi::lua_pop(state, 1);
3194 }
3195
3196 if libs.contains(StdLib::FFI) {
3197 requiref(state, ffi::LUA_FFILIBNAME, ffi::luaopen_ffi, 1)?;
3198 ffi::lua_pop(state, 1);
3199 }
3200 }
3201
3202 Ok(())
3203}
3204
3205unsafe fn ref_stack_pop(extra: &mut ExtraData) -> c_int {
3206 if let Some(free) = extra.ref_free.pop() {
3207 ffi::lua_replace(extra.ref_thread, free);
3208 return free;
3209 }
3210
3211 if extra.ref_stack_top >= extra.ref_stack_size {
3213 let mut inc = extra.ref_stack_size; while inc > 0 && ffi::lua_checkstack(extra.ref_thread, inc) == 0 {
3215 inc /= 2;
3216 }
3217 if inc == 0 {
3218 ffi::lua_pop(extra.ref_thread, 1);
3221 let top = extra.ref_stack_top;
3222 panic!(
3225 "cannot create a Lua reference, out of auxiliary stack space (used {} slots)",
3226 top
3227 );
3228 }
3229 extra.ref_stack_size += inc;
3230 }
3231 extra.ref_stack_top += 1;
3232 extra.ref_stack_top
3233}