2018-08-05 09:51:39 -04:00
|
|
|
use std::any::TypeId;
|
2018-03-28 01:09:51 -04:00
|
|
|
use std::cell::{RefCell, UnsafeCell};
|
2021-04-16 17:01:55 -04:00
|
|
|
use std::collections::{HashMap, HashSet};
|
2017-07-24 18:37:37 -04:00
|
|
|
use std::ffi::CString;
|
2021-05-03 08:05:43 -04:00
|
|
|
use std::fmt;
|
2017-05-21 19:50:59 -04:00
|
|
|
use std::marker::PhantomData;
|
2020-05-08 19:18:48 -04:00
|
|
|
use std::os::raw::{c_char, c_int, c_void};
|
2021-06-19 19:24:53 -04:00
|
|
|
use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
|
2021-07-08 12:32:20 -04:00
|
|
|
use std::sync::{Arc, Mutex, RwLock};
|
2018-08-05 09:51:39 -04:00
|
|
|
use std::{mem, ptr, str};
|
2017-05-21 19:50:59 -04:00
|
|
|
|
2019-09-27 12:27:37 -04:00
|
|
|
use crate::error::{Error, Result};
|
|
|
|
use crate::ffi;
|
|
|
|
use crate::function::Function;
|
2021-06-16 17:13:11 -04:00
|
|
|
use crate::hook::{hook_proc, Debug, HookTriggers};
|
2020-05-06 20:18:56 -04:00
|
|
|
use crate::scope::Scope;
|
2019-12-26 17:51:15 -05:00
|
|
|
use crate::stdlib::StdLib;
|
2019-09-27 12:27:37 -04:00
|
|
|
use crate::string::String;
|
|
|
|
use crate::table::Table;
|
|
|
|
use crate::thread::Thread;
|
2020-05-21 19:35:03 -04:00
|
|
|
use crate::types::{
|
2021-06-30 11:50:50 -04:00
|
|
|
Callback, CallbackUpvalue, HookCallback, Integer, LightUserData, LuaRef, MaybeSend, Number,
|
|
|
|
RegistryKey,
|
2020-05-21 19:35:03 -04:00
|
|
|
};
|
2021-02-19 06:48:56 -05:00
|
|
|
use crate::userdata::{
|
2021-04-27 13:31:57 -04:00
|
|
|
AnyUserData, MetaMethod, UserData, UserDataCell, UserDataFields, UserDataMethods,
|
2021-02-19 06:48:56 -05:00
|
|
|
};
|
2019-09-27 12:27:37 -04:00
|
|
|
use crate::util::{
|
2021-06-19 19:24:53 -04:00
|
|
|
self, assert_stack, callback_error, check_stack, get_destructed_userdata_metatable,
|
2021-07-08 19:05:29 -04:00
|
|
|
get_gc_metatable, get_gc_userdata, get_main_state, get_userdata, init_error_registry,
|
|
|
|
init_gc_metatable, init_userdata_metatable, pop_error, protect_lua, push_gc_userdata,
|
|
|
|
push_string, push_table, push_userdata, rawset_field, safe_pcall, safe_xpcall, StackGuard,
|
|
|
|
WrappedFailure,
|
2018-08-05 09:51:39 -04:00
|
|
|
};
|
2019-09-27 12:27:37 -04:00
|
|
|
use crate::value::{FromLua, FromLuaMulti, MultiValue, Nil, ToLua, ToLuaMulti, Value};
|
2017-05-21 19:50:59 -04:00
|
|
|
|
2021-05-31 18:33:44 -04:00
|
|
|
#[cfg(not(feature = "send"))]
|
|
|
|
use std::rc::Rc;
|
|
|
|
|
2020-04-17 17:38:01 -04:00
|
|
|
#[cfg(feature = "async")]
|
|
|
|
use {
|
2021-06-30 11:50:50 -04:00
|
|
|
crate::types::{AsyncCallback, AsyncCallbackUpvalue, AsyncPollUpvalue},
|
2020-04-19 11:51:35 -04:00
|
|
|
futures_core::{
|
|
|
|
future::{Future, LocalBoxFuture},
|
2020-04-17 17:38:01 -04:00
|
|
|
task::{Context, Poll, Waker},
|
|
|
|
},
|
2020-04-19 11:51:35 -04:00
|
|
|
futures_task::noop_waker,
|
|
|
|
futures_util::future::{self, TryFutureExt},
|
2020-04-17 17:38:01 -04:00
|
|
|
};
|
|
|
|
|
2020-12-29 15:02:03 -05:00
|
|
|
#[cfg(feature = "serialize")]
|
2021-04-10 19:07:04 -04:00
|
|
|
use serde::Serialize;
|
2020-12-29 15:02:03 -05:00
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Top level Lua struct which holds the Lua state itself.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub struct Lua {
|
2017-09-15 16:03:14 -04:00
|
|
|
pub(crate) state: *mut ffi::lua_State,
|
2020-06-07 10:16:12 -04:00
|
|
|
main_state: Option<*mut ffi::lua_State>,
|
2021-07-08 12:32:20 -04:00
|
|
|
extra: *mut ExtraData,
|
2019-10-15 11:39:30 -04:00
|
|
|
ephemeral: bool,
|
2020-05-10 11:56:19 -04:00
|
|
|
safe: bool,
|
2018-03-28 01:09:51 -04:00
|
|
|
// Lua has lots of interior mutability, should not be RefUnwindSafe
|
2019-09-27 12:27:37 -04:00
|
|
|
_no_ref_unwind_safe: PhantomData<UnsafeCell<()>>,
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
|
2021-05-03 17:17:34 -04:00
|
|
|
// Data associated with the Lua.
|
2019-10-15 07:58:02 -04:00
|
|
|
struct ExtraData {
|
|
|
|
registered_userdata: HashMap<TypeId, c_int>,
|
2021-04-16 17:01:55 -04:00
|
|
|
registered_userdata_mt: HashSet<isize>,
|
2020-05-05 21:32:05 -04:00
|
|
|
registry_unref_list: Arc<Mutex<Option<Vec<c_int>>>>,
|
2019-10-15 07:58:02 -04:00
|
|
|
|
2020-12-22 16:17:06 -05:00
|
|
|
libs: StdLib,
|
2020-05-08 19:18:48 -04:00
|
|
|
mem_info: *mut MemoryInfo,
|
2021-05-03 07:40:14 -04:00
|
|
|
safe: bool, // Same as in the Lua struct
|
2020-05-08 19:18:48 -04:00
|
|
|
|
2019-10-15 07:58:02 -04:00
|
|
|
ref_thread: *mut ffi::lua_State,
|
|
|
|
ref_stack_size: c_int,
|
2021-05-02 18:26:02 -04:00
|
|
|
ref_stack_top: c_int,
|
2019-10-15 07:58:02 -04:00
|
|
|
ref_free: Vec<c_int>,
|
2020-05-21 19:35:03 -04:00
|
|
|
|
2021-07-08 19:05:29 -04:00
|
|
|
// Vec of preallocated WrappedFailure enums
|
2021-06-19 19:24:53 -04:00
|
|
|
// Used for callback optimization
|
2021-07-08 19:05:29 -04:00
|
|
|
prealloc_wrapped_failures: Vec<c_int>,
|
2021-06-19 19:24:53 -04:00
|
|
|
|
2020-05-21 19:35:03 -04:00
|
|
|
hook_callback: Option<HookCallback>,
|
2019-10-15 07:58:02 -04:00
|
|
|
}
|
|
|
|
|
2020-05-16 10:13:38 -04:00
|
|
|
#[cfg_attr(any(feature = "lua51", feature = "luajit"), allow(dead_code))]
|
2020-05-08 19:18:48 -04:00
|
|
|
struct MemoryInfo {
|
|
|
|
used_memory: isize,
|
|
|
|
memory_limit: isize,
|
|
|
|
}
|
|
|
|
|
2020-05-08 07:42:40 -04:00
|
|
|
/// Mode of the Lua garbage collector (GC).
|
|
|
|
///
|
|
|
|
/// In Lua 5.4 GC can work in two modes: incremental and generational.
|
|
|
|
/// Previous Lua versions support only incremental GC.
|
|
|
|
///
|
2021-05-02 05:38:33 -04:00
|
|
|
/// More information can be found in the Lua 5.x [documentation].
|
2020-05-08 07:42:40 -04:00
|
|
|
///
|
2021-05-02 05:38:33 -04:00
|
|
|
/// [documentation]: https://www.lua.org/manual/5.4/manual.html#2.5
|
2021-06-16 19:11:58 -04:00
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
2020-05-08 07:42:40 -04:00
|
|
|
pub enum GCMode {
|
|
|
|
Incremental,
|
2020-05-13 21:12:22 -04:00
|
|
|
/// Requires `feature = "lua54"`
|
|
|
|
#[cfg(any(feature = "lua54", doc))]
|
2020-05-08 07:42:40 -04:00
|
|
|
Generational,
|
|
|
|
}
|
2020-05-05 21:32:05 -04:00
|
|
|
|
2021-05-10 14:53:38 -04:00
|
|
|
/// Controls Lua interpreter behavior such as Rust panics handling.
|
2021-05-03 16:16:42 -04:00
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
#[non_exhaustive]
|
|
|
|
pub struct LuaOptions {
|
|
|
|
/// Catch Rust panics when using [`pcall`]/[`xpcall`].
|
|
|
|
///
|
|
|
|
/// If disabled, wraps these functions and automatically resumes panic if found.
|
|
|
|
/// Also in Lua 5.1 adds ability to provide arguments to [`xpcall`] similar to Lua >= 5.2.
|
|
|
|
///
|
|
|
|
/// If enabled, keeps [`pcall`]/[`xpcall`] unmodified.
|
2021-05-10 14:53:38 -04:00
|
|
|
/// Panics are still automatically resumed if returned to the Rust side.
|
2021-05-03 16:16:42 -04:00
|
|
|
///
|
|
|
|
/// Default: **true**
|
|
|
|
///
|
|
|
|
/// [`pcall`]: https://www.lua.org/manual/5.3/manual.html#pdf-pcall
|
|
|
|
/// [`xpcall`]: https://www.lua.org/manual/5.3/manual.html#pdf-xpcall
|
|
|
|
pub catch_rust_panics: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for LuaOptions {
|
|
|
|
fn default() -> Self {
|
|
|
|
LuaOptions {
|
|
|
|
catch_rust_panics: true,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl LuaOptions {
|
2021-05-10 14:53:38 -04:00
|
|
|
/// Returns a new instance of `LuaOptions` with default parameters.
|
2021-05-03 16:16:42 -04:00
|
|
|
pub fn new() -> Self {
|
|
|
|
Self::default()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sets [`catch_rust_panics`] option.
|
|
|
|
///
|
|
|
|
/// [`catch_rust_panics`]: #structfield.catch_rust_panics
|
|
|
|
pub fn catch_rust_panics(mut self, enabled: bool) -> Self {
|
|
|
|
self.catch_rust_panics = enabled;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-08 10:37:18 -04:00
|
|
|
#[cfg(feature = "async")]
|
2021-07-08 13:40:14 -04:00
|
|
|
pub(crate) static ASYNC_POLL_PENDING: u8 = 0;
|
2020-04-17 17:38:01 -04:00
|
|
|
#[cfg(feature = "async")]
|
|
|
|
pub(crate) static WAKER_REGISTRY_KEY: u8 = 0;
|
2021-07-08 13:40:14 -04:00
|
|
|
pub(crate) static EXTRA_REGISTRY_KEY: u8 = 0;
|
2018-02-06 20:23:16 -05:00
|
|
|
|
2020-05-13 21:12:22 -04:00
|
|
|
/// Requires `feature = "send"`
|
2020-05-08 07:42:40 -04:00
|
|
|
#[cfg(feature = "send")]
|
2020-12-29 20:43:00 -05:00
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "send")))]
|
2020-05-08 07:42:40 -04:00
|
|
|
unsafe impl Send for Lua {}
|
|
|
|
|
2019-10-15 11:39:30 -04:00
|
|
|
impl Drop for Lua {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe {
|
|
|
|
if !self.ephemeral {
|
2021-07-08 12:32:20 -04:00
|
|
|
let extra = &mut *self.extra;
|
2021-07-08 19:05:29 -04:00
|
|
|
for index in extra.prealloc_wrapped_failures.clone() {
|
2021-06-19 19:24:53 -04:00
|
|
|
ffi::lua_pushnil(extra.ref_thread);
|
|
|
|
ffi::lua_replace(extra.ref_thread, index);
|
|
|
|
extra.ref_free.push(index);
|
|
|
|
}
|
2019-10-15 11:39:30 -04:00
|
|
|
mlua_debug_assert!(
|
2021-05-02 18:26:02 -04:00
|
|
|
ffi::lua_gettop(extra.ref_thread) == extra.ref_stack_top
|
|
|
|
&& extra.ref_stack_top as usize == extra.ref_free.len(),
|
2019-10-15 11:39:30 -04:00
|
|
|
"reference leak detected"
|
|
|
|
);
|
2021-07-08 12:32:20 -04:00
|
|
|
*mlua_expect!(extra.registry_unref_list.lock(), "unref list poisoned") = None;
|
2021-04-09 07:05:03 -04:00
|
|
|
ffi::lua_close(mlua_expect!(self.main_state, "main_state is null"));
|
2020-05-08 19:18:48 -04:00
|
|
|
if !extra.mem_info.is_null() {
|
|
|
|
Box::from_raw(extra.mem_info);
|
|
|
|
}
|
2021-07-08 12:32:20 -04:00
|
|
|
Box::from_raw(extra);
|
2019-10-15 11:39:30 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-03 08:05:43 -04:00
|
|
|
impl fmt::Debug for Lua {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "Lua({:p})", self.state)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-21 19:50:59 -04:00
|
|
|
impl Lua {
|
2021-05-02 05:38:33 -04:00
|
|
|
/// Creates a new Lua state and loads the **safe** subset of the standard libraries.
|
2020-05-10 11:56:19 -04:00
|
|
|
///
|
2020-05-12 18:34:42 -04:00
|
|
|
/// # Safety
|
2020-05-16 18:38:04 -04:00
|
|
|
/// The created Lua state would have _some_ safety guarantees and would not allow to load unsafe
|
2020-05-10 11:56:19 -04:00
|
|
|
/// standard libraries or C modules.
|
2021-05-02 05:38:33 -04:00
|
|
|
///
|
|
|
|
/// See [`StdLib`] documentation for a list of unsafe modules that cannot be loaded.
|
|
|
|
///
|
|
|
|
/// [`StdLib`]: struct.StdLib.html
|
2020-05-12 18:34:42 -04:00
|
|
|
#[allow(clippy::new_without_default)]
|
2019-10-14 17:21:30 -04:00
|
|
|
pub fn new() -> Lua {
|
2020-05-10 11:56:19 -04:00
|
|
|
mlua_expect!(
|
2021-05-03 16:16:42 -04:00
|
|
|
Self::new_with(StdLib::ALL_SAFE, LuaOptions::default()),
|
2020-05-10 11:56:19 -04:00
|
|
|
"can't create new safe Lua state"
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Creates a new Lua state and loads all the standard libraries.
|
|
|
|
///
|
2020-05-12 18:34:42 -04:00
|
|
|
/// # Safety
|
2020-05-10 11:56:19 -04:00
|
|
|
/// The created Lua state would not have safety guarantees and would allow to load C modules.
|
|
|
|
pub unsafe fn unsafe_new() -> Lua {
|
2021-05-03 16:16:42 -04:00
|
|
|
Self::unsafe_new_with(StdLib::ALL, LuaOptions::default())
|
2019-12-26 17:51:15 -05:00
|
|
|
}
|
|
|
|
|
2020-05-10 11:56:19 -04:00
|
|
|
/// Creates a new Lua state and loads the specified safe subset of the standard libraries.
|
2019-12-26 17:51:15 -05:00
|
|
|
///
|
2021-05-10 14:53:38 -04:00
|
|
|
/// Use the [`StdLib`] flags to specify the libraries you want to load.
|
2019-12-26 17:51:15 -05:00
|
|
|
///
|
2020-05-12 18:34:42 -04:00
|
|
|
/// # Safety
|
2020-05-16 18:38:04 -04:00
|
|
|
/// The created Lua state would have _some_ safety guarantees and would not allow to load unsafe
|
2020-05-10 11:56:19 -04:00
|
|
|
/// standard libraries or C modules.
|
|
|
|
///
|
2021-05-02 05:38:33 -04:00
|
|
|
/// See [`StdLib`] documentation for a list of unsafe modules that cannot be loaded.
|
|
|
|
///
|
2019-12-26 17:51:15 -05:00
|
|
|
/// [`StdLib`]: struct.StdLib.html
|
2021-05-03 16:16:42 -04:00
|
|
|
pub fn new_with(libs: StdLib, options: LuaOptions) -> Result<Lua> {
|
2020-05-10 11:56:19 -04:00
|
|
|
if libs.contains(StdLib::DEBUG) {
|
|
|
|
return Err(Error::SafetyError(
|
|
|
|
"the unsafe `debug` module can't be loaded using safe `new_with`".to_string(),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
#[cfg(feature = "luajit")]
|
|
|
|
{
|
|
|
|
if libs.contains(StdLib::FFI) {
|
|
|
|
return Err(Error::SafetyError(
|
|
|
|
"the unsafe `ffi` module can't be loaded using safe `new_with`".to_string(),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-12 13:00:55 -04:00
|
|
|
let mut lua = unsafe { Self::inner_new(libs, options) };
|
2020-05-10 11:56:19 -04:00
|
|
|
|
2020-12-22 16:17:06 -05:00
|
|
|
if libs.contains(StdLib::PACKAGE) {
|
|
|
|
mlua_expect!(lua.disable_c_modules(), "Error during disabling C modules");
|
|
|
|
}
|
2020-05-10 11:56:19 -04:00
|
|
|
lua.safe = true;
|
2021-07-08 12:32:20 -04:00
|
|
|
unsafe { (*lua.extra).safe = true };
|
2020-05-10 11:56:19 -04:00
|
|
|
|
|
|
|
Ok(lua)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Creates a new Lua state and loads the specified subset of the standard libraries.
|
|
|
|
///
|
2021-05-10 14:53:38 -04:00
|
|
|
/// Use the [`StdLib`] flags to specify the libraries you want to load.
|
2020-05-10 11:56:19 -04:00
|
|
|
///
|
2020-05-12 18:34:42 -04:00
|
|
|
/// # Safety
|
2021-05-02 05:38:33 -04:00
|
|
|
/// The created Lua state will not have safety guarantees and allow to load C modules.
|
2020-05-10 11:56:19 -04:00
|
|
|
///
|
|
|
|
/// [`StdLib`]: struct.StdLib.html
|
2021-05-03 16:16:42 -04:00
|
|
|
pub unsafe fn unsafe_new_with(libs: StdLib, options: LuaOptions) -> Lua {
|
2021-06-12 13:00:55 -04:00
|
|
|
ffi::keep_lua_symbols();
|
|
|
|
Self::inner_new(libs, options)
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe fn inner_new(libs: StdLib, options: LuaOptions) -> Lua {
|
2020-05-16 10:13:38 -04:00
|
|
|
#[cfg_attr(any(feature = "lua51", feature = "luajit"), allow(dead_code))]
|
2020-05-08 19:18:48 -04:00
|
|
|
unsafe extern "C" fn allocator(
|
|
|
|
extra_data: *mut c_void,
|
|
|
|
ptr: *mut c_void,
|
|
|
|
osize: usize,
|
|
|
|
nsize: usize,
|
|
|
|
) -> *mut c_void {
|
2020-05-16 10:13:38 -04:00
|
|
|
use std::alloc;
|
|
|
|
|
2020-05-08 19:18:48 -04:00
|
|
|
let mem_info = &mut *(extra_data as *mut MemoryInfo);
|
|
|
|
|
|
|
|
if nsize == 0 {
|
|
|
|
// Free memory
|
|
|
|
if !ptr.is_null() {
|
|
|
|
let layout =
|
|
|
|
alloc::Layout::from_size_align_unchecked(osize, ffi::SYS_MIN_ALIGN);
|
|
|
|
alloc::dealloc(ptr as *mut u8, layout);
|
|
|
|
mem_info.used_memory -= osize as isize;
|
|
|
|
}
|
|
|
|
return ptr::null_mut();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Are we fit to the memory limits?
|
|
|
|
let mut mem_diff = nsize as isize;
|
|
|
|
if !ptr.is_null() {
|
|
|
|
mem_diff -= osize as isize;
|
|
|
|
}
|
|
|
|
let new_used_memory = mem_info.used_memory + mem_diff;
|
|
|
|
if mem_info.memory_limit > 0 && new_used_memory > mem_info.memory_limit {
|
|
|
|
return ptr::null_mut();
|
|
|
|
}
|
|
|
|
|
|
|
|
let new_layout = alloc::Layout::from_size_align_unchecked(nsize, ffi::SYS_MIN_ALIGN);
|
|
|
|
|
|
|
|
if ptr.is_null() {
|
|
|
|
// Allocate new memory
|
|
|
|
let new_ptr = alloc::alloc(new_layout) as *mut c_void;
|
|
|
|
if !new_ptr.is_null() {
|
|
|
|
mem_info.used_memory += mem_diff;
|
|
|
|
}
|
|
|
|
return new_ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reallocate memory
|
|
|
|
let old_layout = alloc::Layout::from_size_align_unchecked(osize, ffi::SYS_MIN_ALIGN);
|
|
|
|
let new_ptr = alloc::realloc(ptr as *mut u8, old_layout, nsize) as *mut c_void;
|
|
|
|
|
|
|
|
if !new_ptr.is_null() {
|
|
|
|
mem_info.used_memory += mem_diff;
|
|
|
|
} else if !ptr.is_null() && nsize < osize {
|
2021-05-10 14:53:38 -04:00
|
|
|
// Should not happen
|
2020-05-08 19:18:48 -04:00
|
|
|
alloc::handle_alloc_error(new_layout);
|
|
|
|
}
|
|
|
|
|
|
|
|
new_ptr
|
|
|
|
}
|
|
|
|
|
2020-05-16 10:13:38 -04:00
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
2020-05-10 11:56:19 -04:00
|
|
|
let mem_info = Box::into_raw(Box::new(MemoryInfo {
|
|
|
|
used_memory: 0,
|
|
|
|
memory_limit: 0,
|
|
|
|
}));
|
2019-12-26 17:51:15 -05:00
|
|
|
|
2020-05-16 10:13:38 -04:00
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
2020-05-10 11:56:19 -04:00
|
|
|
let state = ffi::lua_newstate(allocator, mem_info as *mut c_void);
|
2020-05-16 10:13:38 -04:00
|
|
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
|
|
|
let state = ffi::luaL_newstate();
|
2019-10-14 17:21:30 -04:00
|
|
|
|
2021-06-16 17:13:11 -04:00
|
|
|
ffi::luaL_requiref(state, cstr!("_G"), ffi::luaopen_base, 1);
|
2020-05-10 11:56:19 -04:00
|
|
|
ffi::lua_pop(state, 1);
|
2020-05-05 08:03:28 -04:00
|
|
|
|
2020-05-10 11:56:19 -04:00
|
|
|
let mut lua = Lua::init_from_ptr(state);
|
|
|
|
lua.ephemeral = false;
|
2021-07-08 12:32:20 -04:00
|
|
|
|
|
|
|
let extra = &mut *lua.extra;
|
|
|
|
|
2021-07-08 17:53:53 -04:00
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
|
|
|
{
|
2021-07-08 12:32:20 -04:00
|
|
|
extra.mem_info = mem_info;
|
2020-05-16 10:13:38 -04:00
|
|
|
}
|
2020-05-05 08:03:28 -04:00
|
|
|
|
2020-05-10 11:56:19 -04:00
|
|
|
mlua_expect!(
|
2021-04-09 07:05:03 -04:00
|
|
|
load_from_std_lib(state, libs),
|
2020-05-10 11:56:19 -04:00
|
|
|
"Error during loading standard libraries"
|
|
|
|
);
|
2021-07-08 12:32:20 -04:00
|
|
|
extra.libs |= libs;
|
2020-05-10 11:56:19 -04:00
|
|
|
|
2021-05-03 16:16:42 -04:00
|
|
|
if !options.catch_rust_panics {
|
|
|
|
mlua_expect!(
|
|
|
|
(|| -> Result<()> {
|
|
|
|
let _sg = StackGuard::new(lua.state);
|
|
|
|
|
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
|
|
|
ffi::lua_rawgeti(lua.state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS);
|
|
|
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
|
|
|
ffi::lua_pushvalue(lua.state, ffi::LUA_GLOBALSINDEX);
|
|
|
|
|
2021-06-16 17:13:11 -04:00
|
|
|
ffi::lua_pushcfunction(lua.state, safe_pcall);
|
|
|
|
rawset_field(lua.state, -2, "pcall")?;
|
2021-05-03 16:16:42 -04:00
|
|
|
|
2021-06-16 17:13:11 -04:00
|
|
|
ffi::lua_pushcfunction(lua.state, safe_xpcall);
|
|
|
|
rawset_field(lua.state, -2, "xpcall")?;
|
2021-05-03 16:16:42 -04:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
})(),
|
|
|
|
"Error during applying option `catch_rust_panics`"
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2020-05-10 11:56:19 -04:00
|
|
|
lua
|
2019-12-26 17:51:15 -05:00
|
|
|
}
|
|
|
|
|
2020-05-12 18:34:42 -04:00
|
|
|
/// Constructs a new Lua instance from an existing raw state.
|
|
|
|
#[allow(clippy::missing_safety_doc)]
|
2019-09-26 14:17:51 -04:00
|
|
|
pub unsafe fn init_from_ptr(state: *mut ffi::lua_State) -> Lua {
|
2020-06-07 10:16:12 -04:00
|
|
|
let maybe_main_state = get_main_state(state);
|
|
|
|
let main_state = maybe_main_state.unwrap_or(state);
|
2020-05-26 20:15:59 -04:00
|
|
|
let main_state_top = ffi::lua_gettop(main_state);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
2021-05-18 15:07:34 -04:00
|
|
|
if let Some(lua) = Lua::make_from_ptr(state) {
|
|
|
|
return lua;
|
|
|
|
}
|
|
|
|
|
2021-05-02 05:38:33 -04:00
|
|
|
let ref_thread = mlua_expect!(
|
2021-04-09 07:05:03 -04:00
|
|
|
(|state| {
|
2021-06-16 17:13:11 -04:00
|
|
|
init_error_registry(state)?;
|
2021-05-02 05:38:33 -04:00
|
|
|
|
2020-04-17 17:38:01 -04:00
|
|
|
// Create the internal metatables and place them in the registry
|
2019-10-15 07:58:02 -04:00
|
|
|
// to prevent them from being garbage collected.
|
2019-09-26 14:17:51 -04:00
|
|
|
|
2021-07-08 17:57:54 -04:00
|
|
|
init_gc_metatable::<Callback>(state, None)?;
|
|
|
|
init_gc_metatable::<CallbackUpvalue>(state, None)?;
|
2020-04-17 17:38:01 -04:00
|
|
|
#[cfg(feature = "async")]
|
|
|
|
{
|
2021-07-08 17:57:54 -04:00
|
|
|
init_gc_metatable::<AsyncCallback>(state, None)?;
|
|
|
|
init_gc_metatable::<AsyncCallbackUpvalue>(state, None)?;
|
|
|
|
init_gc_metatable::<AsyncPollUpvalue>(state, None)?;
|
|
|
|
init_gc_metatable::<Option<Waker>>(state, None)?;
|
2021-05-02 08:04:02 -04:00
|
|
|
|
|
|
|
// Create empty Waker slot
|
2021-07-08 13:40:14 -04:00
|
|
|
push_gc_userdata::<Option<Waker>>(state, None)?;
|
2021-07-08 13:41:10 -04:00
|
|
|
protect_lua(state, 1, 0, |state| {
|
2021-07-08 17:53:53 -04:00
|
|
|
let waker_key = &WAKER_REGISTRY_KEY as *const u8 as *const c_void;
|
2021-06-16 17:13:11 -04:00
|
|
|
ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, waker_key);
|
|
|
|
})?;
|
2020-04-17 17:38:01 -04:00
|
|
|
}
|
2019-10-15 07:58:02 -04:00
|
|
|
|
2020-12-12 15:37:17 -05:00
|
|
|
// Init serde metatables
|
|
|
|
#[cfg(feature = "serialize")]
|
2021-04-09 07:05:03 -04:00
|
|
|
crate::serde::init_metatables(state)?;
|
2020-12-12 15:37:17 -05:00
|
|
|
|
2019-09-27 12:27:37 -04:00
|
|
|
// Create ref stack thread and place it in the registry to prevent it from being garbage
|
|
|
|
// collected.
|
2021-07-08 13:41:10 -04:00
|
|
|
let ref_thread = protect_lua(state, 0, 0, |state| {
|
2021-06-16 17:13:11 -04:00
|
|
|
let thread = ffi::lua_newthread(state);
|
|
|
|
ffi::luaL_ref(state, ffi::LUA_REGISTRYINDEX);
|
|
|
|
thread
|
|
|
|
})?;
|
2021-04-09 07:05:03 -04:00
|
|
|
|
2021-05-02 05:38:33 -04:00
|
|
|
Ok::<_, Error>(ref_thread)
|
2021-04-09 07:05:03 -04:00
|
|
|
})(main_state),
|
2019-09-27 12:27:37 -04:00
|
|
|
"Error during Lua construction",
|
|
|
|
);
|
2019-09-26 14:17:51 -04:00
|
|
|
|
2019-10-15 07:58:02 -04:00
|
|
|
// Create ExtraData
|
2019-09-26 14:17:51 -04:00
|
|
|
|
2021-07-08 12:32:20 -04:00
|
|
|
let extra = Box::into_raw(Box::new(ExtraData {
|
2019-09-26 14:17:51 -04:00
|
|
|
registered_userdata: HashMap::new(),
|
2021-04-16 17:01:55 -04:00
|
|
|
registered_userdata_mt: HashSet::new(),
|
2020-05-05 21:32:05 -04:00
|
|
|
registry_unref_list: Arc::new(Mutex::new(Some(Vec::new()))),
|
2019-09-26 14:17:51 -04:00
|
|
|
ref_thread,
|
2020-12-22 16:17:06 -05:00
|
|
|
libs: StdLib::NONE,
|
2020-05-08 19:18:48 -04:00
|
|
|
mem_info: ptr::null_mut(),
|
2021-05-03 07:40:14 -04:00
|
|
|
safe: false,
|
2019-09-26 14:17:51 -04:00
|
|
|
// We need 1 extra stack space to move values in and out of the ref stack.
|
|
|
|
ref_stack_size: ffi::LUA_MINSTACK - 1,
|
2021-05-02 18:26:02 -04:00
|
|
|
ref_stack_top: 0,
|
2019-09-26 14:17:51 -04:00
|
|
|
ref_free: Vec::new(),
|
2021-07-08 19:05:29 -04:00
|
|
|
prealloc_wrapped_failures: Vec::new(),
|
2020-05-21 19:35:03 -04:00
|
|
|
hook_callback: None,
|
2019-09-26 14:17:51 -04:00
|
|
|
}));
|
|
|
|
|
2021-07-08 12:32:20 -04:00
|
|
|
ffi::lua_pushlightuserdata(main_state, extra as *mut c_void);
|
2020-05-21 19:35:03 -04:00
|
|
|
mlua_expect!(
|
2021-07-08 13:41:10 -04:00
|
|
|
protect_lua(main_state, 1, 0, |state| {
|
2021-07-08 17:53:53 -04:00
|
|
|
let extra_key = &EXTRA_REGISTRY_KEY as *const u8 as *const c_void;
|
2021-06-16 17:13:11 -04:00
|
|
|
ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, extra_key)
|
|
|
|
}),
|
2021-05-18 15:07:34 -04:00
|
|
|
"Error while storing extra data",
|
2020-05-21 19:35:03 -04:00
|
|
|
);
|
|
|
|
|
2019-10-01 11:11:12 -04:00
|
|
|
mlua_debug_assert!(
|
2019-09-30 17:14:58 -04:00
|
|
|
ffi::lua_gettop(main_state) == main_state_top,
|
2019-09-27 12:38:24 -04:00
|
|
|
"stack leak during creation"
|
|
|
|
);
|
2019-09-30 17:14:58 -04:00
|
|
|
assert_stack(main_state, ffi::LUA_MINSTACK);
|
2019-09-26 14:17:51 -04:00
|
|
|
|
|
|
|
Lua {
|
|
|
|
state,
|
2020-06-07 10:16:12 -04:00
|
|
|
main_state: maybe_main_state,
|
2020-05-12 18:34:42 -04:00
|
|
|
extra,
|
2019-10-15 11:39:30 -04:00
|
|
|
ephemeral: true,
|
2020-05-10 11:56:19 -04:00
|
|
|
safe: false,
|
2019-09-27 12:27:37 -04:00
|
|
|
_no_ref_unwind_safe: PhantomData,
|
2019-09-26 14:17:51 -04:00
|
|
|
}
|
2017-10-28 23:46:24 -04:00
|
|
|
}
|
|
|
|
|
2020-05-10 11:56:19 -04:00
|
|
|
/// Loads the specified subset of the standard libraries into an existing Lua state.
|
|
|
|
///
|
2021-05-10 14:53:38 -04:00
|
|
|
/// Use the [`StdLib`] flags to specify the libraries you want to load.
|
2020-05-10 11:56:19 -04:00
|
|
|
///
|
|
|
|
/// [`StdLib`]: struct.StdLib.html
|
|
|
|
pub fn load_from_std_lib(&self, libs: StdLib) -> Result<()> {
|
|
|
|
if self.safe && libs.contains(StdLib::DEBUG) {
|
|
|
|
return Err(Error::SafetyError(
|
|
|
|
"the unsafe `debug` module can't be loaded in safe mode".to_string(),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
#[cfg(feature = "luajit")]
|
|
|
|
{
|
|
|
|
if self.safe && libs.contains(StdLib::FFI) {
|
|
|
|
return Err(Error::SafetyError(
|
|
|
|
"the unsafe `ffi` module can't be loaded in safe mode".to_string(),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-07 10:16:12 -04:00
|
|
|
let state = self.main_state.unwrap_or(self.state);
|
2021-04-09 07:05:03 -04:00
|
|
|
let res = unsafe { load_from_std_lib(state, libs) };
|
2020-12-22 16:17:06 -05:00
|
|
|
|
|
|
|
// If `package` library loaded into a safe lua state then disable C modules
|
2021-07-08 12:32:20 -04:00
|
|
|
let extra = unsafe { &mut *self.extra };
|
|
|
|
let curr_libs = extra.libs;
|
2020-12-22 16:17:06 -05:00
|
|
|
if self.safe && (curr_libs ^ (curr_libs | libs)).contains(StdLib::PACKAGE) {
|
|
|
|
mlua_expect!(self.disable_c_modules(), "Error during disabling C modules");
|
2020-05-10 11:56:19 -04:00
|
|
|
}
|
2021-07-08 12:32:20 -04:00
|
|
|
extra.libs |= libs;
|
2020-12-22 16:17:06 -05:00
|
|
|
|
|
|
|
res
|
2020-05-10 11:56:19 -04:00
|
|
|
}
|
|
|
|
|
2021-07-04 18:51:51 -04:00
|
|
|
/// Calls the Lua function `func` with the string `modname` as an argument, sets
|
|
|
|
/// the call result to `package.loaded[modname]` and returns copy of the result.
|
|
|
|
///
|
|
|
|
/// If `package.loaded[modname]` value is not nil, returns copy of the value without
|
|
|
|
/// calling the function.
|
|
|
|
///
|
|
|
|
/// If the function does not return a non-nil value then this method assigns true to
|
|
|
|
/// `package.loaded[modname]`.
|
|
|
|
///
|
|
|
|
/// Behavior is similar to Lua's [`require`] function.
|
|
|
|
///
|
|
|
|
/// [`require`]: https://www.lua.org/manual/5.3/manual.html#pdf-require
|
|
|
|
pub fn load_from_function<'lua, S, T>(
|
|
|
|
&'lua self,
|
|
|
|
modname: &S,
|
|
|
|
func: Function<'lua>,
|
|
|
|
) -> Result<T>
|
|
|
|
where
|
|
|
|
S: AsRef<[u8]> + ?Sized,
|
|
|
|
T: FromLua<'lua>,
|
|
|
|
{
|
|
|
|
unsafe {
|
|
|
|
let _sg = StackGuard::new(self.state);
|
|
|
|
check_stack(self.state, 3)?;
|
|
|
|
|
2021-07-08 13:41:10 -04:00
|
|
|
protect_lua(self.state, 0, 1, |state| {
|
2021-07-04 18:51:51 -04:00
|
|
|
ffi::luaL_getsubtable(state, ffi::LUA_REGISTRYINDEX, cstr!("_LOADED"));
|
|
|
|
})?;
|
|
|
|
let loaded = Table(self.pop_ref());
|
|
|
|
|
|
|
|
let modname = self.create_string(modname)?;
|
|
|
|
let value = match loaded.raw_get(modname.clone())? {
|
|
|
|
Value::Nil => {
|
|
|
|
let result = match func.call(modname.clone())? {
|
|
|
|
Value::Nil => Value::Boolean(true),
|
|
|
|
res => res,
|
|
|
|
};
|
|
|
|
loaded.raw_set(modname, result.clone())?;
|
|
|
|
result
|
|
|
|
}
|
|
|
|
res => res,
|
|
|
|
};
|
|
|
|
T::from_lua(value, self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-10 11:56:19 -04:00
|
|
|
/// Consumes and leaks `Lua` object, returning a static reference `&'static Lua`.
|
|
|
|
///
|
|
|
|
/// This function is useful when the `Lua` object is supposed to live for the remainder
|
|
|
|
/// of the program's life.
|
|
|
|
/// In particular in asynchronous context this will allow to spawn Lua tasks to execute
|
|
|
|
/// in background.
|
|
|
|
///
|
|
|
|
/// Dropping the returned reference will cause a memory leak. If this is not acceptable,
|
|
|
|
/// the reference should first be wrapped with the [`Lua::from_static`] function producing a `Lua`.
|
|
|
|
/// This `Lua` object can then be dropped which will properly release the allocated memory.
|
|
|
|
///
|
|
|
|
/// [`Lua::from_static`]: #method.from_static
|
|
|
|
pub fn into_static(self) -> &'static Self {
|
|
|
|
Box::leak(Box::new(self))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Constructs a `Lua` from a static reference to it.
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
/// This function is unsafe because improper use may lead to memory problems or undefined behavior.
|
|
|
|
pub unsafe fn from_static(lua: &'static Lua) -> Self {
|
|
|
|
*Box::from_raw(lua as *const Lua as *mut Lua)
|
|
|
|
}
|
|
|
|
|
2019-10-01 13:11:51 -04:00
|
|
|
// Executes module entrypoint function, which returns only one Value.
|
|
|
|
// The returned value then pushed to the Lua stack.
|
|
|
|
#[doc(hidden)]
|
2021-06-16 19:11:58 -04:00
|
|
|
#[cfg(not(tarpaulin_include))]
|
2019-10-01 13:11:51 -04:00
|
|
|
pub fn entrypoint1<'lua, 'callback, R, F>(&'lua self, func: F) -> Result<c_int>
|
|
|
|
where
|
2020-05-04 06:56:42 -04:00
|
|
|
'lua: 'callback,
|
2019-10-01 13:11:51 -04:00
|
|
|
R: ToLua<'callback>,
|
2020-05-06 08:18:04 -04:00
|
|
|
F: 'static + MaybeSend + Fn(&'callback Lua) -> Result<R>,
|
2019-10-01 13:11:51 -04:00
|
|
|
{
|
|
|
|
let cb = self.create_callback(Box::new(move |lua, _| func(lua)?.to_lua_multi(lua)))?;
|
2021-06-13 18:28:41 -04:00
|
|
|
let res = cb.call(());
|
|
|
|
unsafe {
|
|
|
|
check_stack(self.state, 2)?;
|
|
|
|
match res {
|
|
|
|
Ok(res) => self.push_value(res)?,
|
|
|
|
Err(err) => {
|
|
|
|
self.push_value(Value::Error(err))?;
|
|
|
|
// This longjmp is undesired, but we cannot wrap it to a C
|
|
|
|
ffi::lua_error(self.state)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2021-06-13 17:38:51 -04:00
|
|
|
Ok(1)
|
2019-10-01 13:11:51 -04:00
|
|
|
}
|
|
|
|
|
2020-05-21 19:35:03 -04:00
|
|
|
/// Sets a 'hook' function that will periodically be called as Lua code executes.
|
|
|
|
///
|
|
|
|
/// When exactly the hook function is called depends on the contents of the `triggers`
|
|
|
|
/// parameter, see [`HookTriggers`] for more details.
|
|
|
|
///
|
|
|
|
/// The provided hook function can error, and this error will be propagated through the Lua code
|
2021-05-02 05:38:33 -04:00
|
|
|
/// that was executing at the time the hook was triggered. This can be used to implement a
|
2020-05-21 19:35:03 -04:00
|
|
|
/// limited form of execution limits by setting [`HookTriggers.every_nth_instruction`] and
|
|
|
|
/// erroring once an instruction limit has been reached.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// Shows each line number of code being executed by the Lua interpreter.
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use mlua::{Lua, HookTriggers, Result};
|
|
|
|
/// # fn main() -> Result<()> {
|
|
|
|
/// let lua = Lua::new();
|
|
|
|
/// lua.set_hook(HookTriggers {
|
|
|
|
/// every_line: true, ..Default::default()
|
|
|
|
/// }, |_lua, debug| {
|
|
|
|
/// println!("line {}", debug.curr_line());
|
|
|
|
/// Ok(())
|
2020-06-07 10:16:12 -04:00
|
|
|
/// })?;
|
2020-05-21 19:35:03 -04:00
|
|
|
///
|
|
|
|
/// lua.load(r#"
|
|
|
|
/// local x = 2 + 3
|
|
|
|
/// local y = x * 63
|
|
|
|
/// local z = string.len(x..", "..y)
|
|
|
|
/// "#).exec()
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// [`HookTriggers`]: struct.HookTriggers.html
|
|
|
|
/// [`HookTriggers.every_nth_instruction`]: struct.HookTriggers.html#field.every_nth_instruction
|
2020-06-07 10:16:12 -04:00
|
|
|
pub fn set_hook<F>(&self, triggers: HookTriggers, callback: F) -> Result<()>
|
2020-05-21 19:35:03 -04:00
|
|
|
where
|
|
|
|
F: 'static + MaybeSend + FnMut(&Lua, Debug) -> Result<()>,
|
|
|
|
{
|
2020-06-07 10:16:12 -04:00
|
|
|
let state = self.main_state.ok_or(Error::MainThreadNotAvailable)?;
|
2020-05-21 19:35:03 -04:00
|
|
|
unsafe {
|
2021-07-08 12:32:20 -04:00
|
|
|
(*self.extra).hook_callback = Some(Arc::new(RefCell::new(callback)));
|
2021-06-16 17:13:11 -04:00
|
|
|
ffi::lua_sethook(state, Some(hook_proc), triggers.mask(), triggers.count());
|
2020-05-21 19:35:03 -04:00
|
|
|
}
|
2020-06-07 10:16:12 -04:00
|
|
|
Ok(())
|
2020-05-21 19:35:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Remove any hook previously set by `set_hook`. This function has no effect if a hook was not
|
|
|
|
/// previously set.
|
|
|
|
pub fn remove_hook(&self) {
|
2020-06-07 10:16:12 -04:00
|
|
|
// If main_state is not available, then sethook wasn't called.
|
|
|
|
let state = match self.main_state {
|
|
|
|
Some(state) => state,
|
|
|
|
None => return,
|
|
|
|
};
|
2020-05-21 19:35:03 -04:00
|
|
|
unsafe {
|
2021-07-08 12:32:20 -04:00
|
|
|
(*self.extra).hook_callback = None;
|
2020-06-07 10:16:12 -04:00
|
|
|
ffi::lua_sethook(state, None, 0, 0);
|
2020-05-21 19:35:03 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-08 19:18:48 -04:00
|
|
|
/// Returns the amount of memory (in bytes) currently used inside this Lua state.
|
|
|
|
pub fn used_memory(&self) -> usize {
|
2021-07-08 12:32:20 -04:00
|
|
|
unsafe {
|
|
|
|
let state = self.main_state.unwrap_or(self.state);
|
|
|
|
match (*self.extra).mem_info {
|
|
|
|
mem_info if mem_info.is_null() => {
|
|
|
|
// Get data from the Lua GC
|
|
|
|
let used_kbytes = ffi::lua_gc(state, ffi::LUA_GCCOUNT, 0);
|
|
|
|
let used_kbytes_rem = ffi::lua_gc(state, ffi::LUA_GCCOUNTB, 0);
|
|
|
|
(used_kbytes as usize) * 1024 + (used_kbytes_rem as usize)
|
|
|
|
}
|
|
|
|
mem_info => (*mem_info).used_memory as usize,
|
2020-05-08 19:18:48 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-30 07:16:25 -04:00
|
|
|
/// Sets a memory limit (in bytes) on this Lua state.
|
2020-05-08 19:18:48 -04:00
|
|
|
///
|
|
|
|
/// Once an allocation occurs that would pass this memory limit,
|
|
|
|
/// a `Error::MemoryError` is generated instead.
|
|
|
|
/// Returns previous limit (zero means no limit).
|
|
|
|
///
|
|
|
|
/// Does not work on module mode where Lua state is managed externally.
|
2020-05-13 21:12:22 -04:00
|
|
|
///
|
|
|
|
/// Requires `feature = "lua54/lua53/lua52"`
|
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", doc))]
|
2020-05-08 19:18:48 -04:00
|
|
|
pub fn set_memory_limit(&self, memory_limit: usize) -> Result<usize> {
|
|
|
|
unsafe {
|
2021-07-08 12:32:20 -04:00
|
|
|
match (*self.extra).mem_info {
|
|
|
|
mem_info if mem_info.is_null() => Err(Error::MemoryLimitNotAvailable),
|
|
|
|
mem_info => {
|
|
|
|
let prev_limit = (*mem_info).memory_limit as usize;
|
|
|
|
(*mem_info).memory_limit = memory_limit as isize;
|
|
|
|
Ok(prev_limit)
|
|
|
|
}
|
|
|
|
}
|
2020-05-08 19:18:48 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-27 12:27:37 -04:00
|
|
|
/// Returns true if the garbage collector is currently running automatically.
|
2020-05-13 21:12:22 -04:00
|
|
|
///
|
|
|
|
/// Requires `feature = "lua54/lua53/lua52"`
|
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", doc))]
|
2019-09-27 12:27:37 -04:00
|
|
|
pub fn gc_is_running(&self) -> bool {
|
2020-06-07 10:16:12 -04:00
|
|
|
let state = self.main_state.unwrap_or(self.state);
|
|
|
|
unsafe { ffi::lua_gc(state, ffi::LUA_GCISRUNNING, 0) != 0 }
|
2019-09-27 12:27:37 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Stop the Lua GC from running
|
|
|
|
pub fn gc_stop(&self) {
|
2020-06-07 10:16:12 -04:00
|
|
|
let state = self.main_state.unwrap_or(self.state);
|
|
|
|
unsafe { ffi::lua_gc(state, ffi::LUA_GCSTOP, 0) };
|
2019-09-27 12:27:37 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Restarts the Lua GC if it is not running
|
|
|
|
pub fn gc_restart(&self) {
|
2020-06-07 10:16:12 -04:00
|
|
|
let state = self.main_state.unwrap_or(self.state);
|
|
|
|
unsafe { ffi::lua_gc(state, ffi::LUA_GCRESTART, 0) };
|
2019-09-27 12:27:37 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Perform a full garbage-collection cycle.
|
|
|
|
///
|
|
|
|
/// It may be necessary to call this function twice to collect all currently unreachable
|
2021-05-02 05:38:33 -04:00
|
|
|
/// objects. Once to finish the current gc cycle, and once to start and finish the next cycle.
|
2019-09-27 12:27:37 -04:00
|
|
|
pub fn gc_collect(&self) -> Result<()> {
|
2020-06-07 10:16:12 -04:00
|
|
|
let state = self.main_state.unwrap_or(self.state);
|
2021-06-16 17:13:11 -04:00
|
|
|
unsafe {
|
|
|
|
check_stack(state, 3)?;
|
2021-07-08 13:41:10 -04:00
|
|
|
protect_lua(state, 0, 0, |state| {
|
|
|
|
ffi::lua_gc(state, ffi::LUA_GCCOLLECT, 0);
|
|
|
|
})
|
2021-06-16 17:13:11 -04:00
|
|
|
}
|
2019-09-27 12:27:37 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Steps the garbage collector one indivisible step.
|
2017-06-17 21:23:17 -04:00
|
|
|
///
|
2019-09-27 12:27:37 -04:00
|
|
|
/// Returns true if this has finished a collection cycle.
|
|
|
|
pub fn gc_step(&self) -> Result<bool> {
|
|
|
|
self.gc_step_kbytes(0)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Steps the garbage collector as though memory had been allocated.
|
2017-06-17 21:23:17 -04:00
|
|
|
///
|
2021-05-02 05:38:33 -04:00
|
|
|
/// if `kbytes` is 0, then this is the same as calling `gc_step`. Returns true if this step has
|
2019-09-27 12:27:37 -04:00
|
|
|
/// finished a collection cycle.
|
|
|
|
pub fn gc_step_kbytes(&self, kbytes: c_int) -> Result<bool> {
|
2020-06-07 10:16:12 -04:00
|
|
|
let state = self.main_state.unwrap_or(self.state);
|
2021-06-16 17:13:11 -04:00
|
|
|
unsafe {
|
|
|
|
check_stack(state, 3)?;
|
2021-07-08 13:41:10 -04:00
|
|
|
protect_lua(state, 0, 0, |state| {
|
2021-06-16 17:13:11 -04:00
|
|
|
ffi::lua_gc(state, ffi::LUA_GCSTEP, kbytes) != 0
|
|
|
|
})
|
|
|
|
}
|
2019-09-27 12:27:37 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Sets the 'pause' value of the collector.
|
|
|
|
///
|
2021-05-02 05:38:33 -04:00
|
|
|
/// Returns the previous value of 'pause'. More information can be found in the [Lua 5.3
|
2019-09-27 12:27:37 -04:00
|
|
|
/// documentation][lua_doc].
|
|
|
|
///
|
|
|
|
/// [lua_doc]: https://www.lua.org/manual/5.3/manual.html#2.5
|
|
|
|
pub fn gc_set_pause(&self, pause: c_int) -> c_int {
|
2020-06-07 10:16:12 -04:00
|
|
|
let state = self.main_state.unwrap_or(self.state);
|
|
|
|
unsafe { ffi::lua_gc(state, ffi::LUA_GCSETPAUSE, pause) }
|
2019-09-27 12:27:37 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Sets the 'step multiplier' value of the collector.
|
|
|
|
///
|
2021-05-02 05:38:33 -04:00
|
|
|
/// Returns the previous value of the 'step multiplier'. More information can be found in the
|
2020-05-08 07:42:40 -04:00
|
|
|
/// Lua 5.x [documentation][lua_doc].
|
2019-09-27 12:27:37 -04:00
|
|
|
///
|
|
|
|
/// [lua_doc]: https://www.lua.org/manual/5.3/manual.html#2.5
|
|
|
|
pub fn gc_set_step_multiplier(&self, step_multiplier: c_int) -> c_int {
|
2020-06-07 10:16:12 -04:00
|
|
|
let state = self.main_state.unwrap_or(self.state);
|
|
|
|
unsafe { ffi::lua_gc(state, ffi::LUA_GCSETSTEPMUL, step_multiplier) }
|
2019-09-27 12:27:37 -04:00
|
|
|
}
|
|
|
|
|
2020-05-08 07:42:40 -04:00
|
|
|
/// Changes the collector to incremental mode with the given parameters.
|
|
|
|
///
|
|
|
|
/// Returns the previous mode (always `GCMode::Incremental` in Lua < 5.4).
|
|
|
|
/// More information can be found in the Lua 5.x [documentation][lua_doc].
|
|
|
|
///
|
|
|
|
/// [lua_doc]: https://www.lua.org/manual/5.4/manual.html#2.5.1
|
|
|
|
pub fn gc_inc(&self, pause: c_int, step_multiplier: c_int, step_size: c_int) -> GCMode {
|
2020-06-07 10:16:12 -04:00
|
|
|
let state = self.main_state.unwrap_or(self.state);
|
|
|
|
|
2020-05-08 07:42:40 -04:00
|
|
|
#[cfg(any(
|
|
|
|
feature = "lua53",
|
|
|
|
feature = "lua52",
|
|
|
|
feature = "lua51",
|
|
|
|
feature = "luajit"
|
|
|
|
))]
|
|
|
|
{
|
|
|
|
if pause > 0 {
|
2020-06-07 10:16:12 -04:00
|
|
|
unsafe { ffi::lua_gc(state, ffi::LUA_GCSETPAUSE, pause) };
|
2020-05-08 07:42:40 -04:00
|
|
|
}
|
|
|
|
if step_multiplier > 0 {
|
2020-06-07 10:16:12 -04:00
|
|
|
unsafe { ffi::lua_gc(state, ffi::LUA_GCSETSTEPMUL, step_multiplier) };
|
2020-05-08 07:42:40 -04:00
|
|
|
}
|
|
|
|
let _ = step_size; // Ignored
|
2020-05-12 18:34:42 -04:00
|
|
|
GCMode::Incremental
|
2020-05-08 07:42:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "lua54")]
|
2021-05-02 05:38:33 -04:00
|
|
|
let prev_mode =
|
|
|
|
unsafe { ffi::lua_gc(state, ffi::LUA_GCINC, pause, step_multiplier, step_size) };
|
2020-05-08 07:42:40 -04:00
|
|
|
#[cfg(feature = "lua54")]
|
|
|
|
match prev_mode {
|
|
|
|
ffi::LUA_GCINC => GCMode::Incremental,
|
|
|
|
ffi::LUA_GCGEN => GCMode::Generational,
|
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Changes the collector to generational mode with the given parameters.
|
|
|
|
///
|
|
|
|
/// Returns the previous mode. More information about the generational GC
|
|
|
|
/// can be found in the Lua 5.4 [documentation][lua_doc].
|
|
|
|
///
|
2020-05-13 21:12:22 -04:00
|
|
|
/// Requires `feature = "lua54"`
|
|
|
|
///
|
2020-05-08 07:42:40 -04:00
|
|
|
/// [lua_doc]: https://www.lua.org/manual/5.4/manual.html#2.5.2
|
2020-05-13 21:12:22 -04:00
|
|
|
#[cfg(any(feature = "lua54", doc))]
|
2020-05-08 07:42:40 -04:00
|
|
|
pub fn gc_gen(&self, minor_multiplier: c_int, major_multiplier: c_int) -> GCMode {
|
2020-06-07 10:16:12 -04:00
|
|
|
let state = self.main_state.unwrap_or(self.state);
|
|
|
|
let prev_mode =
|
|
|
|
unsafe { ffi::lua_gc(state, ffi::LUA_GCGEN, minor_multiplier, major_multiplier) };
|
2020-05-08 07:42:40 -04:00
|
|
|
match prev_mode {
|
|
|
|
ffi::LUA_GCGEN => GCMode::Generational,
|
|
|
|
ffi::LUA_GCINC => GCMode::Incremental,
|
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-27 12:27:37 -04:00
|
|
|
/// Returns Lua source code as a `Chunk` builder type.
|
|
|
|
///
|
|
|
|
/// In order to actually compile or run the resulting code, you must call [`Chunk::exec`] or
|
2021-05-02 05:38:33 -04:00
|
|
|
/// similar on the returned builder. Code is not even parsed until one of these methods is
|
2019-09-27 12:27:37 -04:00
|
|
|
/// called.
|
|
|
|
///
|
2020-07-24 03:49:37 -04:00
|
|
|
/// If this `Lua` was created with `unsafe_new`, `load` will automatically detect and load
|
|
|
|
/// chunks of either text or binary type, as if passing `bt` mode to `luaL_loadbufferx`.
|
|
|
|
///
|
2019-09-27 12:27:37 -04:00
|
|
|
/// [`Chunk::exec`]: struct.Chunk.html#method.exec
|
|
|
|
pub fn load<'lua, 'a, S>(&'lua self, source: &'a S) -> Chunk<'lua, 'a>
|
2018-10-01 06:00:21 -04:00
|
|
|
where
|
2021-05-05 16:55:49 -04:00
|
|
|
S: AsChunk<'lua> + ?Sized,
|
2018-10-01 06:00:21 -04:00
|
|
|
{
|
2019-09-27 12:27:37 -04:00
|
|
|
Chunk {
|
|
|
|
lua: self,
|
2021-05-05 16:55:49 -04:00
|
|
|
source: source.source(),
|
|
|
|
name: source.name(),
|
|
|
|
env: source.env(self),
|
|
|
|
mode: source.mode(),
|
2019-09-27 12:27:37 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn load_chunk<'lua>(
|
|
|
|
&'lua self,
|
|
|
|
source: &[u8],
|
|
|
|
name: Option<&CString>,
|
2019-09-27 12:38:24 -04:00
|
|
|
env: Option<Value<'lua>>,
|
2020-07-27 18:22:52 -04:00
|
|
|
mode: Option<ChunkMode>,
|
2019-09-27 12:27:37 -04:00
|
|
|
) -> Result<Function<'lua>> {
|
2017-05-21 19:50:59 -04:00
|
|
|
unsafe {
|
2018-03-12 13:13:44 -04:00
|
|
|
let _sg = StackGuard::new(self.state);
|
2021-05-02 05:38:33 -04:00
|
|
|
check_stack(self.state, 1)?;
|
2020-07-27 18:22:52 -04:00
|
|
|
|
|
|
|
let mode_str = match mode {
|
|
|
|
Some(ChunkMode::Binary) if self.safe => {
|
|
|
|
return Err(Error::SafetyError(
|
|
|
|
"binary chunks are disabled in safe mode".to_string(),
|
|
|
|
))
|
|
|
|
}
|
|
|
|
Some(ChunkMode::Binary) => cstr!("b"),
|
|
|
|
Some(ChunkMode::Text) => cstr!("t"),
|
|
|
|
None if source.starts_with(ffi::LUA_SIGNATURE) && self.safe => {
|
|
|
|
return Err(Error::SafetyError(
|
|
|
|
"binary chunks are disabled in safe mode".to_string(),
|
|
|
|
))
|
|
|
|
}
|
|
|
|
None => cstr!("bt"),
|
2020-07-24 03:49:37 -04:00
|
|
|
};
|
2018-03-12 13:13:44 -04:00
|
|
|
|
2020-07-27 18:22:52 -04:00
|
|
|
match ffi::luaL_loadbufferx(
|
|
|
|
self.state,
|
|
|
|
source.as_ptr() as *const c_char,
|
|
|
|
source.len(),
|
2020-07-28 16:05:46 -04:00
|
|
|
name.map(|n| n.as_ptr()).unwrap_or_else(ptr::null),
|
2020-07-27 18:22:52 -04:00
|
|
|
mode_str,
|
|
|
|
) {
|
2019-09-27 12:27:37 -04:00
|
|
|
ffi::LUA_OK => {
|
|
|
|
if let Some(env) = env {
|
|
|
|
self.push_value(env)?;
|
2020-05-08 07:42:40 -04:00
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
2019-09-27 12:27:37 -04:00
|
|
|
ffi::lua_setupvalue(self.state, -2, 1);
|
2019-11-04 11:31:19 -05:00
|
|
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
2019-10-14 17:21:30 -04:00
|
|
|
ffi::lua_setfenv(self.state, -2);
|
2019-09-27 12:27:37 -04:00
|
|
|
}
|
|
|
|
Ok(Function(self.pop_ref()))
|
|
|
|
}
|
2018-03-12 13:13:44 -04:00
|
|
|
err => Err(pop_error(self.state, err)),
|
|
|
|
}
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-02 05:38:33 -04:00
|
|
|
/// Create and return an interned Lua string. Lua strings can be arbitrary [u8] data including
|
2018-09-30 15:42:04 -04:00
|
|
|
/// embedded nulls, so in addition to `&str` and `&String`, you can also pass plain `&[u8]`
|
|
|
|
/// here.
|
2018-10-01 06:00:21 -04:00
|
|
|
pub fn create_string<S>(&self, s: &S) -> Result<String>
|
|
|
|
where
|
2021-05-02 05:38:33 -04:00
|
|
|
S: AsRef<[u8]> + ?Sized,
|
2018-10-01 06:00:21 -04:00
|
|
|
{
|
2017-05-21 19:50:59 -04:00
|
|
|
unsafe {
|
2018-03-12 13:13:44 -04:00
|
|
|
let _sg = StackGuard::new(self.state);
|
2021-05-02 05:38:33 -04:00
|
|
|
check_stack(self.state, 3)?;
|
2021-06-16 17:13:11 -04:00
|
|
|
push_string(self.state, s)?;
|
2018-03-12 13:13:44 -04:00
|
|
|
Ok(String(self.pop_ref()))
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-12 15:37:17 -05:00
|
|
|
/// Creates and returns a new empty table.
|
2017-12-03 23:45:00 -05:00
|
|
|
pub fn create_table(&self) -> Result<Table> {
|
2021-05-02 05:38:33 -04:00
|
|
|
unsafe {
|
|
|
|
let _sg = StackGuard::new(self.state);
|
2021-06-16 17:13:11 -04:00
|
|
|
check_stack(self.state, 3)?;
|
2021-07-08 13:41:10 -04:00
|
|
|
push_table(self.state, 0, 0)?;
|
2021-05-02 05:38:33 -04:00
|
|
|
Ok(Table(self.pop_ref()))
|
|
|
|
}
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
|
2020-12-12 15:37:17 -05:00
|
|
|
/// Creates and returns a new empty table, with the specified capacity.
|
|
|
|
/// `narr` is a hint for how many elements the table will have as a sequence;
|
|
|
|
/// `nrec` is a hint for how many other elements the table will have.
|
|
|
|
/// Lua may use these hints to preallocate memory for the new table.
|
|
|
|
pub fn create_table_with_capacity(&self, narr: c_int, nrec: c_int) -> Result<Table> {
|
|
|
|
unsafe {
|
|
|
|
let _sg = StackGuard::new(self.state);
|
2021-06-16 17:13:11 -04:00
|
|
|
check_stack(self.state, 3)?;
|
|
|
|
push_table(self.state, narr, nrec)?;
|
2020-12-12 15:37:17 -05:00
|
|
|
Ok(Table(self.pop_ref()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Creates a table and fills it with values from an iterator.
|
2021-05-02 05:38:33 -04:00
|
|
|
pub fn create_table_from<'lua, K, V, I>(&'lua self, iter: I) -> Result<Table<'lua>>
|
2017-06-15 10:26:39 -04:00
|
|
|
where
|
|
|
|
K: ToLua<'lua>,
|
|
|
|
V: ToLua<'lua>,
|
|
|
|
I: IntoIterator<Item = (K, V)>,
|
2017-05-21 19:50:59 -04:00
|
|
|
{
|
2017-06-05 01:46:45 -04:00
|
|
|
unsafe {
|
2018-03-12 13:13:44 -04:00
|
|
|
let _sg = StackGuard::new(self.state);
|
2021-05-02 05:38:33 -04:00
|
|
|
check_stack(self.state, 6)?;
|
2018-03-12 13:13:44 -04:00
|
|
|
|
2021-05-02 05:38:33 -04:00
|
|
|
let iter = iter.into_iter();
|
|
|
|
let lower_bound = iter.size_hint().0;
|
2021-06-16 17:13:11 -04:00
|
|
|
push_table(self.state, 0, lower_bound as c_int)?;
|
2021-05-02 05:38:33 -04:00
|
|
|
for (k, v) in iter {
|
2019-09-27 12:27:37 -04:00
|
|
|
self.push_value(k.to_lua(self)?)?;
|
|
|
|
self.push_value(v.to_lua(self)?)?;
|
2021-07-08 13:41:10 -04:00
|
|
|
protect_lua(self.state, 3, 1, |state| ffi::lua_rawset(state, -3))?;
|
2018-03-12 13:13:44 -04:00
|
|
|
}
|
2021-04-09 07:05:03 -04:00
|
|
|
|
2018-03-12 13:13:44 -04:00
|
|
|
Ok(Table(self.pop_ref()))
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Creates a table from an iterator of values, using `1..` as the keys.
|
2021-05-02 05:38:33 -04:00
|
|
|
pub fn create_sequence_from<'lua, T, I>(&'lua self, iter: I) -> Result<Table<'lua>>
|
2017-06-15 10:26:39 -04:00
|
|
|
where
|
|
|
|
T: ToLua<'lua>,
|
|
|
|
I: IntoIterator<Item = T>,
|
2017-05-21 19:50:59 -04:00
|
|
|
{
|
2021-05-02 05:38:33 -04:00
|
|
|
unsafe {
|
|
|
|
let _sg = StackGuard::new(self.state);
|
2021-06-16 17:13:11 -04:00
|
|
|
check_stack(self.state, 5)?;
|
2021-05-02 05:38:33 -04:00
|
|
|
|
|
|
|
let iter = iter.into_iter();
|
|
|
|
let lower_bound = iter.size_hint().0;
|
2021-06-16 17:13:11 -04:00
|
|
|
push_table(self.state, lower_bound as c_int, 0)?;
|
2021-05-02 05:38:33 -04:00
|
|
|
for (i, v) in iter.enumerate() {
|
|
|
|
self.push_value(v.to_lua(self)?)?;
|
2021-07-08 13:41:10 -04:00
|
|
|
protect_lua(self.state, 2, 1, |state| {
|
2021-06-16 17:13:11 -04:00
|
|
|
ffi::lua_rawseti(state, -2, (i + 1) as Integer);
|
|
|
|
})?;
|
2021-05-02 05:38:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(Table(self.pop_ref()))
|
|
|
|
}
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Wraps a Rust function or closure, creating a callable Lua function handle to it.
|
2017-07-25 19:54:40 -04:00
|
|
|
///
|
2018-01-26 13:24:01 -05:00
|
|
|
/// The function's return value is always a `Result`: If the function returns `Err`, the error
|
|
|
|
/// is raised as a Lua error, which can be caught using `(x)pcall` or bubble up to the Rust code
|
|
|
|
/// that invoked the Lua code. This allows using the `?` operator to propagate errors through
|
|
|
|
/// intermediate Lua code.
|
|
|
|
///
|
|
|
|
/// If the function returns `Ok`, the contained value will be converted to one or more Lua
|
|
|
|
/// values. For details on Rust-to-Lua conversions, refer to the [`ToLua`] and [`ToLuaMulti`]
|
|
|
|
/// traits.
|
|
|
|
///
|
2017-07-25 19:54:40 -04:00
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// Create a function which prints its argument:
|
|
|
|
///
|
|
|
|
/// ```
|
2019-10-01 11:11:12 -04:00
|
|
|
/// # use mlua::{Lua, Result};
|
2019-09-27 12:27:37 -04:00
|
|
|
/// # fn main() -> Result<()> {
|
2019-10-17 11:59:33 -04:00
|
|
|
/// # let lua = Lua::new();
|
2017-07-31 01:27:35 -04:00
|
|
|
/// let greet = lua.create_function(|_, name: String| {
|
2017-07-25 19:54:40 -04:00
|
|
|
/// println!("Hello, {}!", name);
|
2017-07-31 01:27:35 -04:00
|
|
|
/// Ok(())
|
2017-07-25 19:54:40 -04:00
|
|
|
/// });
|
|
|
|
/// # let _ = greet; // used
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
///
|
2017-08-01 13:55:08 -04:00
|
|
|
/// Use tuples to accept multiple arguments:
|
2017-07-25 19:54:40 -04:00
|
|
|
///
|
|
|
|
/// ```
|
2019-10-01 11:11:12 -04:00
|
|
|
/// # use mlua::{Lua, Result};
|
2019-09-27 12:27:37 -04:00
|
|
|
/// # fn main() -> Result<()> {
|
2019-10-17 11:59:33 -04:00
|
|
|
/// # let lua = Lua::new();
|
2017-07-31 01:27:35 -04:00
|
|
|
/// let print_person = lua.create_function(|_, (name, age): (String, u8)| {
|
2017-07-25 19:54:40 -04:00
|
|
|
/// println!("{} is {} years old!", name, age);
|
2017-07-31 01:27:35 -04:00
|
|
|
/// Ok(())
|
2017-07-25 19:54:40 -04:00
|
|
|
/// });
|
|
|
|
/// # let _ = print_person; // used
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2018-01-26 13:24:01 -05:00
|
|
|
///
|
|
|
|
/// [`ToLua`]: trait.ToLua.html
|
|
|
|
/// [`ToLuaMulti`]: trait.ToLuaMulti.html
|
2018-02-09 23:35:29 -05:00
|
|
|
pub fn create_function<'lua, 'callback, A, R, F>(&'lua self, func: F) -> Result<Function<'lua>>
|
2017-06-15 10:26:39 -04:00
|
|
|
where
|
2020-05-04 06:56:42 -04:00
|
|
|
'lua: 'callback,
|
2018-02-08 18:50:57 -05:00
|
|
|
A: FromLuaMulti<'callback>,
|
|
|
|
R: ToLuaMulti<'callback>,
|
2020-05-06 08:18:04 -04:00
|
|
|
F: 'static + MaybeSend + Fn(&'callback Lua, A) -> Result<R>,
|
2017-05-21 19:50:59 -04:00
|
|
|
{
|
2018-03-12 16:00:11 -04:00
|
|
|
self.create_callback(Box::new(move |lua, args| {
|
2017-07-31 01:21:41 -04:00
|
|
|
func(lua, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
|
|
|
}))
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
|
2018-02-11 17:54:17 -05:00
|
|
|
/// Wraps a Rust mutable closure, creating a callable Lua function handle to it.
|
|
|
|
///
|
2021-05-02 05:38:33 -04:00
|
|
|
/// This is a version of [`create_function`] that accepts a FnMut argument. Refer to
|
2018-02-11 17:54:17 -05:00
|
|
|
/// [`create_function`] for more information about the implementation.
|
|
|
|
///
|
|
|
|
/// [`create_function`]: #method.create_function
|
2018-02-09 23:35:29 -05:00
|
|
|
pub fn create_function_mut<'lua, 'callback, A, R, F>(
|
|
|
|
&'lua self,
|
|
|
|
func: F,
|
|
|
|
) -> Result<Function<'lua>>
|
|
|
|
where
|
2020-05-04 06:56:42 -04:00
|
|
|
'lua: 'callback,
|
2018-02-09 23:35:29 -05:00
|
|
|
A: FromLuaMulti<'callback>,
|
|
|
|
R: ToLuaMulti<'callback>,
|
2020-05-06 08:18:04 -04:00
|
|
|
F: 'static + MaybeSend + FnMut(&'callback Lua, A) -> Result<R>,
|
2018-02-09 23:35:29 -05:00
|
|
|
{
|
|
|
|
let func = RefCell::new(func);
|
|
|
|
self.create_function(move |lua, args| {
|
2018-08-05 09:51:39 -04:00
|
|
|
(&mut *func
|
|
|
|
.try_borrow_mut()
|
2018-02-09 23:35:29 -05:00
|
|
|
.map_err(|_| Error::RecursiveMutCallback)?)(lua, args)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-07-04 18:51:51 -04:00
|
|
|
/// Wraps a C function, creating a callable Lua function handle to it.
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
/// This function is unsafe because provides a way to execute unsafe C function.
|
|
|
|
pub unsafe fn create_c_function(&self, func: ffi::lua_CFunction) -> Result<Function> {
|
|
|
|
let _sg = StackGuard::new(self.state);
|
|
|
|
check_stack(self.state, 3)?;
|
2021-07-08 13:41:10 -04:00
|
|
|
protect_lua(self.state, 0, 1, |state| {
|
2021-07-04 18:51:51 -04:00
|
|
|
ffi::lua_pushcfunction(state, func);
|
|
|
|
})?;
|
|
|
|
Ok(Function(self.pop_ref()))
|
|
|
|
}
|
|
|
|
|
2020-04-17 17:38:01 -04:00
|
|
|
/// Wraps a Rust async function or closure, creating a callable Lua function handle to it.
|
|
|
|
///
|
|
|
|
/// While executing the function Rust will poll Future and if the result is not ready, call
|
2020-04-18 16:26:12 -04:00
|
|
|
/// `yield()` passing internal representation of a `Poll::Pending` value.
|
2020-04-17 17:38:01 -04:00
|
|
|
///
|
2020-04-18 16:26:12 -04:00
|
|
|
/// The function must be called inside Lua coroutine ([`Thread`]) to be able to suspend its execution.
|
|
|
|
/// An executor should be used to poll [`AsyncThread`] and mlua will take a provided Waker
|
2020-04-17 17:38:01 -04:00
|
|
|
/// in that case. Otherwise noop waker will be used if try to call the function outside of Rust
|
|
|
|
/// executors.
|
|
|
|
///
|
2020-04-18 16:26:12 -04:00
|
|
|
/// The family of `call_async()` functions takes care about creating [`Thread`].
|
|
|
|
///
|
2020-05-13 21:12:22 -04:00
|
|
|
/// Requires `feature = "async"`
|
|
|
|
///
|
2020-04-17 17:38:01 -04:00
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// Non blocking sleep:
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use std::time::Duration;
|
|
|
|
/// use futures_timer::Delay;
|
2020-04-18 16:26:12 -04:00
|
|
|
/// use mlua::{Lua, Result};
|
2020-04-17 17:38:01 -04:00
|
|
|
///
|
|
|
|
/// async fn sleep(_lua: &Lua, n: u64) -> Result<&'static str> {
|
2020-04-18 16:26:12 -04:00
|
|
|
/// Delay::new(Duration::from_millis(n)).await;
|
2020-04-17 17:38:01 -04:00
|
|
|
/// Ok("done")
|
|
|
|
/// }
|
|
|
|
///
|
2020-04-18 16:26:12 -04:00
|
|
|
/// #[tokio::main]
|
|
|
|
/// async fn main() -> Result<()> {
|
|
|
|
/// let lua = Lua::new();
|
|
|
|
/// lua.globals().set("sleep", lua.create_async_function(sleep)?)?;
|
|
|
|
/// let res: String = lua.load("return sleep(...)").call_async(100).await?; // Sleep 100ms
|
|
|
|
/// assert_eq!(res, "done");
|
|
|
|
/// Ok(())
|
|
|
|
/// }
|
2020-04-17 17:38:01 -04:00
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// [`Thread`]: struct.Thread.html
|
2020-06-08 06:31:10 -04:00
|
|
|
/// [`AsyncThread`]: struct.AsyncThread.html
|
2020-04-17 17:38:01 -04:00
|
|
|
#[cfg(feature = "async")]
|
2020-12-29 20:43:00 -05:00
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
2020-04-17 17:38:01 -04:00
|
|
|
pub fn create_async_function<'lua, 'callback, A, R, F, FR>(
|
|
|
|
&'lua self,
|
|
|
|
func: F,
|
|
|
|
) -> Result<Function<'lua>>
|
|
|
|
where
|
2020-05-04 06:56:42 -04:00
|
|
|
'lua: 'callback,
|
2020-04-17 17:38:01 -04:00
|
|
|
A: FromLuaMulti<'callback>,
|
|
|
|
R: ToLuaMulti<'callback>,
|
2020-05-06 08:18:04 -04:00
|
|
|
F: 'static + MaybeSend + Fn(&'callback Lua, A) -> FR,
|
2020-05-05 08:03:28 -04:00
|
|
|
FR: 'lua + Future<Output = Result<R>>,
|
2020-04-17 17:38:01 -04:00
|
|
|
{
|
|
|
|
self.create_async_callback(Box::new(move |lua, args| {
|
|
|
|
let args = match A::from_lua_multi(args, lua) {
|
2020-04-19 11:51:35 -04:00
|
|
|
Ok(args) => args,
|
|
|
|
Err(e) => return Box::pin(future::err(e)),
|
2020-04-17 17:38:01 -04:00
|
|
|
};
|
2020-04-19 11:51:35 -04:00
|
|
|
Box::pin(func(lua, args).and_then(move |ret| future::ready(ret.to_lua_multi(lua))))
|
2020-04-17 17:38:01 -04:00
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Wraps a Lua function into a new thread (or coroutine).
|
|
|
|
///
|
|
|
|
/// Equivalent to `coroutine.create`.
|
2017-12-03 23:45:00 -05:00
|
|
|
pub fn create_thread<'lua>(&'lua self, func: Function<'lua>) -> Result<Thread<'lua>> {
|
2017-05-24 23:13:58 -04:00
|
|
|
unsafe {
|
2018-03-12 13:13:44 -04:00
|
|
|
let _sg = StackGuard::new(self.state);
|
2021-06-16 17:13:11 -04:00
|
|
|
check_stack(self.state, 3)?;
|
2017-05-24 23:13:58 -04:00
|
|
|
|
2021-07-08 13:41:10 -04:00
|
|
|
let thread_state = protect_lua(self.state, 0, 1, |state| ffi::lua_newthread(state))?;
|
2018-03-12 13:13:44 -04:00
|
|
|
self.push_ref(&func.0);
|
|
|
|
ffi::lua_xmove(self.state, thread_state, 1);
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2018-03-12 13:13:44 -04:00
|
|
|
Ok(Thread(self.pop_ref()))
|
2017-05-24 23:13:58 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Create a Lua userdata object from a custom userdata type.
|
2017-12-03 23:45:00 -05:00
|
|
|
pub fn create_userdata<T>(&self, data: T) -> Result<AnyUserData>
|
2017-06-15 10:26:39 -04:00
|
|
|
where
|
2020-05-06 08:18:04 -04:00
|
|
|
T: 'static + MaybeSend + UserData,
|
2017-05-21 19:50:59 -04:00
|
|
|
{
|
2021-04-27 13:31:57 -04:00
|
|
|
unsafe { self.make_userdata(UserDataCell::new(data)) }
|
2020-12-12 15:37:17 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Create a Lua userdata object from a custom serializable userdata type.
|
|
|
|
///
|
|
|
|
/// Requires `feature = "serialize"`
|
|
|
|
#[cfg(feature = "serialize")]
|
2020-12-29 20:43:00 -05:00
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
|
2020-12-12 15:37:17 -05:00
|
|
|
pub fn create_ser_userdata<T>(&self, data: T) -> Result<AnyUserData>
|
|
|
|
where
|
|
|
|
T: 'static + MaybeSend + UserData + Serialize,
|
|
|
|
{
|
2021-04-27 13:31:57 -04:00
|
|
|
unsafe { self.make_userdata(UserDataCell::new_ser(data)) }
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Returns a handle to the global environment.
|
2017-07-18 16:21:12 -04:00
|
|
|
pub fn globals(&self) -> Table {
|
2017-05-21 19:50:59 -04:00
|
|
|
unsafe {
|
2018-03-12 13:13:44 -04:00
|
|
|
let _sg = StackGuard::new(self.state);
|
2021-05-02 05:38:33 -04:00
|
|
|
assert_stack(self.state, 1);
|
2020-05-08 07:42:40 -04:00
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
2018-03-12 13:13:44 -04:00
|
|
|
ffi::lua_rawgeti(self.state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS);
|
2019-11-04 11:31:19 -05:00
|
|
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
2019-10-14 17:21:30 -04:00
|
|
|
ffi::lua_pushvalue(self.state, ffi::LUA_GLOBALSINDEX);
|
2018-03-12 13:13:44 -04:00
|
|
|
Table(self.pop_ref())
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-02 05:38:33 -04:00
|
|
|
/// Returns a handle to the active `Thread`. For calls to `Lua` this will be the main Lua thread,
|
2019-09-27 12:27:37 -04:00
|
|
|
/// for parameters given to a callback, this will be whatever Lua thread called the callback.
|
2020-05-12 18:34:42 -04:00
|
|
|
pub fn current_thread(&self) -> Thread {
|
2019-09-27 12:27:37 -04:00
|
|
|
unsafe {
|
2021-05-02 05:38:33 -04:00
|
|
|
let _sg = StackGuard::new(self.state);
|
|
|
|
assert_stack(self.state, 1);
|
2019-09-27 12:27:37 -04:00
|
|
|
ffi::lua_pushthread(self.state);
|
|
|
|
Thread(self.pop_ref())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-06 20:18:56 -04:00
|
|
|
/// Calls the given function with a `Scope` parameter, giving the function the ability to create
|
|
|
|
/// userdata and callbacks from rust types that are !Send or non-'static.
|
|
|
|
///
|
|
|
|
/// The lifetime of any function or userdata created through `Scope` lasts only until the
|
|
|
|
/// completion of this method call, on completion all such created values are automatically
|
2021-05-02 05:38:33 -04:00
|
|
|
/// dropped and Lua references to them are invalidated. If a script accesses a value created
|
|
|
|
/// through `Scope` outside of this method, a Lua error will result. Since we can ensure the
|
2020-05-06 20:18:56 -04:00
|
|
|
/// lifetime of values created through `Scope`, and we know that `Lua` cannot be sent to another
|
|
|
|
/// thread while `Scope` is live, it is safe to allow !Send datatypes and whose lifetimes only
|
|
|
|
/// outlive the scope lifetime.
|
|
|
|
///
|
|
|
|
/// Inside the scope callback, all handles created through Scope will share the same unique 'lua
|
2021-05-02 05:38:33 -04:00
|
|
|
/// lifetime of the parent `Lua`. This allows scoped and non-scoped values to be mixed in
|
2020-05-06 20:18:56 -04:00
|
|
|
/// API calls, which is very useful (e.g. passing a scoped userdata to a non-scoped function).
|
|
|
|
/// However, this also enables handles to scoped values to be trivially leaked from the given
|
|
|
|
/// callback. This is not dangerous, though! After the callback returns, all scoped values are
|
|
|
|
/// invalidated, which means that though references may exist, the Rust types backing them have
|
2021-05-02 05:38:33 -04:00
|
|
|
/// dropped. `Function` types will error when called, and `AnyUserData` will be typeless. It
|
2020-05-06 20:18:56 -04:00
|
|
|
/// would be impossible to prevent handles to scoped values from escaping anyway, since you
|
|
|
|
/// would always be able to smuggle them through Lua state.
|
|
|
|
pub fn scope<'lua, 'scope, R, F>(&'lua self, f: F) -> Result<R>
|
|
|
|
where
|
|
|
|
'lua: 'scope,
|
|
|
|
R: 'static,
|
|
|
|
F: FnOnce(&Scope<'lua, 'scope>) -> Result<R>,
|
|
|
|
{
|
|
|
|
f(&Scope::new(self))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// An asynchronous version of [`scope`] that allows to create scoped async functions and
|
|
|
|
/// execute them.
|
|
|
|
///
|
2020-05-13 21:12:22 -04:00
|
|
|
/// Requires `feature = "async"`
|
|
|
|
///
|
2020-05-06 20:18:56 -04:00
|
|
|
/// [`scope`]: #method.scope
|
|
|
|
#[cfg(feature = "async")]
|
2020-12-29 20:43:00 -05:00
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
2020-05-06 20:18:56 -04:00
|
|
|
pub fn async_scope<'lua, 'scope, R, F, FR>(
|
|
|
|
&'lua self,
|
|
|
|
f: F,
|
|
|
|
) -> LocalBoxFuture<'scope, Result<R>>
|
|
|
|
where
|
|
|
|
'lua: 'scope,
|
|
|
|
R: 'static,
|
|
|
|
F: FnOnce(Scope<'lua, 'scope>) -> FR,
|
|
|
|
FR: 'scope + Future<Output = Result<R>>,
|
|
|
|
{
|
|
|
|
Box::pin(f(Scope::new(self)))
|
|
|
|
}
|
|
|
|
|
Improve the situation with numerical conversion
This is a somewhat involved change with two breaking API changes:
1) Lua::coerce_xxx methods now return Option (this is easier and faster than
dealing with Result)
2) rlua numeric conversions now allow more loss of precision
conversions (e.g. 1.5f32 to 1i32)
The logic for the first breaking change is that mostly the coerce methods are
probably used internally, and they make sense as low-level fallible casts and
are now used as such, and there's no reason to confuse things with a Result with
a large error type and force the user to match on the error which will hopefully
only be FromLuaConversionError anyway.
The logic for the second change is that it matches the behavior of
num_traits::cast, and is more consistent in that *some* loss of precision
conversions were previously allowed (e.g. f64 to f32).
The problem is that now, Lua::coerce_integer and Lua::unpack::<i64> have
different behavior when given, for example, the number 1.5. I still think this
is the best option, though, because the Lua::coerce_xxx methods represent how
Lua works internally and the standard C API cast functions that Lua provides,
and the ToLua / FromLua code represents the most common form of fallible Rust
numeric conversion.
I could revert this change and turn `Lua::eval::<i64>("1.5", None)` back into an
error, but it seems inconsistent to allow f64 -> f32 loss of precision but not
f64 -> i64 loss of precision.
2018-09-26 20:41:07 -04:00
|
|
|
/// Attempts to coerce a Lua value into a String in a manner consistent with Lua's internal
|
|
|
|
/// behavior.
|
2017-06-17 21:23:17 -04:00
|
|
|
///
|
Improve the situation with numerical conversion
This is a somewhat involved change with two breaking API changes:
1) Lua::coerce_xxx methods now return Option (this is easier and faster than
dealing with Result)
2) rlua numeric conversions now allow more loss of precision
conversions (e.g. 1.5f32 to 1i32)
The logic for the first breaking change is that mostly the coerce methods are
probably used internally, and they make sense as low-level fallible casts and
are now used as such, and there's no reason to confuse things with a Result with
a large error type and force the user to match on the error which will hopefully
only be FromLuaConversionError anyway.
The logic for the second change is that it matches the behavior of
num_traits::cast, and is more consistent in that *some* loss of precision
conversions were previously allowed (e.g. f64 to f32).
The problem is that now, Lua::coerce_integer and Lua::unpack::<i64> have
different behavior when given, for example, the number 1.5. I still think this
is the best option, though, because the Lua::coerce_xxx methods represent how
Lua works internally and the standard C API cast functions that Lua provides,
and the ToLua / FromLua code represents the most common form of fallible Rust
numeric conversion.
I could revert this change and turn `Lua::eval::<i64>("1.5", None)` back into an
error, but it seems inconsistent to allow f64 -> f32 loss of precision but not
f64 -> i64 loss of precision.
2018-09-26 20:41:07 -04:00
|
|
|
/// To succeed, the value must be a string (in which case this is a no-op), an integer, or a
|
|
|
|
/// number.
|
2019-09-27 12:27:37 -04:00
|
|
|
pub fn coerce_string<'lua>(&'lua self, v: Value<'lua>) -> Result<Option<String<'lua>>> {
|
|
|
|
Ok(match v {
|
Improve the situation with numerical conversion
This is a somewhat involved change with two breaking API changes:
1) Lua::coerce_xxx methods now return Option (this is easier and faster than
dealing with Result)
2) rlua numeric conversions now allow more loss of precision
conversions (e.g. 1.5f32 to 1i32)
The logic for the first breaking change is that mostly the coerce methods are
probably used internally, and they make sense as low-level fallible casts and
are now used as such, and there's no reason to confuse things with a Result with
a large error type and force the user to match on the error which will hopefully
only be FromLuaConversionError anyway.
The logic for the second change is that it matches the behavior of
num_traits::cast, and is more consistent in that *some* loss of precision
conversions were previously allowed (e.g. f64 to f32).
The problem is that now, Lua::coerce_integer and Lua::unpack::<i64> have
different behavior when given, for example, the number 1.5. I still think this
is the best option, though, because the Lua::coerce_xxx methods represent how
Lua works internally and the standard C API cast functions that Lua provides,
and the ToLua / FromLua code represents the most common form of fallible Rust
numeric conversion.
I could revert this change and turn `Lua::eval::<i64>("1.5", None)` back into an
error, but it seems inconsistent to allow f64 -> f32 loss of precision but not
f64 -> i64 loss of precision.
2018-09-26 20:41:07 -04:00
|
|
|
Value::String(s) => Some(s),
|
2017-05-21 19:50:59 -04:00
|
|
|
v => unsafe {
|
2018-03-12 13:13:44 -04:00
|
|
|
let _sg = StackGuard::new(self.state);
|
2021-06-16 17:13:11 -04:00
|
|
|
check_stack(self.state, 4)?;
|
2018-03-12 13:13:44 -04:00
|
|
|
|
2019-09-27 12:27:37 -04:00
|
|
|
self.push_value(v)?;
|
2021-07-08 13:41:10 -04:00
|
|
|
let res = protect_lua(self.state, 1, 1, |state| {
|
2021-06-16 17:13:11 -04:00
|
|
|
ffi::lua_tolstring(state, -1, ptr::null_mut())
|
|
|
|
})?;
|
|
|
|
if !res.is_null() {
|
Improve the situation with numerical conversion
This is a somewhat involved change with two breaking API changes:
1) Lua::coerce_xxx methods now return Option (this is easier and faster than
dealing with Result)
2) rlua numeric conversions now allow more loss of precision
conversions (e.g. 1.5f32 to 1i32)
The logic for the first breaking change is that mostly the coerce methods are
probably used internally, and they make sense as low-level fallible casts and
are now used as such, and there's no reason to confuse things with a Result with
a large error type and force the user to match on the error which will hopefully
only be FromLuaConversionError anyway.
The logic for the second change is that it matches the behavior of
num_traits::cast, and is more consistent in that *some* loss of precision
conversions were previously allowed (e.g. f64 to f32).
The problem is that now, Lua::coerce_integer and Lua::unpack::<i64> have
different behavior when given, for example, the number 1.5. I still think this
is the best option, though, because the Lua::coerce_xxx methods represent how
Lua works internally and the standard C API cast functions that Lua provides,
and the ToLua / FromLua code represents the most common form of fallible Rust
numeric conversion.
I could revert this change and turn `Lua::eval::<i64>("1.5", None)` back into an
error, but it seems inconsistent to allow f64 -> f32 loss of precision but not
f64 -> i64 loss of precision.
2018-09-26 20:41:07 -04:00
|
|
|
Some(String(self.pop_ref()))
|
2019-09-27 12:27:37 -04:00
|
|
|
} else {
|
|
|
|
None
|
2018-03-12 13:13:44 -04:00
|
|
|
}
|
2017-05-21 19:50:59 -04:00
|
|
|
},
|
2019-09-27 12:27:37 -04:00
|
|
|
})
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
|
Improve the situation with numerical conversion
This is a somewhat involved change with two breaking API changes:
1) Lua::coerce_xxx methods now return Option (this is easier and faster than
dealing with Result)
2) rlua numeric conversions now allow more loss of precision
conversions (e.g. 1.5f32 to 1i32)
The logic for the first breaking change is that mostly the coerce methods are
probably used internally, and they make sense as low-level fallible casts and
are now used as such, and there's no reason to confuse things with a Result with
a large error type and force the user to match on the error which will hopefully
only be FromLuaConversionError anyway.
The logic for the second change is that it matches the behavior of
num_traits::cast, and is more consistent in that *some* loss of precision
conversions were previously allowed (e.g. f64 to f32).
The problem is that now, Lua::coerce_integer and Lua::unpack::<i64> have
different behavior when given, for example, the number 1.5. I still think this
is the best option, though, because the Lua::coerce_xxx methods represent how
Lua works internally and the standard C API cast functions that Lua provides,
and the ToLua / FromLua code represents the most common form of fallible Rust
numeric conversion.
I could revert this change and turn `Lua::eval::<i64>("1.5", None)` back into an
error, but it seems inconsistent to allow f64 -> f32 loss of precision but not
f64 -> i64 loss of precision.
2018-09-26 20:41:07 -04:00
|
|
|
/// Attempts to coerce a Lua value into an integer in a manner consistent with Lua's internal
|
|
|
|
/// behavior.
|
2017-06-17 21:23:17 -04:00
|
|
|
///
|
Improve the situation with numerical conversion
This is a somewhat involved change with two breaking API changes:
1) Lua::coerce_xxx methods now return Option (this is easier and faster than
dealing with Result)
2) rlua numeric conversions now allow more loss of precision
conversions (e.g. 1.5f32 to 1i32)
The logic for the first breaking change is that mostly the coerce methods are
probably used internally, and they make sense as low-level fallible casts and
are now used as such, and there's no reason to confuse things with a Result with
a large error type and force the user to match on the error which will hopefully
only be FromLuaConversionError anyway.
The logic for the second change is that it matches the behavior of
num_traits::cast, and is more consistent in that *some* loss of precision
conversions were previously allowed (e.g. f64 to f32).
The problem is that now, Lua::coerce_integer and Lua::unpack::<i64> have
different behavior when given, for example, the number 1.5. I still think this
is the best option, though, because the Lua::coerce_xxx methods represent how
Lua works internally and the standard C API cast functions that Lua provides,
and the ToLua / FromLua code represents the most common form of fallible Rust
numeric conversion.
I could revert this change and turn `Lua::eval::<i64>("1.5", None)` back into an
error, but it seems inconsistent to allow f64 -> f32 loss of precision but not
f64 -> i64 loss of precision.
2018-09-26 20:41:07 -04:00
|
|
|
/// To succeed, the value must be an integer, a floating point number that has an exact
|
|
|
|
/// representation as an integer, or a string that can be converted to an integer. Refer to the
|
|
|
|
/// Lua manual for details.
|
2019-09-27 12:27:37 -04:00
|
|
|
pub fn coerce_integer(&self, v: Value) -> Result<Option<Integer>> {
|
|
|
|
Ok(match v {
|
Improve the situation with numerical conversion
This is a somewhat involved change with two breaking API changes:
1) Lua::coerce_xxx methods now return Option (this is easier and faster than
dealing with Result)
2) rlua numeric conversions now allow more loss of precision
conversions (e.g. 1.5f32 to 1i32)
The logic for the first breaking change is that mostly the coerce methods are
probably used internally, and they make sense as low-level fallible casts and
are now used as such, and there's no reason to confuse things with a Result with
a large error type and force the user to match on the error which will hopefully
only be FromLuaConversionError anyway.
The logic for the second change is that it matches the behavior of
num_traits::cast, and is more consistent in that *some* loss of precision
conversions were previously allowed (e.g. f64 to f32).
The problem is that now, Lua::coerce_integer and Lua::unpack::<i64> have
different behavior when given, for example, the number 1.5. I still think this
is the best option, though, because the Lua::coerce_xxx methods represent how
Lua works internally and the standard C API cast functions that Lua provides,
and the ToLua / FromLua code represents the most common form of fallible Rust
numeric conversion.
I could revert this change and turn `Lua::eval::<i64>("1.5", None)` back into an
error, but it seems inconsistent to allow f64 -> f32 loss of precision but not
f64 -> i64 loss of precision.
2018-09-26 20:41:07 -04:00
|
|
|
Value::Integer(i) => Some(i),
|
2017-05-21 19:50:59 -04:00
|
|
|
v => unsafe {
|
2018-03-12 13:13:44 -04:00
|
|
|
let _sg = StackGuard::new(self.state);
|
2021-05-02 05:38:33 -04:00
|
|
|
check_stack(self.state, 2)?;
|
2018-03-12 13:13:44 -04:00
|
|
|
|
2019-09-27 12:27:37 -04:00
|
|
|
self.push_value(v)?;
|
2018-03-12 13:13:44 -04:00
|
|
|
let mut isint = 0;
|
|
|
|
let i = ffi::lua_tointegerx(self.state, -1, &mut isint);
|
|
|
|
if isint == 0 {
|
Improve the situation with numerical conversion
This is a somewhat involved change with two breaking API changes:
1) Lua::coerce_xxx methods now return Option (this is easier and faster than
dealing with Result)
2) rlua numeric conversions now allow more loss of precision
conversions (e.g. 1.5f32 to 1i32)
The logic for the first breaking change is that mostly the coerce methods are
probably used internally, and they make sense as low-level fallible casts and
are now used as such, and there's no reason to confuse things with a Result with
a large error type and force the user to match on the error which will hopefully
only be FromLuaConversionError anyway.
The logic for the second change is that it matches the behavior of
num_traits::cast, and is more consistent in that *some* loss of precision
conversions were previously allowed (e.g. f64 to f32).
The problem is that now, Lua::coerce_integer and Lua::unpack::<i64> have
different behavior when given, for example, the number 1.5. I still think this
is the best option, though, because the Lua::coerce_xxx methods represent how
Lua works internally and the standard C API cast functions that Lua provides,
and the ToLua / FromLua code represents the most common form of fallible Rust
numeric conversion.
I could revert this change and turn `Lua::eval::<i64>("1.5", None)` back into an
error, but it seems inconsistent to allow f64 -> f32 loss of precision but not
f64 -> i64 loss of precision.
2018-09-26 20:41:07 -04:00
|
|
|
None
|
2018-03-12 13:13:44 -04:00
|
|
|
} else {
|
Improve the situation with numerical conversion
This is a somewhat involved change with two breaking API changes:
1) Lua::coerce_xxx methods now return Option (this is easier and faster than
dealing with Result)
2) rlua numeric conversions now allow more loss of precision
conversions (e.g. 1.5f32 to 1i32)
The logic for the first breaking change is that mostly the coerce methods are
probably used internally, and they make sense as low-level fallible casts and
are now used as such, and there's no reason to confuse things with a Result with
a large error type and force the user to match on the error which will hopefully
only be FromLuaConversionError anyway.
The logic for the second change is that it matches the behavior of
num_traits::cast, and is more consistent in that *some* loss of precision
conversions were previously allowed (e.g. f64 to f32).
The problem is that now, Lua::coerce_integer and Lua::unpack::<i64> have
different behavior when given, for example, the number 1.5. I still think this
is the best option, though, because the Lua::coerce_xxx methods represent how
Lua works internally and the standard C API cast functions that Lua provides,
and the ToLua / FromLua code represents the most common form of fallible Rust
numeric conversion.
I could revert this change and turn `Lua::eval::<i64>("1.5", None)` back into an
error, but it seems inconsistent to allow f64 -> f32 loss of precision but not
f64 -> i64 loss of precision.
2018-09-26 20:41:07 -04:00
|
|
|
Some(i)
|
2018-03-12 13:13:44 -04:00
|
|
|
}
|
2017-05-21 19:50:59 -04:00
|
|
|
},
|
2019-09-27 12:27:37 -04:00
|
|
|
})
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
|
Improve the situation with numerical conversion
This is a somewhat involved change with two breaking API changes:
1) Lua::coerce_xxx methods now return Option (this is easier and faster than
dealing with Result)
2) rlua numeric conversions now allow more loss of precision
conversions (e.g. 1.5f32 to 1i32)
The logic for the first breaking change is that mostly the coerce methods are
probably used internally, and they make sense as low-level fallible casts and
are now used as such, and there's no reason to confuse things with a Result with
a large error type and force the user to match on the error which will hopefully
only be FromLuaConversionError anyway.
The logic for the second change is that it matches the behavior of
num_traits::cast, and is more consistent in that *some* loss of precision
conversions were previously allowed (e.g. f64 to f32).
The problem is that now, Lua::coerce_integer and Lua::unpack::<i64> have
different behavior when given, for example, the number 1.5. I still think this
is the best option, though, because the Lua::coerce_xxx methods represent how
Lua works internally and the standard C API cast functions that Lua provides,
and the ToLua / FromLua code represents the most common form of fallible Rust
numeric conversion.
I could revert this change and turn `Lua::eval::<i64>("1.5", None)` back into an
error, but it seems inconsistent to allow f64 -> f32 loss of precision but not
f64 -> i64 loss of precision.
2018-09-26 20:41:07 -04:00
|
|
|
/// Attempts to coerce a Lua value into a Number in a manner consistent with Lua's internal
|
|
|
|
/// behavior.
|
2017-06-17 21:23:17 -04:00
|
|
|
///
|
Improve the situation with numerical conversion
This is a somewhat involved change with two breaking API changes:
1) Lua::coerce_xxx methods now return Option (this is easier and faster than
dealing with Result)
2) rlua numeric conversions now allow more loss of precision
conversions (e.g. 1.5f32 to 1i32)
The logic for the first breaking change is that mostly the coerce methods are
probably used internally, and they make sense as low-level fallible casts and
are now used as such, and there's no reason to confuse things with a Result with
a large error type and force the user to match on the error which will hopefully
only be FromLuaConversionError anyway.
The logic for the second change is that it matches the behavior of
num_traits::cast, and is more consistent in that *some* loss of precision
conversions were previously allowed (e.g. f64 to f32).
The problem is that now, Lua::coerce_integer and Lua::unpack::<i64> have
different behavior when given, for example, the number 1.5. I still think this
is the best option, though, because the Lua::coerce_xxx methods represent how
Lua works internally and the standard C API cast functions that Lua provides,
and the ToLua / FromLua code represents the most common form of fallible Rust
numeric conversion.
I could revert this change and turn `Lua::eval::<i64>("1.5", None)` back into an
error, but it seems inconsistent to allow f64 -> f32 loss of precision but not
f64 -> i64 loss of precision.
2018-09-26 20:41:07 -04:00
|
|
|
/// To succeed, the value must be a number or a string that can be converted to a number. Refer
|
|
|
|
/// to the Lua manual for details.
|
2019-09-27 12:27:37 -04:00
|
|
|
pub fn coerce_number(&self, v: Value) -> Result<Option<Number>> {
|
|
|
|
Ok(match v {
|
Improve the situation with numerical conversion
This is a somewhat involved change with two breaking API changes:
1) Lua::coerce_xxx methods now return Option (this is easier and faster than
dealing with Result)
2) rlua numeric conversions now allow more loss of precision
conversions (e.g. 1.5f32 to 1i32)
The logic for the first breaking change is that mostly the coerce methods are
probably used internally, and they make sense as low-level fallible casts and
are now used as such, and there's no reason to confuse things with a Result with
a large error type and force the user to match on the error which will hopefully
only be FromLuaConversionError anyway.
The logic for the second change is that it matches the behavior of
num_traits::cast, and is more consistent in that *some* loss of precision
conversions were previously allowed (e.g. f64 to f32).
The problem is that now, Lua::coerce_integer and Lua::unpack::<i64> have
different behavior when given, for example, the number 1.5. I still think this
is the best option, though, because the Lua::coerce_xxx methods represent how
Lua works internally and the standard C API cast functions that Lua provides,
and the ToLua / FromLua code represents the most common form of fallible Rust
numeric conversion.
I could revert this change and turn `Lua::eval::<i64>("1.5", None)` back into an
error, but it seems inconsistent to allow f64 -> f32 loss of precision but not
f64 -> i64 loss of precision.
2018-09-26 20:41:07 -04:00
|
|
|
Value::Number(n) => Some(n),
|
2017-05-21 19:50:59 -04:00
|
|
|
v => unsafe {
|
2018-03-12 13:13:44 -04:00
|
|
|
let _sg = StackGuard::new(self.state);
|
2021-05-02 05:38:33 -04:00
|
|
|
check_stack(self.state, 2)?;
|
2018-03-12 13:13:44 -04:00
|
|
|
|
2019-09-27 12:27:37 -04:00
|
|
|
self.push_value(v)?;
|
2018-03-12 13:13:44 -04:00
|
|
|
let mut isnum = 0;
|
|
|
|
let n = ffi::lua_tonumberx(self.state, -1, &mut isnum);
|
|
|
|
if isnum == 0 {
|
Improve the situation with numerical conversion
This is a somewhat involved change with two breaking API changes:
1) Lua::coerce_xxx methods now return Option (this is easier and faster than
dealing with Result)
2) rlua numeric conversions now allow more loss of precision
conversions (e.g. 1.5f32 to 1i32)
The logic for the first breaking change is that mostly the coerce methods are
probably used internally, and they make sense as low-level fallible casts and
are now used as such, and there's no reason to confuse things with a Result with
a large error type and force the user to match on the error which will hopefully
only be FromLuaConversionError anyway.
The logic for the second change is that it matches the behavior of
num_traits::cast, and is more consistent in that *some* loss of precision
conversions were previously allowed (e.g. f64 to f32).
The problem is that now, Lua::coerce_integer and Lua::unpack::<i64> have
different behavior when given, for example, the number 1.5. I still think this
is the best option, though, because the Lua::coerce_xxx methods represent how
Lua works internally and the standard C API cast functions that Lua provides,
and the ToLua / FromLua code represents the most common form of fallible Rust
numeric conversion.
I could revert this change and turn `Lua::eval::<i64>("1.5", None)` back into an
error, but it seems inconsistent to allow f64 -> f32 loss of precision but not
f64 -> i64 loss of precision.
2018-09-26 20:41:07 -04:00
|
|
|
None
|
2018-03-12 13:13:44 -04:00
|
|
|
} else {
|
Improve the situation with numerical conversion
This is a somewhat involved change with two breaking API changes:
1) Lua::coerce_xxx methods now return Option (this is easier and faster than
dealing with Result)
2) rlua numeric conversions now allow more loss of precision
conversions (e.g. 1.5f32 to 1i32)
The logic for the first breaking change is that mostly the coerce methods are
probably used internally, and they make sense as low-level fallible casts and
are now used as such, and there's no reason to confuse things with a Result with
a large error type and force the user to match on the error which will hopefully
only be FromLuaConversionError anyway.
The logic for the second change is that it matches the behavior of
num_traits::cast, and is more consistent in that *some* loss of precision
conversions were previously allowed (e.g. f64 to f32).
The problem is that now, Lua::coerce_integer and Lua::unpack::<i64> have
different behavior when given, for example, the number 1.5. I still think this
is the best option, though, because the Lua::coerce_xxx methods represent how
Lua works internally and the standard C API cast functions that Lua provides,
and the ToLua / FromLua code represents the most common form of fallible Rust
numeric conversion.
I could revert this change and turn `Lua::eval::<i64>("1.5", None)` back into an
error, but it seems inconsistent to allow f64 -> f32 loss of precision but not
f64 -> i64 loss of precision.
2018-09-26 20:41:07 -04:00
|
|
|
Some(n)
|
2018-03-12 13:13:44 -04:00
|
|
|
}
|
2017-05-21 19:50:59 -04:00
|
|
|
},
|
2019-09-27 12:27:37 -04:00
|
|
|
})
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
|
2017-08-01 13:55:08 -04:00
|
|
|
/// Converts a value that implements `ToLua` into a `Value` instance.
|
|
|
|
pub fn pack<'lua, T: ToLua<'lua>>(&'lua self, t: T) -> Result<Value<'lua>> {
|
2017-05-21 19:50:59 -04:00
|
|
|
t.to_lua(self)
|
|
|
|
}
|
|
|
|
|
2017-08-01 13:55:08 -04:00
|
|
|
/// Converts a `Value` instance into a value that implements `FromLua`.
|
|
|
|
pub fn unpack<'lua, T: FromLua<'lua>>(&'lua self, value: Value<'lua>) -> Result<T> {
|
2017-05-21 19:50:59 -04:00
|
|
|
T::from_lua(value, self)
|
|
|
|
}
|
|
|
|
|
2017-08-01 13:55:08 -04:00
|
|
|
/// Converts a value that implements `ToLuaMulti` into a `MultiValue` instance.
|
|
|
|
pub fn pack_multi<'lua, T: ToLuaMulti<'lua>>(&'lua self, t: T) -> Result<MultiValue<'lua>> {
|
2017-05-21 19:50:59 -04:00
|
|
|
t.to_lua_multi(self)
|
|
|
|
}
|
|
|
|
|
2017-08-01 13:55:08 -04:00
|
|
|
/// Converts a `MultiValue` instance into a value that implements `FromLuaMulti`.
|
|
|
|
pub fn unpack_multi<'lua, T: FromLuaMulti<'lua>>(
|
|
|
|
&'lua self,
|
|
|
|
value: MultiValue<'lua>,
|
|
|
|
) -> Result<T> {
|
2017-05-21 19:50:59 -04:00
|
|
|
T::from_lua_multi(value, self)
|
|
|
|
}
|
|
|
|
|
2017-12-16 18:05:53 -05:00
|
|
|
/// Set a value in the Lua registry based on a string name.
|
2017-12-16 17:44:13 -05:00
|
|
|
///
|
|
|
|
/// This value will be available to rust from all `Lua` instances which share the same main
|
|
|
|
/// state.
|
2019-09-27 12:38:24 -04:00
|
|
|
pub fn set_named_registry_value<'lua, S, T>(&'lua self, name: &S, t: T) -> Result<()>
|
2019-09-27 12:27:37 -04:00
|
|
|
where
|
2021-05-02 05:38:33 -04:00
|
|
|
S: AsRef<[u8]> + ?Sized,
|
2019-09-27 12:27:37 -04:00
|
|
|
T: ToLua<'lua>,
|
|
|
|
{
|
2018-03-19 15:16:40 -04:00
|
|
|
let t = t.to_lua(self)?;
|
2017-12-16 17:44:13 -05:00
|
|
|
unsafe {
|
2018-03-12 13:13:44 -04:00
|
|
|
let _sg = StackGuard::new(self.state);
|
2021-05-02 05:38:33 -04:00
|
|
|
check_stack(self.state, 5)?;
|
2017-12-17 00:19:59 -05:00
|
|
|
|
2019-09-27 12:27:37 -04:00
|
|
|
self.push_value(t)?;
|
2021-06-16 17:13:11 -04:00
|
|
|
rawset_field(self.state, ffi::LUA_REGISTRYINDEX, name)
|
2017-12-16 17:44:13 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-16 18:05:53 -05:00
|
|
|
/// Get a value from the Lua registry based on a string name.
|
2017-12-16 17:44:13 -05:00
|
|
|
///
|
2018-02-11 17:54:17 -05:00
|
|
|
/// Any Lua instance which shares the underlying main state may call this method to
|
|
|
|
/// get a value previously set by [`set_named_registry_value`].
|
|
|
|
///
|
|
|
|
/// [`set_named_registry_value`]: #method.set_named_registry_value
|
2019-09-27 12:27:37 -04:00
|
|
|
pub fn named_registry_value<'lua, S, T>(&'lua self, name: &S) -> Result<T>
|
|
|
|
where
|
2021-05-02 05:38:33 -04:00
|
|
|
S: AsRef<[u8]> + ?Sized,
|
2019-09-27 12:27:37 -04:00
|
|
|
T: FromLua<'lua>,
|
|
|
|
{
|
2018-03-19 15:16:40 -04:00
|
|
|
let value = unsafe {
|
2018-03-12 13:13:44 -04:00
|
|
|
let _sg = StackGuard::new(self.state);
|
2021-05-02 05:38:33 -04:00
|
|
|
check_stack(self.state, 3)?;
|
2017-12-17 00:19:59 -05:00
|
|
|
|
2021-06-16 17:13:11 -04:00
|
|
|
push_string(self.state, name)?;
|
2021-04-09 07:05:03 -04:00
|
|
|
ffi::lua_rawget(self.state, ffi::LUA_REGISTRYINDEX);
|
2017-12-17 00:19:59 -05:00
|
|
|
|
2018-03-19 15:16:40 -04:00
|
|
|
self.pop_value()
|
|
|
|
};
|
|
|
|
T::from_lua(value, self)
|
2017-12-16 17:44:13 -05:00
|
|
|
}
|
|
|
|
|
2017-12-17 00:19:59 -05:00
|
|
|
/// Removes a named value in the Lua registry.
|
2017-12-16 18:05:53 -05:00
|
|
|
///
|
2018-02-11 18:17:15 -05:00
|
|
|
/// Equivalent to calling [`set_named_registry_value`] with a value of Nil.
|
2018-02-11 17:54:17 -05:00
|
|
|
///
|
|
|
|
/// [`set_named_registry_value`]: #method.set_named_registry_value
|
2020-05-04 06:56:42 -04:00
|
|
|
pub fn unset_named_registry_value<S>(&self, name: &S) -> Result<()>
|
2019-09-27 12:27:37 -04:00
|
|
|
where
|
2021-05-02 05:38:33 -04:00
|
|
|
S: AsRef<[u8]> + ?Sized,
|
2019-09-27 12:27:37 -04:00
|
|
|
{
|
2017-12-16 18:05:53 -05:00
|
|
|
self.set_named_registry_value(name, Nil)
|
|
|
|
}
|
|
|
|
|
2017-12-17 00:19:59 -05:00
|
|
|
/// Place a value in the Lua registry with an auto-generated key.
|
|
|
|
///
|
|
|
|
/// This value will be available to rust from all `Lua` instances which share the same main
|
2018-02-06 03:33:19 -05:00
|
|
|
/// state.
|
2019-09-27 12:27:37 -04:00
|
|
|
///
|
|
|
|
/// Be warned, garbage collection of values held inside the registry is not automatic, see
|
|
|
|
/// [`RegistryKey`] for more details.
|
|
|
|
///
|
|
|
|
/// [`RegistryKey`]: struct.RegistryKey.html
|
2017-12-17 00:19:59 -05:00
|
|
|
pub fn create_registry_value<'lua, T: ToLua<'lua>>(&'lua self, t: T) -> Result<RegistryKey> {
|
2018-03-19 15:16:40 -04:00
|
|
|
let t = t.to_lua(self)?;
|
2017-12-17 00:19:59 -05:00
|
|
|
unsafe {
|
2018-03-12 13:13:44 -04:00
|
|
|
let _sg = StackGuard::new(self.state);
|
2021-05-02 05:38:33 -04:00
|
|
|
check_stack(self.state, 4)?;
|
2017-12-17 00:19:59 -05:00
|
|
|
|
2019-09-27 12:27:37 -04:00
|
|
|
self.push_value(t)?;
|
2021-07-08 13:41:10 -04:00
|
|
|
let registry_id = protect_lua(self.state, 1, 0, |state| {
|
2021-06-16 17:13:11 -04:00
|
|
|
ffi::luaL_ref(state, ffi::LUA_REGISTRYINDEX)
|
|
|
|
})?;
|
2017-12-17 00:19:59 -05:00
|
|
|
|
2018-03-12 13:13:44 -04:00
|
|
|
Ok(RegistryKey {
|
|
|
|
registry_id,
|
2021-07-08 12:32:20 -04:00
|
|
|
unref_list: (*self.extra).registry_unref_list.clone(),
|
2017-12-17 00:19:59 -05:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get a value from the Lua registry by its `RegistryKey`
|
|
|
|
///
|
2018-02-11 17:54:17 -05:00
|
|
|
/// Any Lua instance which shares the underlying main state may call this method to get a value
|
|
|
|
/// previously placed by [`create_registry_value`].
|
|
|
|
///
|
|
|
|
/// [`create_registry_value`]: #method.create_registry_value
|
2017-12-17 00:19:59 -05:00
|
|
|
pub fn registry_value<'lua, T: FromLua<'lua>>(&'lua self, key: &RegistryKey) -> Result<T> {
|
2021-05-02 05:38:33 -04:00
|
|
|
if !self.owns_registry_value(key) {
|
|
|
|
return Err(Error::MismatchedRegistryKey);
|
|
|
|
}
|
2018-01-26 19:27:41 -05:00
|
|
|
|
2021-05-02 05:38:33 -04:00
|
|
|
let value = unsafe {
|
2018-03-12 13:13:44 -04:00
|
|
|
let _sg = StackGuard::new(self.state);
|
2021-05-02 05:38:33 -04:00
|
|
|
check_stack(self.state, 1)?;
|
2018-03-12 13:13:44 -04:00
|
|
|
|
|
|
|
ffi::lua_rawgeti(
|
|
|
|
self.state,
|
|
|
|
ffi::LUA_REGISTRYINDEX,
|
2021-04-09 07:05:03 -04:00
|
|
|
key.registry_id as Integer,
|
2018-03-12 13:13:44 -04:00
|
|
|
);
|
2018-03-19 15:16:40 -04:00
|
|
|
self.pop_value()
|
|
|
|
};
|
|
|
|
T::from_lua(value, self)
|
2017-12-17 00:19:59 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Removes a value from the Lua registry.
|
|
|
|
///
|
2018-02-06 03:33:19 -05:00
|
|
|
/// You may call this function to manually remove a value placed in the registry with
|
2018-02-11 17:54:17 -05:00
|
|
|
/// [`create_registry_value`]. In addition to manual `RegistryKey` removal, you can also call
|
|
|
|
/// [`expire_registry_values`] to automatically remove values from the registry whose
|
2018-02-06 03:33:19 -05:00
|
|
|
/// `RegistryKey`s have been dropped.
|
2018-02-11 17:54:17 -05:00
|
|
|
///
|
|
|
|
/// [`create_registry_value`]: #method.create_registry_value
|
|
|
|
/// [`expire_registry_values`]: #method.expire_registry_values
|
A lot of performance changes.
Okay, so this is kind of a mega-commit of a lot of performance related changes
to rlua, some of which are pretty complicated.
There are some small improvements here and there, but most of the benefits of
this change are from a few big changes. The simplest big change is that there
is now `protect_lua` as well as `protect_lua_call`, which allows skipping a
lightuserdata parameter and some stack manipulation in some cases. Second
simplest is the change to use Vec instead of VecDeque for MultiValue, and to
have MultiValue be used as a sort of "backwards-only" Vec so that ToLuaMulti /
FromLuaMulti still work correctly.
The most complex change, though, is a change to the way LuaRef works, so that
LuaRef can optionally point into the Lua stack instead of only registry values.
At state creation a set number of stack slots is reserved for the first N LuaRef
types (currently 16), and space for these are also allocated separately
allocated at callback time. There is a huge breaking change here, which is that
now any LuaRef types MUST only be used with the Lua on which they were created,
and CANNOT be used with any other Lua callback instance. This mostly will
affect people using LuaRef types from inside a scope callback, but hopefully in
those cases `Function::bind` will be a suitable replacement. On the plus side,
the rules for LuaRef types are easier to state now.
There is probably more easy-ish perf on the table here, but here's the
preliminary results, based on my very limited benchmarks:
create table time: [314.13 ns 315.71 ns 317.44 ns]
change: [-36.154% -35.670% -35.205%] (p = 0.00 < 0.05)
create array 10 time: [2.9731 us 2.9816 us 2.9901 us]
change: [-16.996% -16.600% -16.196%] (p = 0.00 < 0.05)
Performance has improved.
create string table 10 time: [5.6904 us 5.7164 us 5.7411 us]
change: [-53.536% -53.309% -53.079%] (p = 0.00 < 0.05)
Performance has improved.
call add function 3 10 time: [5.1134 us 5.1222 us 5.1320 us]
change: [-4.1095% -3.6910% -3.1781%] (p = 0.00 < 0.05)
Performance has improved.
call callback add 2 10 time: [5.4408 us 5.4480 us 5.4560 us]
change: [-6.4203% -5.7780% -5.0013%] (p = 0.00 < 0.05)
Performance has improved.
call callback append 10 time: [9.8243 us 9.8410 us 9.8586 us]
change: [-26.937% -26.702% -26.469%] (p = 0.00 < 0.05)
Performance has improved.
create registry 10 time: [3.7005 us 3.7089 us 3.7174 us]
change: [-8.4965% -8.1042% -7.6926%] (p = 0.00 < 0.05)
Performance has improved.
I think that a lot of these benchmarks are too "easy", and most API usage is
going to be more like the 'create string table 10' benchmark, where there are a
lot of handles and tables and strings, so I think that 25%-50% improvement is a
good guess for most use cases.
2018-03-11 23:20:10 -04:00
|
|
|
pub fn remove_registry_value(&self, key: RegistryKey) -> Result<()> {
|
2021-05-02 05:38:33 -04:00
|
|
|
if !self.owns_registry_value(&key) {
|
|
|
|
return Err(Error::MismatchedRegistryKey);
|
|
|
|
}
|
2017-12-17 00:19:59 -05:00
|
|
|
unsafe {
|
A lot of performance changes.
Okay, so this is kind of a mega-commit of a lot of performance related changes
to rlua, some of which are pretty complicated.
There are some small improvements here and there, but most of the benefits of
this change are from a few big changes. The simplest big change is that there
is now `protect_lua` as well as `protect_lua_call`, which allows skipping a
lightuserdata parameter and some stack manipulation in some cases. Second
simplest is the change to use Vec instead of VecDeque for MultiValue, and to
have MultiValue be used as a sort of "backwards-only" Vec so that ToLuaMulti /
FromLuaMulti still work correctly.
The most complex change, though, is a change to the way LuaRef works, so that
LuaRef can optionally point into the Lua stack instead of only registry values.
At state creation a set number of stack slots is reserved for the first N LuaRef
types (currently 16), and space for these are also allocated separately
allocated at callback time. There is a huge breaking change here, which is that
now any LuaRef types MUST only be used with the Lua on which they were created,
and CANNOT be used with any other Lua callback instance. This mostly will
affect people using LuaRef types from inside a scope callback, but hopefully in
those cases `Function::bind` will be a suitable replacement. On the plus side,
the rules for LuaRef types are easier to state now.
There is probably more easy-ish perf on the table here, but here's the
preliminary results, based on my very limited benchmarks:
create table time: [314.13 ns 315.71 ns 317.44 ns]
change: [-36.154% -35.670% -35.205%] (p = 0.00 < 0.05)
create array 10 time: [2.9731 us 2.9816 us 2.9901 us]
change: [-16.996% -16.600% -16.196%] (p = 0.00 < 0.05)
Performance has improved.
create string table 10 time: [5.6904 us 5.7164 us 5.7411 us]
change: [-53.536% -53.309% -53.079%] (p = 0.00 < 0.05)
Performance has improved.
call add function 3 10 time: [5.1134 us 5.1222 us 5.1320 us]
change: [-4.1095% -3.6910% -3.1781%] (p = 0.00 < 0.05)
Performance has improved.
call callback add 2 10 time: [5.4408 us 5.4480 us 5.4560 us]
change: [-6.4203% -5.7780% -5.0013%] (p = 0.00 < 0.05)
Performance has improved.
call callback append 10 time: [9.8243 us 9.8410 us 9.8586 us]
change: [-26.937% -26.702% -26.469%] (p = 0.00 < 0.05)
Performance has improved.
create registry 10 time: [3.7005 us 3.7089 us 3.7174 us]
change: [-8.4965% -8.1042% -7.6926%] (p = 0.00 < 0.05)
Performance has improved.
I think that a lot of these benchmarks are too "easy", and most API usage is
going to be more like the 'create string table 10' benchmark, where there are a
lot of handles and tables and strings, so I think that 25%-50% improvement is a
good guess for most use cases.
2018-03-11 23:20:10 -04:00
|
|
|
ffi::luaL_unref(self.state, ffi::LUA_REGISTRYINDEX, key.take());
|
2017-12-17 00:19:59 -05:00
|
|
|
}
|
2021-05-02 05:38:33 -04:00
|
|
|
Ok(())
|
2017-12-17 00:19:59 -05:00
|
|
|
}
|
|
|
|
|
2018-02-06 03:33:19 -05:00
|
|
|
/// Returns true if the given `RegistryKey` was created by a `Lua` which shares the underlying
|
|
|
|
/// main state with this `Lua` instance.
|
2018-02-06 00:41:51 -05:00
|
|
|
///
|
2018-02-06 10:51:39 -05:00
|
|
|
/// Other than this, methods that accept a `RegistryKey` will return
|
|
|
|
/// `Error::MismatchedRegistryKey` if passed a `RegistryKey` that was not created with a
|
|
|
|
/// matching `Lua` state.
|
2018-02-06 00:41:51 -05:00
|
|
|
pub fn owns_registry_value(&self, key: &RegistryKey) -> bool {
|
2021-07-08 12:32:20 -04:00
|
|
|
let registry_unref_list = unsafe { &(*self.extra).registry_unref_list };
|
|
|
|
Arc::ptr_eq(&key.unref_list, registry_unref_list)
|
2018-02-06 03:33:19 -05:00
|
|
|
}
|
|
|
|
|
2018-02-11 17:54:17 -05:00
|
|
|
/// Remove any registry values whose `RegistryKey`s have all been dropped.
|
|
|
|
///
|
2018-03-12 17:50:48 -04:00
|
|
|
/// Unlike normal handle values, `RegistryKey`s do not automatically remove themselves on Drop,
|
|
|
|
/// but you can call this method to remove any unreachable registry values not manually removed
|
|
|
|
/// by `Lua::remove_registry_value`.
|
2018-02-06 03:33:19 -05:00
|
|
|
pub fn expire_registry_values(&self) {
|
|
|
|
unsafe {
|
2021-07-08 12:32:20 -04:00
|
|
|
let mut unref_list = mlua_expect!(
|
|
|
|
(*self.extra).registry_unref_list.lock(),
|
|
|
|
"unref list poisoned"
|
|
|
|
);
|
2020-07-28 16:05:46 -04:00
|
|
|
let unref_list = mem::replace(&mut *unref_list, Some(Vec::new()));
|
2019-10-01 11:11:12 -04:00
|
|
|
for id in mlua_expect!(unref_list, "unref list not set") {
|
2018-02-06 03:33:19 -05:00
|
|
|
ffi::luaL_unref(self.state, ffi::LUA_REGISTRYINDEX, id);
|
|
|
|
}
|
|
|
|
}
|
2018-02-06 00:41:51 -05:00
|
|
|
}
|
|
|
|
|
2018-02-09 23:35:29 -05:00
|
|
|
// Uses 2 stack spaces, does not call checkstack
|
2019-10-01 13:11:51 -04:00
|
|
|
pub(crate) unsafe fn push_value(&self, value: Value) -> Result<()> {
|
2017-06-19 02:57:03 -04:00
|
|
|
match value {
|
2017-07-18 16:21:12 -04:00
|
|
|
Value::Nil => {
|
A lot of performance changes.
Okay, so this is kind of a mega-commit of a lot of performance related changes
to rlua, some of which are pretty complicated.
There are some small improvements here and there, but most of the benefits of
this change are from a few big changes. The simplest big change is that there
is now `protect_lua` as well as `protect_lua_call`, which allows skipping a
lightuserdata parameter and some stack manipulation in some cases. Second
simplest is the change to use Vec instead of VecDeque for MultiValue, and to
have MultiValue be used as a sort of "backwards-only" Vec so that ToLuaMulti /
FromLuaMulti still work correctly.
The most complex change, though, is a change to the way LuaRef works, so that
LuaRef can optionally point into the Lua stack instead of only registry values.
At state creation a set number of stack slots is reserved for the first N LuaRef
types (currently 16), and space for these are also allocated separately
allocated at callback time. There is a huge breaking change here, which is that
now any LuaRef types MUST only be used with the Lua on which they were created,
and CANNOT be used with any other Lua callback instance. This mostly will
affect people using LuaRef types from inside a scope callback, but hopefully in
those cases `Function::bind` will be a suitable replacement. On the plus side,
the rules for LuaRef types are easier to state now.
There is probably more easy-ish perf on the table here, but here's the
preliminary results, based on my very limited benchmarks:
create table time: [314.13 ns 315.71 ns 317.44 ns]
change: [-36.154% -35.670% -35.205%] (p = 0.00 < 0.05)
create array 10 time: [2.9731 us 2.9816 us 2.9901 us]
change: [-16.996% -16.600% -16.196%] (p = 0.00 < 0.05)
Performance has improved.
create string table 10 time: [5.6904 us 5.7164 us 5.7411 us]
change: [-53.536% -53.309% -53.079%] (p = 0.00 < 0.05)
Performance has improved.
call add function 3 10 time: [5.1134 us 5.1222 us 5.1320 us]
change: [-4.1095% -3.6910% -3.1781%] (p = 0.00 < 0.05)
Performance has improved.
call callback add 2 10 time: [5.4408 us 5.4480 us 5.4560 us]
change: [-6.4203% -5.7780% -5.0013%] (p = 0.00 < 0.05)
Performance has improved.
call callback append 10 time: [9.8243 us 9.8410 us 9.8586 us]
change: [-26.937% -26.702% -26.469%] (p = 0.00 < 0.05)
Performance has improved.
create registry 10 time: [3.7005 us 3.7089 us 3.7174 us]
change: [-8.4965% -8.1042% -7.6926%] (p = 0.00 < 0.05)
Performance has improved.
I think that a lot of these benchmarks are too "easy", and most API usage is
going to be more like the 'create string table 10' benchmark, where there are a
lot of handles and tables and strings, so I think that 25%-50% improvement is a
good guess for most use cases.
2018-03-11 23:20:10 -04:00
|
|
|
ffi::lua_pushnil(self.state);
|
2017-06-19 02:57:03 -04:00
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-07-18 16:21:12 -04:00
|
|
|
Value::Boolean(b) => {
|
A lot of performance changes.
Okay, so this is kind of a mega-commit of a lot of performance related changes
to rlua, some of which are pretty complicated.
There are some small improvements here and there, but most of the benefits of
this change are from a few big changes. The simplest big change is that there
is now `protect_lua` as well as `protect_lua_call`, which allows skipping a
lightuserdata parameter and some stack manipulation in some cases. Second
simplest is the change to use Vec instead of VecDeque for MultiValue, and to
have MultiValue be used as a sort of "backwards-only" Vec so that ToLuaMulti /
FromLuaMulti still work correctly.
The most complex change, though, is a change to the way LuaRef works, so that
LuaRef can optionally point into the Lua stack instead of only registry values.
At state creation a set number of stack slots is reserved for the first N LuaRef
types (currently 16), and space for these are also allocated separately
allocated at callback time. There is a huge breaking change here, which is that
now any LuaRef types MUST only be used with the Lua on which they were created,
and CANNOT be used with any other Lua callback instance. This mostly will
affect people using LuaRef types from inside a scope callback, but hopefully in
those cases `Function::bind` will be a suitable replacement. On the plus side,
the rules for LuaRef types are easier to state now.
There is probably more easy-ish perf on the table here, but here's the
preliminary results, based on my very limited benchmarks:
create table time: [314.13 ns 315.71 ns 317.44 ns]
change: [-36.154% -35.670% -35.205%] (p = 0.00 < 0.05)
create array 10 time: [2.9731 us 2.9816 us 2.9901 us]
change: [-16.996% -16.600% -16.196%] (p = 0.00 < 0.05)
Performance has improved.
create string table 10 time: [5.6904 us 5.7164 us 5.7411 us]
change: [-53.536% -53.309% -53.079%] (p = 0.00 < 0.05)
Performance has improved.
call add function 3 10 time: [5.1134 us 5.1222 us 5.1320 us]
change: [-4.1095% -3.6910% -3.1781%] (p = 0.00 < 0.05)
Performance has improved.
call callback add 2 10 time: [5.4408 us 5.4480 us 5.4560 us]
change: [-6.4203% -5.7780% -5.0013%] (p = 0.00 < 0.05)
Performance has improved.
call callback append 10 time: [9.8243 us 9.8410 us 9.8586 us]
change: [-26.937% -26.702% -26.469%] (p = 0.00 < 0.05)
Performance has improved.
create registry 10 time: [3.7005 us 3.7089 us 3.7174 us]
change: [-8.4965% -8.1042% -7.6926%] (p = 0.00 < 0.05)
Performance has improved.
I think that a lot of these benchmarks are too "easy", and most API usage is
going to be more like the 'create string table 10' benchmark, where there are a
lot of handles and tables and strings, so I think that 25%-50% improvement is a
good guess for most use cases.
2018-03-11 23:20:10 -04:00
|
|
|
ffi::lua_pushboolean(self.state, if b { 1 } else { 0 });
|
2017-06-19 02:57:03 -04:00
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-07-18 16:21:12 -04:00
|
|
|
Value::LightUserData(ud) => {
|
A lot of performance changes.
Okay, so this is kind of a mega-commit of a lot of performance related changes
to rlua, some of which are pretty complicated.
There are some small improvements here and there, but most of the benefits of
this change are from a few big changes. The simplest big change is that there
is now `protect_lua` as well as `protect_lua_call`, which allows skipping a
lightuserdata parameter and some stack manipulation in some cases. Second
simplest is the change to use Vec instead of VecDeque for MultiValue, and to
have MultiValue be used as a sort of "backwards-only" Vec so that ToLuaMulti /
FromLuaMulti still work correctly.
The most complex change, though, is a change to the way LuaRef works, so that
LuaRef can optionally point into the Lua stack instead of only registry values.
At state creation a set number of stack slots is reserved for the first N LuaRef
types (currently 16), and space for these are also allocated separately
allocated at callback time. There is a huge breaking change here, which is that
now any LuaRef types MUST only be used with the Lua on which they were created,
and CANNOT be used with any other Lua callback instance. This mostly will
affect people using LuaRef types from inside a scope callback, but hopefully in
those cases `Function::bind` will be a suitable replacement. On the plus side,
the rules for LuaRef types are easier to state now.
There is probably more easy-ish perf on the table here, but here's the
preliminary results, based on my very limited benchmarks:
create table time: [314.13 ns 315.71 ns 317.44 ns]
change: [-36.154% -35.670% -35.205%] (p = 0.00 < 0.05)
create array 10 time: [2.9731 us 2.9816 us 2.9901 us]
change: [-16.996% -16.600% -16.196%] (p = 0.00 < 0.05)
Performance has improved.
create string table 10 time: [5.6904 us 5.7164 us 5.7411 us]
change: [-53.536% -53.309% -53.079%] (p = 0.00 < 0.05)
Performance has improved.
call add function 3 10 time: [5.1134 us 5.1222 us 5.1320 us]
change: [-4.1095% -3.6910% -3.1781%] (p = 0.00 < 0.05)
Performance has improved.
call callback add 2 10 time: [5.4408 us 5.4480 us 5.4560 us]
change: [-6.4203% -5.7780% -5.0013%] (p = 0.00 < 0.05)
Performance has improved.
call callback append 10 time: [9.8243 us 9.8410 us 9.8586 us]
change: [-26.937% -26.702% -26.469%] (p = 0.00 < 0.05)
Performance has improved.
create registry 10 time: [3.7005 us 3.7089 us 3.7174 us]
change: [-8.4965% -8.1042% -7.6926%] (p = 0.00 < 0.05)
Performance has improved.
I think that a lot of these benchmarks are too "easy", and most API usage is
going to be more like the 'create string table 10' benchmark, where there are a
lot of handles and tables and strings, so I think that 25%-50% improvement is a
good guess for most use cases.
2018-03-11 23:20:10 -04:00
|
|
|
ffi::lua_pushlightuserdata(self.state, ud.0);
|
2017-06-19 02:57:03 -04:00
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-07-18 16:21:12 -04:00
|
|
|
Value::Integer(i) => {
|
A lot of performance changes.
Okay, so this is kind of a mega-commit of a lot of performance related changes
to rlua, some of which are pretty complicated.
There are some small improvements here and there, but most of the benefits of
this change are from a few big changes. The simplest big change is that there
is now `protect_lua` as well as `protect_lua_call`, which allows skipping a
lightuserdata parameter and some stack manipulation in some cases. Second
simplest is the change to use Vec instead of VecDeque for MultiValue, and to
have MultiValue be used as a sort of "backwards-only" Vec so that ToLuaMulti /
FromLuaMulti still work correctly.
The most complex change, though, is a change to the way LuaRef works, so that
LuaRef can optionally point into the Lua stack instead of only registry values.
At state creation a set number of stack slots is reserved for the first N LuaRef
types (currently 16), and space for these are also allocated separately
allocated at callback time. There is a huge breaking change here, which is that
now any LuaRef types MUST only be used with the Lua on which they were created,
and CANNOT be used with any other Lua callback instance. This mostly will
affect people using LuaRef types from inside a scope callback, but hopefully in
those cases `Function::bind` will be a suitable replacement. On the plus side,
the rules for LuaRef types are easier to state now.
There is probably more easy-ish perf on the table here, but here's the
preliminary results, based on my very limited benchmarks:
create table time: [314.13 ns 315.71 ns 317.44 ns]
change: [-36.154% -35.670% -35.205%] (p = 0.00 < 0.05)
create array 10 time: [2.9731 us 2.9816 us 2.9901 us]
change: [-16.996% -16.600% -16.196%] (p = 0.00 < 0.05)
Performance has improved.
create string table 10 time: [5.6904 us 5.7164 us 5.7411 us]
change: [-53.536% -53.309% -53.079%] (p = 0.00 < 0.05)
Performance has improved.
call add function 3 10 time: [5.1134 us 5.1222 us 5.1320 us]
change: [-4.1095% -3.6910% -3.1781%] (p = 0.00 < 0.05)
Performance has improved.
call callback add 2 10 time: [5.4408 us 5.4480 us 5.4560 us]
change: [-6.4203% -5.7780% -5.0013%] (p = 0.00 < 0.05)
Performance has improved.
call callback append 10 time: [9.8243 us 9.8410 us 9.8586 us]
change: [-26.937% -26.702% -26.469%] (p = 0.00 < 0.05)
Performance has improved.
create registry 10 time: [3.7005 us 3.7089 us 3.7174 us]
change: [-8.4965% -8.1042% -7.6926%] (p = 0.00 < 0.05)
Performance has improved.
I think that a lot of these benchmarks are too "easy", and most API usage is
going to be more like the 'create string table 10' benchmark, where there are a
lot of handles and tables and strings, so I think that 25%-50% improvement is a
good guess for most use cases.
2018-03-11 23:20:10 -04:00
|
|
|
ffi::lua_pushinteger(self.state, i);
|
2017-06-19 02:57:03 -04:00
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-07-18 16:21:12 -04:00
|
|
|
Value::Number(n) => {
|
A lot of performance changes.
Okay, so this is kind of a mega-commit of a lot of performance related changes
to rlua, some of which are pretty complicated.
There are some small improvements here and there, but most of the benefits of
this change are from a few big changes. The simplest big change is that there
is now `protect_lua` as well as `protect_lua_call`, which allows skipping a
lightuserdata parameter and some stack manipulation in some cases. Second
simplest is the change to use Vec instead of VecDeque for MultiValue, and to
have MultiValue be used as a sort of "backwards-only" Vec so that ToLuaMulti /
FromLuaMulti still work correctly.
The most complex change, though, is a change to the way LuaRef works, so that
LuaRef can optionally point into the Lua stack instead of only registry values.
At state creation a set number of stack slots is reserved for the first N LuaRef
types (currently 16), and space for these are also allocated separately
allocated at callback time. There is a huge breaking change here, which is that
now any LuaRef types MUST only be used with the Lua on which they were created,
and CANNOT be used with any other Lua callback instance. This mostly will
affect people using LuaRef types from inside a scope callback, but hopefully in
those cases `Function::bind` will be a suitable replacement. On the plus side,
the rules for LuaRef types are easier to state now.
There is probably more easy-ish perf on the table here, but here's the
preliminary results, based on my very limited benchmarks:
create table time: [314.13 ns 315.71 ns 317.44 ns]
change: [-36.154% -35.670% -35.205%] (p = 0.00 < 0.05)
create array 10 time: [2.9731 us 2.9816 us 2.9901 us]
change: [-16.996% -16.600% -16.196%] (p = 0.00 < 0.05)
Performance has improved.
create string table 10 time: [5.6904 us 5.7164 us 5.7411 us]
change: [-53.536% -53.309% -53.079%] (p = 0.00 < 0.05)
Performance has improved.
call add function 3 10 time: [5.1134 us 5.1222 us 5.1320 us]
change: [-4.1095% -3.6910% -3.1781%] (p = 0.00 < 0.05)
Performance has improved.
call callback add 2 10 time: [5.4408 us 5.4480 us 5.4560 us]
change: [-6.4203% -5.7780% -5.0013%] (p = 0.00 < 0.05)
Performance has improved.
call callback append 10 time: [9.8243 us 9.8410 us 9.8586 us]
change: [-26.937% -26.702% -26.469%] (p = 0.00 < 0.05)
Performance has improved.
create registry 10 time: [3.7005 us 3.7089 us 3.7174 us]
change: [-8.4965% -8.1042% -7.6926%] (p = 0.00 < 0.05)
Performance has improved.
I think that a lot of these benchmarks are too "easy", and most API usage is
going to be more like the 'create string table 10' benchmark, where there are a
lot of handles and tables and strings, so I think that 25%-50% improvement is a
good guess for most use cases.
2018-03-11 23:20:10 -04:00
|
|
|
ffi::lua_pushnumber(self.state, n);
|
2017-06-19 02:57:03 -04:00
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-07-18 16:21:12 -04:00
|
|
|
Value::String(s) => {
|
A lot of performance changes.
Okay, so this is kind of a mega-commit of a lot of performance related changes
to rlua, some of which are pretty complicated.
There are some small improvements here and there, but most of the benefits of
this change are from a few big changes. The simplest big change is that there
is now `protect_lua` as well as `protect_lua_call`, which allows skipping a
lightuserdata parameter and some stack manipulation in some cases. Second
simplest is the change to use Vec instead of VecDeque for MultiValue, and to
have MultiValue be used as a sort of "backwards-only" Vec so that ToLuaMulti /
FromLuaMulti still work correctly.
The most complex change, though, is a change to the way LuaRef works, so that
LuaRef can optionally point into the Lua stack instead of only registry values.
At state creation a set number of stack slots is reserved for the first N LuaRef
types (currently 16), and space for these are also allocated separately
allocated at callback time. There is a huge breaking change here, which is that
now any LuaRef types MUST only be used with the Lua on which they were created,
and CANNOT be used with any other Lua callback instance. This mostly will
affect people using LuaRef types from inside a scope callback, but hopefully in
those cases `Function::bind` will be a suitable replacement. On the plus side,
the rules for LuaRef types are easier to state now.
There is probably more easy-ish perf on the table here, but here's the
preliminary results, based on my very limited benchmarks:
create table time: [314.13 ns 315.71 ns 317.44 ns]
change: [-36.154% -35.670% -35.205%] (p = 0.00 < 0.05)
create array 10 time: [2.9731 us 2.9816 us 2.9901 us]
change: [-16.996% -16.600% -16.196%] (p = 0.00 < 0.05)
Performance has improved.
create string table 10 time: [5.6904 us 5.7164 us 5.7411 us]
change: [-53.536% -53.309% -53.079%] (p = 0.00 < 0.05)
Performance has improved.
call add function 3 10 time: [5.1134 us 5.1222 us 5.1320 us]
change: [-4.1095% -3.6910% -3.1781%] (p = 0.00 < 0.05)
Performance has improved.
call callback add 2 10 time: [5.4408 us 5.4480 us 5.4560 us]
change: [-6.4203% -5.7780% -5.0013%] (p = 0.00 < 0.05)
Performance has improved.
call callback append 10 time: [9.8243 us 9.8410 us 9.8586 us]
change: [-26.937% -26.702% -26.469%] (p = 0.00 < 0.05)
Performance has improved.
create registry 10 time: [3.7005 us 3.7089 us 3.7174 us]
change: [-8.4965% -8.1042% -7.6926%] (p = 0.00 < 0.05)
Performance has improved.
I think that a lot of these benchmarks are too "easy", and most API usage is
going to be more like the 'create string table 10' benchmark, where there are a
lot of handles and tables and strings, so I think that 25%-50% improvement is a
good guess for most use cases.
2018-03-11 23:20:10 -04:00
|
|
|
self.push_ref(&s.0);
|
2017-06-19 02:57:03 -04:00
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-07-18 16:21:12 -04:00
|
|
|
Value::Table(t) => {
|
A lot of performance changes.
Okay, so this is kind of a mega-commit of a lot of performance related changes
to rlua, some of which are pretty complicated.
There are some small improvements here and there, but most of the benefits of
this change are from a few big changes. The simplest big change is that there
is now `protect_lua` as well as `protect_lua_call`, which allows skipping a
lightuserdata parameter and some stack manipulation in some cases. Second
simplest is the change to use Vec instead of VecDeque for MultiValue, and to
have MultiValue be used as a sort of "backwards-only" Vec so that ToLuaMulti /
FromLuaMulti still work correctly.
The most complex change, though, is a change to the way LuaRef works, so that
LuaRef can optionally point into the Lua stack instead of only registry values.
At state creation a set number of stack slots is reserved for the first N LuaRef
types (currently 16), and space for these are also allocated separately
allocated at callback time. There is a huge breaking change here, which is that
now any LuaRef types MUST only be used with the Lua on which they were created,
and CANNOT be used with any other Lua callback instance. This mostly will
affect people using LuaRef types from inside a scope callback, but hopefully in
those cases `Function::bind` will be a suitable replacement. On the plus side,
the rules for LuaRef types are easier to state now.
There is probably more easy-ish perf on the table here, but here's the
preliminary results, based on my very limited benchmarks:
create table time: [314.13 ns 315.71 ns 317.44 ns]
change: [-36.154% -35.670% -35.205%] (p = 0.00 < 0.05)
create array 10 time: [2.9731 us 2.9816 us 2.9901 us]
change: [-16.996% -16.600% -16.196%] (p = 0.00 < 0.05)
Performance has improved.
create string table 10 time: [5.6904 us 5.7164 us 5.7411 us]
change: [-53.536% -53.309% -53.079%] (p = 0.00 < 0.05)
Performance has improved.
call add function 3 10 time: [5.1134 us 5.1222 us 5.1320 us]
change: [-4.1095% -3.6910% -3.1781%] (p = 0.00 < 0.05)
Performance has improved.
call callback add 2 10 time: [5.4408 us 5.4480 us 5.4560 us]
change: [-6.4203% -5.7780% -5.0013%] (p = 0.00 < 0.05)
Performance has improved.
call callback append 10 time: [9.8243 us 9.8410 us 9.8586 us]
change: [-26.937% -26.702% -26.469%] (p = 0.00 < 0.05)
Performance has improved.
create registry 10 time: [3.7005 us 3.7089 us 3.7174 us]
change: [-8.4965% -8.1042% -7.6926%] (p = 0.00 < 0.05)
Performance has improved.
I think that a lot of these benchmarks are too "easy", and most API usage is
going to be more like the 'create string table 10' benchmark, where there are a
lot of handles and tables and strings, so I think that 25%-50% improvement is a
good guess for most use cases.
2018-03-11 23:20:10 -04:00
|
|
|
self.push_ref(&t.0);
|
2017-06-19 02:57:03 -04:00
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-07-18 16:21:12 -04:00
|
|
|
Value::Function(f) => {
|
A lot of performance changes.
Okay, so this is kind of a mega-commit of a lot of performance related changes
to rlua, some of which are pretty complicated.
There are some small improvements here and there, but most of the benefits of
this change are from a few big changes. The simplest big change is that there
is now `protect_lua` as well as `protect_lua_call`, which allows skipping a
lightuserdata parameter and some stack manipulation in some cases. Second
simplest is the change to use Vec instead of VecDeque for MultiValue, and to
have MultiValue be used as a sort of "backwards-only" Vec so that ToLuaMulti /
FromLuaMulti still work correctly.
The most complex change, though, is a change to the way LuaRef works, so that
LuaRef can optionally point into the Lua stack instead of only registry values.
At state creation a set number of stack slots is reserved for the first N LuaRef
types (currently 16), and space for these are also allocated separately
allocated at callback time. There is a huge breaking change here, which is that
now any LuaRef types MUST only be used with the Lua on which they were created,
and CANNOT be used with any other Lua callback instance. This mostly will
affect people using LuaRef types from inside a scope callback, but hopefully in
those cases `Function::bind` will be a suitable replacement. On the plus side,
the rules for LuaRef types are easier to state now.
There is probably more easy-ish perf on the table here, but here's the
preliminary results, based on my very limited benchmarks:
create table time: [314.13 ns 315.71 ns 317.44 ns]
change: [-36.154% -35.670% -35.205%] (p = 0.00 < 0.05)
create array 10 time: [2.9731 us 2.9816 us 2.9901 us]
change: [-16.996% -16.600% -16.196%] (p = 0.00 < 0.05)
Performance has improved.
create string table 10 time: [5.6904 us 5.7164 us 5.7411 us]
change: [-53.536% -53.309% -53.079%] (p = 0.00 < 0.05)
Performance has improved.
call add function 3 10 time: [5.1134 us 5.1222 us 5.1320 us]
change: [-4.1095% -3.6910% -3.1781%] (p = 0.00 < 0.05)
Performance has improved.
call callback add 2 10 time: [5.4408 us 5.4480 us 5.4560 us]
change: [-6.4203% -5.7780% -5.0013%] (p = 0.00 < 0.05)
Performance has improved.
call callback append 10 time: [9.8243 us 9.8410 us 9.8586 us]
change: [-26.937% -26.702% -26.469%] (p = 0.00 < 0.05)
Performance has improved.
create registry 10 time: [3.7005 us 3.7089 us 3.7174 us]
change: [-8.4965% -8.1042% -7.6926%] (p = 0.00 < 0.05)
Performance has improved.
I think that a lot of these benchmarks are too "easy", and most API usage is
going to be more like the 'create string table 10' benchmark, where there are a
lot of handles and tables and strings, so I think that 25%-50% improvement is a
good guess for most use cases.
2018-03-11 23:20:10 -04:00
|
|
|
self.push_ref(&f.0);
|
2017-06-19 02:57:03 -04:00
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-07-18 16:21:12 -04:00
|
|
|
Value::Thread(t) => {
|
A lot of performance changes.
Okay, so this is kind of a mega-commit of a lot of performance related changes
to rlua, some of which are pretty complicated.
There are some small improvements here and there, but most of the benefits of
this change are from a few big changes. The simplest big change is that there
is now `protect_lua` as well as `protect_lua_call`, which allows skipping a
lightuserdata parameter and some stack manipulation in some cases. Second
simplest is the change to use Vec instead of VecDeque for MultiValue, and to
have MultiValue be used as a sort of "backwards-only" Vec so that ToLuaMulti /
FromLuaMulti still work correctly.
The most complex change, though, is a change to the way LuaRef works, so that
LuaRef can optionally point into the Lua stack instead of only registry values.
At state creation a set number of stack slots is reserved for the first N LuaRef
types (currently 16), and space for these are also allocated separately
allocated at callback time. There is a huge breaking change here, which is that
now any LuaRef types MUST only be used with the Lua on which they were created,
and CANNOT be used with any other Lua callback instance. This mostly will
affect people using LuaRef types from inside a scope callback, but hopefully in
those cases `Function::bind` will be a suitable replacement. On the plus side,
the rules for LuaRef types are easier to state now.
There is probably more easy-ish perf on the table here, but here's the
preliminary results, based on my very limited benchmarks:
create table time: [314.13 ns 315.71 ns 317.44 ns]
change: [-36.154% -35.670% -35.205%] (p = 0.00 < 0.05)
create array 10 time: [2.9731 us 2.9816 us 2.9901 us]
change: [-16.996% -16.600% -16.196%] (p = 0.00 < 0.05)
Performance has improved.
create string table 10 time: [5.6904 us 5.7164 us 5.7411 us]
change: [-53.536% -53.309% -53.079%] (p = 0.00 < 0.05)
Performance has improved.
call add function 3 10 time: [5.1134 us 5.1222 us 5.1320 us]
change: [-4.1095% -3.6910% -3.1781%] (p = 0.00 < 0.05)
Performance has improved.
call callback add 2 10 time: [5.4408 us 5.4480 us 5.4560 us]
change: [-6.4203% -5.7780% -5.0013%] (p = 0.00 < 0.05)
Performance has improved.
call callback append 10 time: [9.8243 us 9.8410 us 9.8586 us]
change: [-26.937% -26.702% -26.469%] (p = 0.00 < 0.05)
Performance has improved.
create registry 10 time: [3.7005 us 3.7089 us 3.7174 us]
change: [-8.4965% -8.1042% -7.6926%] (p = 0.00 < 0.05)
Performance has improved.
I think that a lot of these benchmarks are too "easy", and most API usage is
going to be more like the 'create string table 10' benchmark, where there are a
lot of handles and tables and strings, so I think that 25%-50% improvement is a
good guess for most use cases.
2018-03-11 23:20:10 -04:00
|
|
|
self.push_ref(&t.0);
|
2017-06-25 01:47:55 -04:00
|
|
|
}
|
|
|
|
|
2017-07-18 16:21:12 -04:00
|
|
|
Value::UserData(ud) => {
|
A lot of performance changes.
Okay, so this is kind of a mega-commit of a lot of performance related changes
to rlua, some of which are pretty complicated.
There are some small improvements here and there, but most of the benefits of
this change are from a few big changes. The simplest big change is that there
is now `protect_lua` as well as `protect_lua_call`, which allows skipping a
lightuserdata parameter and some stack manipulation in some cases. Second
simplest is the change to use Vec instead of VecDeque for MultiValue, and to
have MultiValue be used as a sort of "backwards-only" Vec so that ToLuaMulti /
FromLuaMulti still work correctly.
The most complex change, though, is a change to the way LuaRef works, so that
LuaRef can optionally point into the Lua stack instead of only registry values.
At state creation a set number of stack slots is reserved for the first N LuaRef
types (currently 16), and space for these are also allocated separately
allocated at callback time. There is a huge breaking change here, which is that
now any LuaRef types MUST only be used with the Lua on which they were created,
and CANNOT be used with any other Lua callback instance. This mostly will
affect people using LuaRef types from inside a scope callback, but hopefully in
those cases `Function::bind` will be a suitable replacement. On the plus side,
the rules for LuaRef types are easier to state now.
There is probably more easy-ish perf on the table here, but here's the
preliminary results, based on my very limited benchmarks:
create table time: [314.13 ns 315.71 ns 317.44 ns]
change: [-36.154% -35.670% -35.205%] (p = 0.00 < 0.05)
create array 10 time: [2.9731 us 2.9816 us 2.9901 us]
change: [-16.996% -16.600% -16.196%] (p = 0.00 < 0.05)
Performance has improved.
create string table 10 time: [5.6904 us 5.7164 us 5.7411 us]
change: [-53.536% -53.309% -53.079%] (p = 0.00 < 0.05)
Performance has improved.
call add function 3 10 time: [5.1134 us 5.1222 us 5.1320 us]
change: [-4.1095% -3.6910% -3.1781%] (p = 0.00 < 0.05)
Performance has improved.
call callback add 2 10 time: [5.4408 us 5.4480 us 5.4560 us]
change: [-6.4203% -5.7780% -5.0013%] (p = 0.00 < 0.05)
Performance has improved.
call callback append 10 time: [9.8243 us 9.8410 us 9.8586 us]
change: [-26.937% -26.702% -26.469%] (p = 0.00 < 0.05)
Performance has improved.
create registry 10 time: [3.7005 us 3.7089 us 3.7174 us]
change: [-8.4965% -8.1042% -7.6926%] (p = 0.00 < 0.05)
Performance has improved.
I think that a lot of these benchmarks are too "easy", and most API usage is
going to be more like the 'create string table 10' benchmark, where there are a
lot of handles and tables and strings, so I think that 25%-50% improvement is a
good guess for most use cases.
2018-03-11 23:20:10 -04:00
|
|
|
self.push_ref(&ud.0);
|
2017-06-19 02:57:03 -04:00
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2021-07-08 19:05:29 -04:00
|
|
|
Value::Error(err) => {
|
|
|
|
push_gc_userdata(self.state, WrappedFailure::Error(err))?;
|
2017-05-25 00:43:35 -04:00
|
|
|
}
|
2017-06-19 02:57:03 -04:00
|
|
|
}
|
2019-09-27 12:27:37 -04:00
|
|
|
|
|
|
|
Ok(())
|
2017-05-25 00:43:35 -04:00
|
|
|
}
|
|
|
|
|
2018-02-12 13:42:13 -05:00
|
|
|
// Uses 2 stack spaces, does not call checkstack
|
2019-10-01 13:11:51 -04:00
|
|
|
pub(crate) unsafe fn pop_value(&self) -> Value {
|
2021-04-15 18:04:36 -04:00
|
|
|
let state = self.state;
|
|
|
|
match ffi::lua_type(state, -1) {
|
2017-05-25 00:43:35 -04:00
|
|
|
ffi::LUA_TNIL => {
|
2021-04-15 18:04:36 -04:00
|
|
|
ffi::lua_pop(state, 1);
|
2017-07-24 07:12:52 -04:00
|
|
|
Nil
|
2017-05-25 00:43:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
ffi::LUA_TBOOLEAN => {
|
2021-04-15 18:04:36 -04:00
|
|
|
let b = Value::Boolean(ffi::lua_toboolean(state, -1) != 0);
|
|
|
|
ffi::lua_pop(state, 1);
|
2017-06-19 02:57:03 -04:00
|
|
|
b
|
2017-05-25 00:43:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
ffi::LUA_TLIGHTUSERDATA => {
|
2021-04-15 18:04:36 -04:00
|
|
|
let ud = Value::LightUserData(LightUserData(ffi::lua_touserdata(state, -1)));
|
|
|
|
ffi::lua_pop(state, 1);
|
2017-06-19 02:57:03 -04:00
|
|
|
ud
|
2017-05-25 00:43:35 -04:00
|
|
|
}
|
|
|
|
|
2019-09-27 12:27:37 -04:00
|
|
|
ffi::LUA_TNUMBER => {
|
2021-04-15 18:04:36 -04:00
|
|
|
if ffi::lua_isinteger(state, -1) != 0 {
|
|
|
|
let i = Value::Integer(ffi::lua_tointeger(state, -1));
|
|
|
|
ffi::lua_pop(state, 1);
|
2019-09-27 12:27:37 -04:00
|
|
|
i
|
|
|
|
} else {
|
2021-04-15 18:04:36 -04:00
|
|
|
let n = Value::Number(ffi::lua_tonumber(state, -1));
|
|
|
|
ffi::lua_pop(state, 1);
|
2019-09-27 12:27:37 -04:00
|
|
|
n
|
|
|
|
}
|
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
|
A lot of performance changes.
Okay, so this is kind of a mega-commit of a lot of performance related changes
to rlua, some of which are pretty complicated.
There are some small improvements here and there, but most of the benefits of
this change are from a few big changes. The simplest big change is that there
is now `protect_lua` as well as `protect_lua_call`, which allows skipping a
lightuserdata parameter and some stack manipulation in some cases. Second
simplest is the change to use Vec instead of VecDeque for MultiValue, and to
have MultiValue be used as a sort of "backwards-only" Vec so that ToLuaMulti /
FromLuaMulti still work correctly.
The most complex change, though, is a change to the way LuaRef works, so that
LuaRef can optionally point into the Lua stack instead of only registry values.
At state creation a set number of stack slots is reserved for the first N LuaRef
types (currently 16), and space for these are also allocated separately
allocated at callback time. There is a huge breaking change here, which is that
now any LuaRef types MUST only be used with the Lua on which they were created,
and CANNOT be used with any other Lua callback instance. This mostly will
affect people using LuaRef types from inside a scope callback, but hopefully in
those cases `Function::bind` will be a suitable replacement. On the plus side,
the rules for LuaRef types are easier to state now.
There is probably more easy-ish perf on the table here, but here's the
preliminary results, based on my very limited benchmarks:
create table time: [314.13 ns 315.71 ns 317.44 ns]
change: [-36.154% -35.670% -35.205%] (p = 0.00 < 0.05)
create array 10 time: [2.9731 us 2.9816 us 2.9901 us]
change: [-16.996% -16.600% -16.196%] (p = 0.00 < 0.05)
Performance has improved.
create string table 10 time: [5.6904 us 5.7164 us 5.7411 us]
change: [-53.536% -53.309% -53.079%] (p = 0.00 < 0.05)
Performance has improved.
call add function 3 10 time: [5.1134 us 5.1222 us 5.1320 us]
change: [-4.1095% -3.6910% -3.1781%] (p = 0.00 < 0.05)
Performance has improved.
call callback add 2 10 time: [5.4408 us 5.4480 us 5.4560 us]
change: [-6.4203% -5.7780% -5.0013%] (p = 0.00 < 0.05)
Performance has improved.
call callback append 10 time: [9.8243 us 9.8410 us 9.8586 us]
change: [-26.937% -26.702% -26.469%] (p = 0.00 < 0.05)
Performance has improved.
create registry 10 time: [3.7005 us 3.7089 us 3.7174 us]
change: [-8.4965% -8.1042% -7.6926%] (p = 0.00 < 0.05)
Performance has improved.
I think that a lot of these benchmarks are too "easy", and most API usage is
going to be more like the 'create string table 10' benchmark, where there are a
lot of handles and tables and strings, so I think that 25%-50% improvement is a
good guess for most use cases.
2018-03-11 23:20:10 -04:00
|
|
|
ffi::LUA_TSTRING => Value::String(String(self.pop_ref())),
|
2017-05-25 00:43:35 -04:00
|
|
|
|
A lot of performance changes.
Okay, so this is kind of a mega-commit of a lot of performance related changes
to rlua, some of which are pretty complicated.
There are some small improvements here and there, but most of the benefits of
this change are from a few big changes. The simplest big change is that there
is now `protect_lua` as well as `protect_lua_call`, which allows skipping a
lightuserdata parameter and some stack manipulation in some cases. Second
simplest is the change to use Vec instead of VecDeque for MultiValue, and to
have MultiValue be used as a sort of "backwards-only" Vec so that ToLuaMulti /
FromLuaMulti still work correctly.
The most complex change, though, is a change to the way LuaRef works, so that
LuaRef can optionally point into the Lua stack instead of only registry values.
At state creation a set number of stack slots is reserved for the first N LuaRef
types (currently 16), and space for these are also allocated separately
allocated at callback time. There is a huge breaking change here, which is that
now any LuaRef types MUST only be used with the Lua on which they were created,
and CANNOT be used with any other Lua callback instance. This mostly will
affect people using LuaRef types from inside a scope callback, but hopefully in
those cases `Function::bind` will be a suitable replacement. On the plus side,
the rules for LuaRef types are easier to state now.
There is probably more easy-ish perf on the table here, but here's the
preliminary results, based on my very limited benchmarks:
create table time: [314.13 ns 315.71 ns 317.44 ns]
change: [-36.154% -35.670% -35.205%] (p = 0.00 < 0.05)
create array 10 time: [2.9731 us 2.9816 us 2.9901 us]
change: [-16.996% -16.600% -16.196%] (p = 0.00 < 0.05)
Performance has improved.
create string table 10 time: [5.6904 us 5.7164 us 5.7411 us]
change: [-53.536% -53.309% -53.079%] (p = 0.00 < 0.05)
Performance has improved.
call add function 3 10 time: [5.1134 us 5.1222 us 5.1320 us]
change: [-4.1095% -3.6910% -3.1781%] (p = 0.00 < 0.05)
Performance has improved.
call callback add 2 10 time: [5.4408 us 5.4480 us 5.4560 us]
change: [-6.4203% -5.7780% -5.0013%] (p = 0.00 < 0.05)
Performance has improved.
call callback append 10 time: [9.8243 us 9.8410 us 9.8586 us]
change: [-26.937% -26.702% -26.469%] (p = 0.00 < 0.05)
Performance has improved.
create registry 10 time: [3.7005 us 3.7089 us 3.7174 us]
change: [-8.4965% -8.1042% -7.6926%] (p = 0.00 < 0.05)
Performance has improved.
I think that a lot of these benchmarks are too "easy", and most API usage is
going to be more like the 'create string table 10' benchmark, where there are a
lot of handles and tables and strings, so I think that 25%-50% improvement is a
good guess for most use cases.
2018-03-11 23:20:10 -04:00
|
|
|
ffi::LUA_TTABLE => Value::Table(Table(self.pop_ref())),
|
2017-05-25 00:43:35 -04:00
|
|
|
|
A lot of performance changes.
Okay, so this is kind of a mega-commit of a lot of performance related changes
to rlua, some of which are pretty complicated.
There are some small improvements here and there, but most of the benefits of
this change are from a few big changes. The simplest big change is that there
is now `protect_lua` as well as `protect_lua_call`, which allows skipping a
lightuserdata parameter and some stack manipulation in some cases. Second
simplest is the change to use Vec instead of VecDeque for MultiValue, and to
have MultiValue be used as a sort of "backwards-only" Vec so that ToLuaMulti /
FromLuaMulti still work correctly.
The most complex change, though, is a change to the way LuaRef works, so that
LuaRef can optionally point into the Lua stack instead of only registry values.
At state creation a set number of stack slots is reserved for the first N LuaRef
types (currently 16), and space for these are also allocated separately
allocated at callback time. There is a huge breaking change here, which is that
now any LuaRef types MUST only be used with the Lua on which they were created,
and CANNOT be used with any other Lua callback instance. This mostly will
affect people using LuaRef types from inside a scope callback, but hopefully in
those cases `Function::bind` will be a suitable replacement. On the plus side,
the rules for LuaRef types are easier to state now.
There is probably more easy-ish perf on the table here, but here's the
preliminary results, based on my very limited benchmarks:
create table time: [314.13 ns 315.71 ns 317.44 ns]
change: [-36.154% -35.670% -35.205%] (p = 0.00 < 0.05)
create array 10 time: [2.9731 us 2.9816 us 2.9901 us]
change: [-16.996% -16.600% -16.196%] (p = 0.00 < 0.05)
Performance has improved.
create string table 10 time: [5.6904 us 5.7164 us 5.7411 us]
change: [-53.536% -53.309% -53.079%] (p = 0.00 < 0.05)
Performance has improved.
call add function 3 10 time: [5.1134 us 5.1222 us 5.1320 us]
change: [-4.1095% -3.6910% -3.1781%] (p = 0.00 < 0.05)
Performance has improved.
call callback add 2 10 time: [5.4408 us 5.4480 us 5.4560 us]
change: [-6.4203% -5.7780% -5.0013%] (p = 0.00 < 0.05)
Performance has improved.
call callback append 10 time: [9.8243 us 9.8410 us 9.8586 us]
change: [-26.937% -26.702% -26.469%] (p = 0.00 < 0.05)
Performance has improved.
create registry 10 time: [3.7005 us 3.7089 us 3.7174 us]
change: [-8.4965% -8.1042% -7.6926%] (p = 0.00 < 0.05)
Performance has improved.
I think that a lot of these benchmarks are too "easy", and most API usage is
going to be more like the 'create string table 10' benchmark, where there are a
lot of handles and tables and strings, so I think that 25%-50% improvement is a
good guess for most use cases.
2018-03-11 23:20:10 -04:00
|
|
|
ffi::LUA_TFUNCTION => Value::Function(Function(self.pop_ref())),
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-06-25 01:47:55 -04:00
|
|
|
ffi::LUA_TUSERDATA => {
|
2021-04-15 18:04:36 -04:00
|
|
|
// We must prevent interaction with userdata types other than UserData OR a WrappedError.
|
|
|
|
// WrappedPanics are automatically resumed.
|
2021-07-08 19:05:29 -04:00
|
|
|
match get_gc_userdata::<WrappedFailure>(state, -1).as_mut() {
|
|
|
|
Some(WrappedFailure::Error(err)) => {
|
|
|
|
let err = err.clone();
|
2021-04-15 18:04:36 -04:00
|
|
|
ffi::lua_pop(state, 1);
|
2021-07-08 19:05:29 -04:00
|
|
|
Value::Error(err)
|
2021-04-15 18:04:36 -04:00
|
|
|
}
|
2021-07-08 19:05:29 -04:00
|
|
|
Some(WrappedFailure::Panic(panic)) => {
|
|
|
|
if let Some(panic) = panic.take() {
|
|
|
|
ffi::lua_pop(state, 1);
|
|
|
|
resume_unwind(panic);
|
|
|
|
}
|
|
|
|
// Previously resumed panic?
|
|
|
|
ffi::lua_pop(state, 1);
|
|
|
|
Nil
|
|
|
|
}
|
|
|
|
_ => Value::UserData(AnyUserData(self.pop_ref())),
|
2017-06-25 01:47:55 -04:00
|
|
|
}
|
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
|
A lot of performance changes.
Okay, so this is kind of a mega-commit of a lot of performance related changes
to rlua, some of which are pretty complicated.
There are some small improvements here and there, but most of the benefits of
this change are from a few big changes. The simplest big change is that there
is now `protect_lua` as well as `protect_lua_call`, which allows skipping a
lightuserdata parameter and some stack manipulation in some cases. Second
simplest is the change to use Vec instead of VecDeque for MultiValue, and to
have MultiValue be used as a sort of "backwards-only" Vec so that ToLuaMulti /
FromLuaMulti still work correctly.
The most complex change, though, is a change to the way LuaRef works, so that
LuaRef can optionally point into the Lua stack instead of only registry values.
At state creation a set number of stack slots is reserved for the first N LuaRef
types (currently 16), and space for these are also allocated separately
allocated at callback time. There is a huge breaking change here, which is that
now any LuaRef types MUST only be used with the Lua on which they were created,
and CANNOT be used with any other Lua callback instance. This mostly will
affect people using LuaRef types from inside a scope callback, but hopefully in
those cases `Function::bind` will be a suitable replacement. On the plus side,
the rules for LuaRef types are easier to state now.
There is probably more easy-ish perf on the table here, but here's the
preliminary results, based on my very limited benchmarks:
create table time: [314.13 ns 315.71 ns 317.44 ns]
change: [-36.154% -35.670% -35.205%] (p = 0.00 < 0.05)
create array 10 time: [2.9731 us 2.9816 us 2.9901 us]
change: [-16.996% -16.600% -16.196%] (p = 0.00 < 0.05)
Performance has improved.
create string table 10 time: [5.6904 us 5.7164 us 5.7411 us]
change: [-53.536% -53.309% -53.079%] (p = 0.00 < 0.05)
Performance has improved.
call add function 3 10 time: [5.1134 us 5.1222 us 5.1320 us]
change: [-4.1095% -3.6910% -3.1781%] (p = 0.00 < 0.05)
Performance has improved.
call callback add 2 10 time: [5.4408 us 5.4480 us 5.4560 us]
change: [-6.4203% -5.7780% -5.0013%] (p = 0.00 < 0.05)
Performance has improved.
call callback append 10 time: [9.8243 us 9.8410 us 9.8586 us]
change: [-26.937% -26.702% -26.469%] (p = 0.00 < 0.05)
Performance has improved.
create registry 10 time: [3.7005 us 3.7089 us 3.7174 us]
change: [-8.4965% -8.1042% -7.6926%] (p = 0.00 < 0.05)
Performance has improved.
I think that a lot of these benchmarks are too "easy", and most API usage is
going to be more like the 'create string table 10' benchmark, where there are a
lot of handles and tables and strings, so I think that 25%-50% improvement is a
good guess for most use cases.
2018-03-11 23:20:10 -04:00
|
|
|
ffi::LUA_TTHREAD => Value::Thread(Thread(self.pop_ref())),
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2019-10-01 11:11:12 -04:00
|
|
|
_ => mlua_panic!("LUA_TNONE in pop_value"),
|
2017-06-19 02:57:03 -04:00
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
}
|
|
|
|
|
2018-03-28 01:09:51 -04:00
|
|
|
// Pushes a LuaRef value onto the stack, uses 1 stack space, does not call checkstack
|
|
|
|
pub(crate) unsafe fn push_ref<'lua>(&'lua self, lref: &LuaRef<'lua>) {
|
2018-03-12 22:25:45 -04:00
|
|
|
assert!(
|
2021-07-08 12:32:20 -04:00
|
|
|
lref.lua.extra == self.extra,
|
2018-03-28 01:09:51 -04:00
|
|
|
"Lua instance passed Value created from a different main Lua state"
|
2018-03-12 22:25:45 -04:00
|
|
|
);
|
2021-07-08 12:32:20 -04:00
|
|
|
ffi::lua_pushvalue((*self.extra).ref_thread, lref.index);
|
|
|
|
ffi::lua_xmove((*self.extra).ref_thread, self.state, 1);
|
2017-05-25 00:43:35 -04:00
|
|
|
}
|
|
|
|
|
2021-05-02 05:38:33 -04:00
|
|
|
// Pops the topmost element of the stack and stores a reference to it. This pins the object,
|
2018-03-28 01:09:51 -04:00
|
|
|
// preventing garbage collection until the returned `LuaRef` is dropped.
|
2017-10-24 08:53:26 -04:00
|
|
|
//
|
2019-09-27 12:27:37 -04:00
|
|
|
// References are stored in the stack of a specially created auxiliary thread that exists only
|
2021-05-02 05:38:33 -04:00
|
|
|
// to store reference values. This is much faster than storing these in the registry, and also
|
2018-03-28 01:09:51 -04:00
|
|
|
// much more flexible and requires less bookkeeping than storing them directly in the currently
|
2021-05-02 05:38:33 -04:00
|
|
|
// used stack. The implementation is somewhat biased towards the use case of a relatively small
|
2018-03-28 01:09:51 -04:00
|
|
|
// number of short term references being created, and `RegistryKey` being used for long term
|
|
|
|
// references.
|
2020-05-12 18:34:42 -04:00
|
|
|
pub(crate) unsafe fn pop_ref(&self) -> LuaRef {
|
2021-07-08 12:32:20 -04:00
|
|
|
let extra = &mut *self.extra;
|
2019-10-15 07:58:02 -04:00
|
|
|
ffi::lua_xmove(self.state, extra.ref_thread, 1);
|
2021-07-08 12:32:20 -04:00
|
|
|
let index = ref_stack_pop(extra);
|
2018-03-28 01:09:51 -04:00
|
|
|
LuaRef { lua: self, index }
|
A lot of performance changes.
Okay, so this is kind of a mega-commit of a lot of performance related changes
to rlua, some of which are pretty complicated.
There are some small improvements here and there, but most of the benefits of
this change are from a few big changes. The simplest big change is that there
is now `protect_lua` as well as `protect_lua_call`, which allows skipping a
lightuserdata parameter and some stack manipulation in some cases. Second
simplest is the change to use Vec instead of VecDeque for MultiValue, and to
have MultiValue be used as a sort of "backwards-only" Vec so that ToLuaMulti /
FromLuaMulti still work correctly.
The most complex change, though, is a change to the way LuaRef works, so that
LuaRef can optionally point into the Lua stack instead of only registry values.
At state creation a set number of stack slots is reserved for the first N LuaRef
types (currently 16), and space for these are also allocated separately
allocated at callback time. There is a huge breaking change here, which is that
now any LuaRef types MUST only be used with the Lua on which they were created,
and CANNOT be used with any other Lua callback instance. This mostly will
affect people using LuaRef types from inside a scope callback, but hopefully in
those cases `Function::bind` will be a suitable replacement. On the plus side,
the rules for LuaRef types are easier to state now.
There is probably more easy-ish perf on the table here, but here's the
preliminary results, based on my very limited benchmarks:
create table time: [314.13 ns 315.71 ns 317.44 ns]
change: [-36.154% -35.670% -35.205%] (p = 0.00 < 0.05)
create array 10 time: [2.9731 us 2.9816 us 2.9901 us]
change: [-16.996% -16.600% -16.196%] (p = 0.00 < 0.05)
Performance has improved.
create string table 10 time: [5.6904 us 5.7164 us 5.7411 us]
change: [-53.536% -53.309% -53.079%] (p = 0.00 < 0.05)
Performance has improved.
call add function 3 10 time: [5.1134 us 5.1222 us 5.1320 us]
change: [-4.1095% -3.6910% -3.1781%] (p = 0.00 < 0.05)
Performance has improved.
call callback add 2 10 time: [5.4408 us 5.4480 us 5.4560 us]
change: [-6.4203% -5.7780% -5.0013%] (p = 0.00 < 0.05)
Performance has improved.
call callback append 10 time: [9.8243 us 9.8410 us 9.8586 us]
change: [-26.937% -26.702% -26.469%] (p = 0.00 < 0.05)
Performance has improved.
create registry 10 time: [3.7005 us 3.7089 us 3.7174 us]
change: [-8.4965% -8.1042% -7.6926%] (p = 0.00 < 0.05)
Performance has improved.
I think that a lot of these benchmarks are too "easy", and most API usage is
going to be more like the 'create string table 10' benchmark, where there are a
lot of handles and tables and strings, so I think that 25%-50% improvement is a
good guess for most use cases.
2018-03-11 23:20:10 -04:00
|
|
|
}
|
|
|
|
|
2018-03-28 01:09:51 -04:00
|
|
|
pub(crate) fn clone_ref<'lua>(&'lua self, lref: &LuaRef<'lua>) -> LuaRef<'lua> {
|
A lot of performance changes.
Okay, so this is kind of a mega-commit of a lot of performance related changes
to rlua, some of which are pretty complicated.
There are some small improvements here and there, but most of the benefits of
this change are from a few big changes. The simplest big change is that there
is now `protect_lua` as well as `protect_lua_call`, which allows skipping a
lightuserdata parameter and some stack manipulation in some cases. Second
simplest is the change to use Vec instead of VecDeque for MultiValue, and to
have MultiValue be used as a sort of "backwards-only" Vec so that ToLuaMulti /
FromLuaMulti still work correctly.
The most complex change, though, is a change to the way LuaRef works, so that
LuaRef can optionally point into the Lua stack instead of only registry values.
At state creation a set number of stack slots is reserved for the first N LuaRef
types (currently 16), and space for these are also allocated separately
allocated at callback time. There is a huge breaking change here, which is that
now any LuaRef types MUST only be used with the Lua on which they were created,
and CANNOT be used with any other Lua callback instance. This mostly will
affect people using LuaRef types from inside a scope callback, but hopefully in
those cases `Function::bind` will be a suitable replacement. On the plus side,
the rules for LuaRef types are easier to state now.
There is probably more easy-ish perf on the table here, but here's the
preliminary results, based on my very limited benchmarks:
create table time: [314.13 ns 315.71 ns 317.44 ns]
change: [-36.154% -35.670% -35.205%] (p = 0.00 < 0.05)
create array 10 time: [2.9731 us 2.9816 us 2.9901 us]
change: [-16.996% -16.600% -16.196%] (p = 0.00 < 0.05)
Performance has improved.
create string table 10 time: [5.6904 us 5.7164 us 5.7411 us]
change: [-53.536% -53.309% -53.079%] (p = 0.00 < 0.05)
Performance has improved.
call add function 3 10 time: [5.1134 us 5.1222 us 5.1320 us]
change: [-4.1095% -3.6910% -3.1781%] (p = 0.00 < 0.05)
Performance has improved.
call callback add 2 10 time: [5.4408 us 5.4480 us 5.4560 us]
change: [-6.4203% -5.7780% -5.0013%] (p = 0.00 < 0.05)
Performance has improved.
call callback append 10 time: [9.8243 us 9.8410 us 9.8586 us]
change: [-26.937% -26.702% -26.469%] (p = 0.00 < 0.05)
Performance has improved.
create registry 10 time: [3.7005 us 3.7089 us 3.7174 us]
change: [-8.4965% -8.1042% -7.6926%] (p = 0.00 < 0.05)
Performance has improved.
I think that a lot of these benchmarks are too "easy", and most API usage is
going to be more like the 'create string table 10' benchmark, where there are a
lot of handles and tables and strings, so I think that 25%-50% improvement is a
good guess for most use cases.
2018-03-11 23:20:10 -04:00
|
|
|
unsafe {
|
2021-07-08 12:32:20 -04:00
|
|
|
let extra = &mut *self.extra;
|
2019-10-15 07:58:02 -04:00
|
|
|
ffi::lua_pushvalue(extra.ref_thread, lref.index);
|
2021-07-08 12:32:20 -04:00
|
|
|
let index = ref_stack_pop(extra);
|
2018-03-28 01:09:51 -04:00
|
|
|
LuaRef { lua: self, index }
|
A lot of performance changes.
Okay, so this is kind of a mega-commit of a lot of performance related changes
to rlua, some of which are pretty complicated.
There are some small improvements here and there, but most of the benefits of
this change are from a few big changes. The simplest big change is that there
is now `protect_lua` as well as `protect_lua_call`, which allows skipping a
lightuserdata parameter and some stack manipulation in some cases. Second
simplest is the change to use Vec instead of VecDeque for MultiValue, and to
have MultiValue be used as a sort of "backwards-only" Vec so that ToLuaMulti /
FromLuaMulti still work correctly.
The most complex change, though, is a change to the way LuaRef works, so that
LuaRef can optionally point into the Lua stack instead of only registry values.
At state creation a set number of stack slots is reserved for the first N LuaRef
types (currently 16), and space for these are also allocated separately
allocated at callback time. There is a huge breaking change here, which is that
now any LuaRef types MUST only be used with the Lua on which they were created,
and CANNOT be used with any other Lua callback instance. This mostly will
affect people using LuaRef types from inside a scope callback, but hopefully in
those cases `Function::bind` will be a suitable replacement. On the plus side,
the rules for LuaRef types are easier to state now.
There is probably more easy-ish perf on the table here, but here's the
preliminary results, based on my very limited benchmarks:
create table time: [314.13 ns 315.71 ns 317.44 ns]
change: [-36.154% -35.670% -35.205%] (p = 0.00 < 0.05)
create array 10 time: [2.9731 us 2.9816 us 2.9901 us]
change: [-16.996% -16.600% -16.196%] (p = 0.00 < 0.05)
Performance has improved.
create string table 10 time: [5.6904 us 5.7164 us 5.7411 us]
change: [-53.536% -53.309% -53.079%] (p = 0.00 < 0.05)
Performance has improved.
call add function 3 10 time: [5.1134 us 5.1222 us 5.1320 us]
change: [-4.1095% -3.6910% -3.1781%] (p = 0.00 < 0.05)
Performance has improved.
call callback add 2 10 time: [5.4408 us 5.4480 us 5.4560 us]
change: [-6.4203% -5.7780% -5.0013%] (p = 0.00 < 0.05)
Performance has improved.
call callback append 10 time: [9.8243 us 9.8410 us 9.8586 us]
change: [-26.937% -26.702% -26.469%] (p = 0.00 < 0.05)
Performance has improved.
create registry 10 time: [3.7005 us 3.7089 us 3.7174 us]
change: [-8.4965% -8.1042% -7.6926%] (p = 0.00 < 0.05)
Performance has improved.
I think that a lot of these benchmarks are too "easy", and most API usage is
going to be more like the 'create string table 10' benchmark, where there are a
lot of handles and tables and strings, so I think that 25%-50% improvement is a
good guess for most use cases.
2018-03-11 23:20:10 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-28 01:09:51 -04:00
|
|
|
pub(crate) fn drop_ref<'lua>(&'lua self, lref: &mut LuaRef<'lua>) {
|
A lot of performance changes.
Okay, so this is kind of a mega-commit of a lot of performance related changes
to rlua, some of which are pretty complicated.
There are some small improvements here and there, but most of the benefits of
this change are from a few big changes. The simplest big change is that there
is now `protect_lua` as well as `protect_lua_call`, which allows skipping a
lightuserdata parameter and some stack manipulation in some cases. Second
simplest is the change to use Vec instead of VecDeque for MultiValue, and to
have MultiValue be used as a sort of "backwards-only" Vec so that ToLuaMulti /
FromLuaMulti still work correctly.
The most complex change, though, is a change to the way LuaRef works, so that
LuaRef can optionally point into the Lua stack instead of only registry values.
At state creation a set number of stack slots is reserved for the first N LuaRef
types (currently 16), and space for these are also allocated separately
allocated at callback time. There is a huge breaking change here, which is that
now any LuaRef types MUST only be used with the Lua on which they were created,
and CANNOT be used with any other Lua callback instance. This mostly will
affect people using LuaRef types from inside a scope callback, but hopefully in
those cases `Function::bind` will be a suitable replacement. On the plus side,
the rules for LuaRef types are easier to state now.
There is probably more easy-ish perf on the table here, but here's the
preliminary results, based on my very limited benchmarks:
create table time: [314.13 ns 315.71 ns 317.44 ns]
change: [-36.154% -35.670% -35.205%] (p = 0.00 < 0.05)
create array 10 time: [2.9731 us 2.9816 us 2.9901 us]
change: [-16.996% -16.600% -16.196%] (p = 0.00 < 0.05)
Performance has improved.
create string table 10 time: [5.6904 us 5.7164 us 5.7411 us]
change: [-53.536% -53.309% -53.079%] (p = 0.00 < 0.05)
Performance has improved.
call add function 3 10 time: [5.1134 us 5.1222 us 5.1320 us]
change: [-4.1095% -3.6910% -3.1781%] (p = 0.00 < 0.05)
Performance has improved.
call callback add 2 10 time: [5.4408 us 5.4480 us 5.4560 us]
change: [-6.4203% -5.7780% -5.0013%] (p = 0.00 < 0.05)
Performance has improved.
call callback append 10 time: [9.8243 us 9.8410 us 9.8586 us]
change: [-26.937% -26.702% -26.469%] (p = 0.00 < 0.05)
Performance has improved.
create registry 10 time: [3.7005 us 3.7089 us 3.7174 us]
change: [-8.4965% -8.1042% -7.6926%] (p = 0.00 < 0.05)
Performance has improved.
I think that a lot of these benchmarks are too "easy", and most API usage is
going to be more like the 'create string table 10' benchmark, where there are a
lot of handles and tables and strings, so I think that 25%-50% improvement is a
good guess for most use cases.
2018-03-11 23:20:10 -04:00
|
|
|
unsafe {
|
2021-07-08 12:32:20 -04:00
|
|
|
let extra = &mut *self.extra;
|
2019-10-15 07:58:02 -04:00
|
|
|
ffi::lua_pushnil(extra.ref_thread);
|
|
|
|
ffi::lua_replace(extra.ref_thread, lref.index);
|
|
|
|
extra.ref_free.push(lref.index);
|
2017-05-25 00:43:35 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-02 05:38:33 -04:00
|
|
|
pub(crate) unsafe fn push_userdata_metatable<T: 'static + UserData>(&self) -> Result<()> {
|
2021-02-21 18:51:49 -05:00
|
|
|
let type_id = TypeId::of::<T>();
|
2021-07-08 12:32:20 -04:00
|
|
|
if let Some(&table_id) = (*self.extra).registered_userdata.get(&type_id) {
|
2021-05-02 05:38:33 -04:00
|
|
|
ffi::lua_rawgeti(self.state, ffi::LUA_REGISTRYINDEX, table_id as Integer);
|
|
|
|
return Ok(());
|
2018-03-12 13:13:44 -04:00
|
|
|
}
|
|
|
|
|
2021-05-02 05:38:33 -04:00
|
|
|
let _sg = StackGuard::new_extra(self.state, 1);
|
|
|
|
check_stack(self.state, 13)?;
|
2017-05-21 19:50:59 -04:00
|
|
|
|
2021-02-19 06:48:56 -05:00
|
|
|
let mut fields = StaticUserDataFields::default();
|
2018-09-04 03:40:13 -04:00
|
|
|
let mut methods = StaticUserDataMethods::default();
|
2021-02-19 06:48:56 -05:00
|
|
|
T::add_fields(&mut fields);
|
2018-03-12 13:13:44 -04:00
|
|
|
T::add_methods(&mut methods);
|
|
|
|
|
2021-02-19 06:48:56 -05:00
|
|
|
// Prepare metatable, add meta methods first and then meta fields
|
2021-04-09 07:05:03 -04:00
|
|
|
let metatable_nrec = methods.meta_methods.len() + fields.meta_fields.len();
|
2021-06-16 17:13:11 -04:00
|
|
|
push_table(self.state, 0, metatable_nrec as c_int)?;
|
2018-09-04 03:40:13 -04:00
|
|
|
for (k, m) in methods.meta_methods {
|
2019-09-27 12:27:37 -04:00
|
|
|
self.push_value(Value::Function(self.create_callback(m)?))?;
|
2021-06-16 17:13:11 -04:00
|
|
|
rawset_field(self.state, -2, k.validate()?.name())?;
|
2018-09-04 03:40:13 -04:00
|
|
|
}
|
2021-02-19 06:48:56 -05:00
|
|
|
for (k, f) in fields.meta_fields {
|
|
|
|
self.push_value(f(self)?)?;
|
2021-06-16 17:13:11 -04:00
|
|
|
rawset_field(self.state, -2, k.validate()?.name())?;
|
2021-02-19 06:48:56 -05:00
|
|
|
}
|
2021-05-31 18:33:44 -04:00
|
|
|
// Add special `__mlua_type_id` field
|
2021-07-08 13:41:10 -04:00
|
|
|
let type_id_ptr = protect_lua(self.state, 0, 1, |state| {
|
2021-06-16 17:13:11 -04:00
|
|
|
ffi::lua_newuserdata(state, mem::size_of::<TypeId>()) as *mut TypeId
|
|
|
|
})?;
|
2021-05-31 18:33:44 -04:00
|
|
|
ptr::write(type_id_ptr, type_id);
|
2021-06-16 17:13:11 -04:00
|
|
|
rawset_field(self.state, -2, "__mlua_type_id")?;
|
2021-02-19 06:48:56 -05:00
|
|
|
let metatable_index = ffi::lua_absindex(self.state, -1);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
2021-02-19 06:48:56 -05:00
|
|
|
let mut extra_tables_count = 0;
|
|
|
|
|
|
|
|
let mut field_getters_index = None;
|
2021-04-09 07:05:03 -04:00
|
|
|
let field_getters_nrec = fields.field_getters.len();
|
|
|
|
if field_getters_nrec > 0 {
|
2021-06-16 17:13:11 -04:00
|
|
|
push_table(self.state, 0, field_getters_nrec as c_int)?;
|
2021-02-19 06:48:56 -05:00
|
|
|
for (k, m) in fields.field_getters {
|
|
|
|
self.push_value(Value::Function(self.create_callback(m)?))?;
|
2021-06-16 17:13:11 -04:00
|
|
|
rawset_field(self.state, -2, &k)?;
|
2021-02-19 06:48:56 -05:00
|
|
|
}
|
|
|
|
field_getters_index = Some(ffi::lua_absindex(self.state, -1));
|
|
|
|
extra_tables_count += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut field_setters_index = None;
|
2021-04-09 07:05:03 -04:00
|
|
|
let field_setters_nrec = fields.field_setters.len();
|
|
|
|
if field_setters_nrec > 0 {
|
2021-06-16 17:13:11 -04:00
|
|
|
push_table(self.state, 0, field_setters_nrec as c_int)?;
|
2021-02-19 06:48:56 -05:00
|
|
|
for (k, m) in fields.field_setters {
|
|
|
|
self.push_value(Value::Function(self.create_callback(m)?))?;
|
2021-06-16 17:13:11 -04:00
|
|
|
rawset_field(self.state, -2, &k)?;
|
2021-02-19 06:48:56 -05:00
|
|
|
}
|
|
|
|
field_setters_index = Some(ffi::lua_absindex(self.state, -1));
|
|
|
|
extra_tables_count += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut methods_index = None;
|
2020-04-17 17:38:01 -04:00
|
|
|
#[cfg(feature = "async")]
|
2021-04-09 07:05:03 -04:00
|
|
|
let methods_nrec = methods.methods.len() + methods.async_methods.len();
|
2020-04-17 17:38:01 -04:00
|
|
|
#[cfg(not(feature = "async"))]
|
2021-04-09 07:05:03 -04:00
|
|
|
let methods_nrec = methods.methods.len();
|
|
|
|
if methods_nrec > 0 {
|
2021-06-16 17:13:11 -04:00
|
|
|
push_table(self.state, 0, methods_nrec as c_int)?;
|
2018-03-12 13:13:44 -04:00
|
|
|
for (k, m) in methods.methods {
|
2019-09-27 12:27:37 -04:00
|
|
|
self.push_value(Value::Function(self.create_callback(m)?))?;
|
2021-06-16 17:13:11 -04:00
|
|
|
rawset_field(self.state, -2, &k)?;
|
2018-03-12 13:13:44 -04:00
|
|
|
}
|
2020-04-17 17:38:01 -04:00
|
|
|
#[cfg(feature = "async")]
|
|
|
|
for (k, m) in methods.async_methods {
|
|
|
|
self.push_value(Value::Function(self.create_async_callback(m)?))?;
|
2021-06-16 17:13:11 -04:00
|
|
|
rawset_field(self.state, -2, &k)?;
|
2020-04-17 17:38:01 -04:00
|
|
|
}
|
2021-02-19 06:48:56 -05:00
|
|
|
methods_index = Some(ffi::lua_absindex(self.state, -1));
|
|
|
|
extra_tables_count += 1;
|
2018-03-12 13:13:44 -04:00
|
|
|
}
|
2017-05-21 19:50:59 -04:00
|
|
|
|
2021-02-19 06:48:56 -05:00
|
|
|
init_userdata_metatable::<UserDataCell<T>>(
|
|
|
|
self.state,
|
|
|
|
metatable_index,
|
|
|
|
field_getters_index,
|
|
|
|
field_setters_index,
|
|
|
|
methods_index,
|
|
|
|
)?;
|
|
|
|
|
|
|
|
// Pop extra tables to get metatable on top of the stack
|
|
|
|
ffi::lua_pop(self.state, extra_tables_count);
|
|
|
|
|
2021-04-16 17:01:55 -04:00
|
|
|
let ptr = ffi::lua_topointer(self.state, -1);
|
2021-05-02 05:38:33 -04:00
|
|
|
ffi::lua_pushvalue(self.state, -1);
|
2021-07-08 13:41:10 -04:00
|
|
|
let id = protect_lua(self.state, 1, 0, |state| {
|
2021-06-16 17:13:11 -04:00
|
|
|
ffi::luaL_ref(state, ffi::LUA_REGISTRYINDEX)
|
|
|
|
})?;
|
2019-10-15 07:58:02 -04:00
|
|
|
|
2021-07-08 12:32:20 -04:00
|
|
|
let extra = &mut *self.extra;
|
2021-02-21 18:51:49 -05:00
|
|
|
extra.registered_userdata.insert(type_id, id);
|
2021-04-16 17:01:55 -04:00
|
|
|
extra.registered_userdata_mt.insert(ptr as isize);
|
2019-10-15 07:58:02 -04:00
|
|
|
|
2021-05-02 05:38:33 -04:00
|
|
|
Ok(())
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
2017-12-03 23:01:03 -05:00
|
|
|
|
2021-07-08 12:32:20 -04:00
|
|
|
pub(crate) unsafe fn register_userdata_metatable(&self, id: isize) {
|
|
|
|
(*self.extra).registered_userdata_mt.insert(id);
|
2021-04-16 17:01:55 -04:00
|
|
|
}
|
|
|
|
|
2021-07-08 12:32:20 -04:00
|
|
|
pub(crate) unsafe fn deregister_userdata_metatable(&self, id: isize) {
|
|
|
|
(*self.extra).registered_userdata_mt.remove(&id);
|
2021-04-16 17:01:55 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Pushes a LuaRef value onto the stack, checking that it's a registered
|
|
|
|
// and not destructed UserData.
|
2021-05-02 05:38:33 -04:00
|
|
|
// Uses 3 stack spaces, does not call checkstack.
|
2021-05-31 18:33:44 -04:00
|
|
|
pub(crate) unsafe fn push_userdata_ref(&self, lref: &LuaRef, with_mt: bool) -> Result<()> {
|
2020-12-12 15:37:17 -05:00
|
|
|
self.push_ref(lref);
|
|
|
|
if ffi::lua_getmetatable(self.state, -1) == 0 {
|
2021-04-16 17:01:55 -04:00
|
|
|
return Err(Error::UserDataTypeMismatch);
|
|
|
|
}
|
|
|
|
// Check that userdata is registered
|
|
|
|
let ptr = ffi::lua_topointer(self.state, -1);
|
2021-07-08 12:32:20 -04:00
|
|
|
let extra = &*self.extra;
|
2021-04-16 17:01:55 -04:00
|
|
|
if extra.registered_userdata_mt.contains(&(ptr as isize)) {
|
2021-05-31 18:33:44 -04:00
|
|
|
if !with_mt {
|
|
|
|
ffi::lua_pop(self.state, 1);
|
|
|
|
}
|
2021-04-16 17:01:55 -04:00
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
// Maybe userdata was destructed?
|
|
|
|
get_destructed_userdata_metatable(self.state);
|
|
|
|
if ffi::lua_rawequal(self.state, -1, -2) != 0 {
|
2021-02-22 15:38:36 -05:00
|
|
|
ffi::lua_pop(self.state, 2);
|
2021-04-16 17:01:55 -04:00
|
|
|
return Err(Error::UserDataDestructed);
|
2020-12-12 15:37:17 -05:00
|
|
|
}
|
2021-04-16 17:01:55 -04:00
|
|
|
ffi::lua_pop(self.state, 2);
|
|
|
|
Err(Error::UserDataTypeMismatch)
|
2020-12-12 15:37:17 -05:00
|
|
|
}
|
|
|
|
|
2021-05-02 05:38:33 -04:00
|
|
|
// Creates a Function out of a Callback containing a 'static Fn. This is safe ONLY because the
|
|
|
|
// Fn is 'static, otherwise it could capture 'callback arguments improperly. Without ATCs, we
|
2018-09-04 17:36:06 -04:00
|
|
|
// cannot easily deal with the "correct" callback type of:
|
|
|
|
//
|
|
|
|
// Box<for<'lua> Fn(&'lua Lua, MultiValue<'lua>) -> Result<MultiValue<'lua>>)>
|
|
|
|
//
|
2018-09-04 19:09:09 -04:00
|
|
|
// So we instead use a caller provided lifetime, which without the 'static requirement would be
|
|
|
|
// unsafe.
|
2018-03-12 16:00:11 -04:00
|
|
|
pub(crate) fn create_callback<'lua, 'callback>(
|
|
|
|
&'lua self,
|
|
|
|
func: Callback<'callback, 'static>,
|
2020-05-04 06:56:42 -04:00
|
|
|
) -> Result<Function<'lua>>
|
|
|
|
where
|
|
|
|
'lua: 'callback,
|
|
|
|
{
|
2018-03-12 22:25:45 -04:00
|
|
|
unsafe extern "C" fn call_callback(state: *mut ffi::lua_State) -> c_int {
|
2021-06-30 11:50:50 -04:00
|
|
|
let get_extra = |state| {
|
|
|
|
let upvalue = get_userdata::<CallbackUpvalue>(state, ffi::lua_upvalueindex(1));
|
2021-07-08 12:32:20 -04:00
|
|
|
(*upvalue).lua.extra
|
2021-06-30 11:50:50 -04:00
|
|
|
};
|
|
|
|
callback_error_ext(state, get_extra, |nargs| {
|
|
|
|
let upvalue_idx = ffi::lua_upvalueindex(1);
|
|
|
|
if ffi::lua_type(state, upvalue_idx) == ffi::LUA_TNIL {
|
2019-10-15 07:58:02 -04:00
|
|
|
return Err(Error::CallbackDestructed);
|
|
|
|
}
|
2021-06-30 11:50:50 -04:00
|
|
|
let upvalue = get_userdata::<CallbackUpvalue>(state, upvalue_idx);
|
2018-03-28 01:09:51 -04:00
|
|
|
|
|
|
|
if nargs < ffi::LUA_MINSTACK {
|
|
|
|
check_stack(state, ffi::LUA_MINSTACK - nargs)?;
|
|
|
|
}
|
2018-03-12 16:00:11 -04:00
|
|
|
|
2021-06-30 11:50:50 -04:00
|
|
|
let lua = &mut (*upvalue).lua;
|
2020-04-17 17:38:01 -04:00
|
|
|
lua.state = state;
|
2018-03-12 22:25:45 -04:00
|
|
|
|
2018-03-28 01:09:51 -04:00
|
|
|
let mut args = MultiValue::new();
|
|
|
|
args.reserve(nargs as usize);
|
|
|
|
for _ in 0..nargs {
|
|
|
|
args.push_front(lua.pop_value());
|
|
|
|
}
|
|
|
|
|
2021-06-30 11:50:50 -04:00
|
|
|
let results = ((*upvalue).func)(lua, args)?;
|
2018-03-12 16:00:11 -04:00
|
|
|
let nresults = results.len() as c_int;
|
|
|
|
|
2018-03-19 15:26:21 -04:00
|
|
|
check_stack(state, nresults)?;
|
2018-03-12 16:00:11 -04:00
|
|
|
for r in results {
|
2019-09-27 12:27:37 -04:00
|
|
|
lua.push_value(r)?;
|
2018-03-12 16:00:11 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(nresults)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
let _sg = StackGuard::new(self.state);
|
2021-06-30 11:50:50 -04:00
|
|
|
check_stack(self.state, 4)?;
|
2018-03-12 16:00:11 -04:00
|
|
|
|
2021-06-30 11:50:50 -04:00
|
|
|
let lua = self.clone();
|
2021-07-08 13:40:14 -04:00
|
|
|
let func = mem::transmute(func);
|
|
|
|
push_gc_userdata(self.state, CallbackUpvalue { lua, func })?;
|
2021-07-08 13:41:10 -04:00
|
|
|
protect_lua(self.state, 1, 1, |state| {
|
2021-06-30 11:50:50 -04:00
|
|
|
ffi::lua_pushcclosure(state, call_callback, 1);
|
2021-06-16 17:13:11 -04:00
|
|
|
})?;
|
2018-03-12 16:00:11 -04:00
|
|
|
|
|
|
|
Ok(Function(self.pop_ref()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-17 17:38:01 -04:00
|
|
|
#[cfg(feature = "async")]
|
|
|
|
pub(crate) fn create_async_callback<'lua, 'callback>(
|
|
|
|
&'lua self,
|
|
|
|
func: AsyncCallback<'callback, 'static>,
|
2020-05-04 06:56:42 -04:00
|
|
|
) -> Result<Function<'lua>>
|
|
|
|
where
|
|
|
|
'lua: 'callback,
|
|
|
|
{
|
2021-07-08 17:53:53 -04:00
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
|
|
|
{
|
2021-07-08 12:32:20 -04:00
|
|
|
let libs = unsafe { (*self.extra).libs };
|
2020-12-22 16:17:06 -05:00
|
|
|
if !libs.contains(StdLib::COROUTINE) {
|
|
|
|
self.load_from_std_lib(StdLib::COROUTINE)?;
|
|
|
|
}
|
|
|
|
}
|
2020-04-17 17:38:01 -04:00
|
|
|
|
|
|
|
unsafe extern "C" fn call_callback(state: *mut ffi::lua_State) -> c_int {
|
2021-06-30 11:50:50 -04:00
|
|
|
let get_extra = |state| {
|
|
|
|
let upvalue = get_userdata::<AsyncCallbackUpvalue>(state, ffi::lua_upvalueindex(1));
|
2021-07-08 12:32:20 -04:00
|
|
|
(*upvalue).lua.extra
|
2021-06-30 11:50:50 -04:00
|
|
|
};
|
|
|
|
callback_error_ext(state, get_extra, |nargs| {
|
|
|
|
let upvalue_idx = ffi::lua_upvalueindex(1);
|
|
|
|
if ffi::lua_type(state, upvalue_idx) == ffi::LUA_TNIL {
|
2020-04-17 17:38:01 -04:00
|
|
|
return Err(Error::CallbackDestructed);
|
|
|
|
}
|
2021-06-30 11:50:50 -04:00
|
|
|
let upvalue = get_userdata::<AsyncCallbackUpvalue>(state, upvalue_idx);
|
2020-04-17 17:38:01 -04:00
|
|
|
|
|
|
|
if nargs < ffi::LUA_MINSTACK {
|
|
|
|
check_stack(state, ffi::LUA_MINSTACK - nargs)?;
|
|
|
|
}
|
|
|
|
|
2021-06-30 11:50:50 -04:00
|
|
|
let lua = &mut (*upvalue).lua;
|
2020-04-17 17:38:01 -04:00
|
|
|
lua.state = state;
|
|
|
|
|
|
|
|
let mut args = MultiValue::new();
|
|
|
|
args.reserve(nargs as usize);
|
|
|
|
for _ in 0..nargs {
|
|
|
|
args.push_front(lua.pop_value());
|
|
|
|
}
|
|
|
|
|
2021-06-30 11:50:50 -04:00
|
|
|
let fut = ((*upvalue).func)(lua, args);
|
|
|
|
let lua = lua.clone();
|
2021-07-08 13:40:14 -04:00
|
|
|
push_gc_userdata(state, AsyncPollUpvalue { lua, fut })?;
|
2021-07-08 13:41:10 -04:00
|
|
|
protect_lua(state, 1, 1, |state| {
|
2021-06-30 11:50:50 -04:00
|
|
|
ffi::lua_pushcclosure(state, poll_future, 1);
|
2021-06-16 17:13:11 -04:00
|
|
|
})?;
|
2020-04-17 17:38:01 -04:00
|
|
|
|
|
|
|
Ok(1)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe extern "C" fn poll_future(state: *mut ffi::lua_State) -> c_int {
|
2021-06-30 11:50:50 -04:00
|
|
|
let get_extra = |state| {
|
|
|
|
let upvalue = get_userdata::<AsyncPollUpvalue>(state, ffi::lua_upvalueindex(1));
|
2021-07-08 12:32:20 -04:00
|
|
|
(*upvalue).lua.extra
|
2021-06-30 11:50:50 -04:00
|
|
|
};
|
|
|
|
callback_error_ext(state, get_extra, |nargs| {
|
|
|
|
let upvalue_idx = ffi::lua_upvalueindex(1);
|
|
|
|
if ffi::lua_type(state, upvalue_idx) == ffi::LUA_TNIL {
|
2021-02-21 18:51:49 -05:00
|
|
|
return Err(Error::CallbackDestructed);
|
|
|
|
}
|
2021-06-30 11:50:50 -04:00
|
|
|
let upvalue = get_userdata::<AsyncPollUpvalue>(state, upvalue_idx);
|
2020-04-17 17:38:01 -04:00
|
|
|
|
|
|
|
if nargs < ffi::LUA_MINSTACK {
|
|
|
|
check_stack(state, ffi::LUA_MINSTACK - nargs)?;
|
|
|
|
}
|
|
|
|
|
2021-06-30 11:50:50 -04:00
|
|
|
let lua = &mut (*upvalue).lua;
|
2021-05-05 07:37:27 -04:00
|
|
|
lua.state = state;
|
2020-04-17 17:38:01 -04:00
|
|
|
|
|
|
|
// Try to get an outer poll waker
|
2021-05-02 05:38:33 -04:00
|
|
|
let waker_key = &WAKER_REGISTRY_KEY as *const u8 as *const c_void;
|
|
|
|
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, waker_key);
|
2021-07-08 13:40:14 -04:00
|
|
|
let waker = match get_gc_userdata::<Option<Waker>>(state, -1).as_ref() {
|
2021-05-02 08:04:02 -04:00
|
|
|
Some(Some(waker)) => waker.clone(),
|
|
|
|
_ => noop_waker(),
|
|
|
|
};
|
2020-04-17 17:38:01 -04:00
|
|
|
ffi::lua_pop(state, 1);
|
|
|
|
|
|
|
|
let mut ctx = Context::from_waker(&waker);
|
|
|
|
|
2021-06-30 11:50:50 -04:00
|
|
|
let fut = &mut (*upvalue).fut;
|
|
|
|
match fut.as_mut().poll(&mut ctx) {
|
2020-04-17 17:38:01 -04:00
|
|
|
Poll::Pending => {
|
2021-03-03 18:21:56 -05:00
|
|
|
check_stack(state, 1)?;
|
2020-04-17 17:38:01 -04:00
|
|
|
ffi::lua_pushboolean(state, 0);
|
2021-03-03 18:21:56 -05:00
|
|
|
Ok(1)
|
2020-04-17 17:38:01 -04:00
|
|
|
}
|
|
|
|
Poll::Ready(results) => {
|
2021-03-03 17:32:22 -05:00
|
|
|
let results = results?;
|
|
|
|
let nresults = results.len() as Integer;
|
|
|
|
let results = lua.create_sequence_from(results)?;
|
|
|
|
check_stack(state, 3)?;
|
2020-04-17 17:38:01 -04:00
|
|
|
ffi::lua_pushboolean(state, 1);
|
|
|
|
lua.push_value(Value::Table(results))?;
|
2021-03-03 17:32:22 -05:00
|
|
|
lua.push_value(Value::Integer(nresults))?;
|
|
|
|
Ok(3)
|
2020-04-17 17:38:01 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
let get_poll = unsafe {
|
|
|
|
let _sg = StackGuard::new(self.state);
|
2021-06-30 11:50:50 -04:00
|
|
|
check_stack(self.state, 4)?;
|
2020-04-17 17:38:01 -04:00
|
|
|
|
2021-06-30 11:50:50 -04:00
|
|
|
let lua = self.clone();
|
2021-07-08 13:40:14 -04:00
|
|
|
let func = mem::transmute(func);
|
|
|
|
push_gc_userdata(self.state, AsyncCallbackUpvalue { lua, func })?;
|
2021-07-08 13:41:10 -04:00
|
|
|
protect_lua(self.state, 1, 1, |state| {
|
2021-06-30 11:50:50 -04:00
|
|
|
ffi::lua_pushcclosure(state, call_callback, 1);
|
2021-06-16 17:13:11 -04:00
|
|
|
})?;
|
2020-04-17 17:38:01 -04:00
|
|
|
|
|
|
|
Function(self.pop_ref())
|
|
|
|
};
|
|
|
|
|
2020-04-28 08:30:24 -04:00
|
|
|
let coroutine = self.globals().get::<_, Table>("coroutine")?;
|
|
|
|
|
2021-05-02 05:38:33 -04:00
|
|
|
let env = self.create_table_with_capacity(0, 4)?;
|
2020-04-17 17:38:01 -04:00
|
|
|
env.set("get_poll", get_poll)?;
|
2020-04-28 08:30:24 -04:00
|
|
|
env.set("yield", coroutine.get::<_, Function>("yield")?)?;
|
2020-04-17 17:38:01 -04:00
|
|
|
env.set(
|
|
|
|
"unpack",
|
2021-03-03 17:32:22 -05:00
|
|
|
self.create_function(|_, (tbl, len): (Table, Integer)| {
|
2020-04-17 17:38:01 -04:00
|
|
|
Ok(MultiValue::from_vec(
|
2021-03-03 17:32:22 -05:00
|
|
|
tbl.raw_sequence_values_by_len(Some(len))
|
|
|
|
.collect::<Result<Vec<Value>>>()?,
|
2020-04-17 17:38:01 -04:00
|
|
|
))
|
|
|
|
})?,
|
|
|
|
)?;
|
2021-05-02 07:06:32 -04:00
|
|
|
env.set("pending", {
|
|
|
|
LightUserData(&ASYNC_POLL_PENDING as *const u8 as *mut c_void)
|
2021-03-03 18:21:56 -05:00
|
|
|
})?;
|
2020-04-17 17:38:01 -04:00
|
|
|
|
2021-02-21 18:34:35 -05:00
|
|
|
// We set `poll` variable in the env table to be able to destroy upvalues
|
2020-04-17 17:38:01 -04:00
|
|
|
self.load(
|
|
|
|
r#"
|
2021-02-21 18:34:35 -05:00
|
|
|
poll = get_poll(...)
|
2021-03-03 18:21:56 -05:00
|
|
|
local poll, pending, yield, unpack = poll, pending, yield, unpack
|
2020-04-17 17:38:01 -04:00
|
|
|
while true do
|
2021-03-03 17:32:22 -05:00
|
|
|
local ready, res, nres = poll()
|
2020-04-17 17:38:01 -04:00
|
|
|
if ready then
|
2021-03-03 17:32:22 -05:00
|
|
|
return unpack(res, nres)
|
2020-04-17 17:38:01 -04:00
|
|
|
end
|
2021-03-03 18:21:56 -05:00
|
|
|
yield(pending)
|
2020-04-17 17:38:01 -04:00
|
|
|
end
|
|
|
|
"#,
|
|
|
|
)
|
|
|
|
.set_name("_mlua_async_poll")?
|
|
|
|
.set_environment(env)?
|
|
|
|
.into_function()
|
|
|
|
}
|
|
|
|
|
2021-04-27 13:31:57 -04:00
|
|
|
pub(crate) unsafe fn make_userdata<T>(&self, data: UserDataCell<T>) -> Result<AnyUserData>
|
2018-03-12 16:00:11 -04:00
|
|
|
where
|
2018-09-04 03:40:13 -04:00
|
|
|
T: 'static + UserData,
|
2018-03-12 16:00:11 -04:00
|
|
|
{
|
|
|
|
let _sg = StackGuard::new(self.state);
|
2021-05-02 05:38:33 -04:00
|
|
|
check_stack(self.state, 2)?;
|
2018-03-12 16:00:11 -04:00
|
|
|
|
2021-07-10 17:45:32 -04:00
|
|
|
// It's safe to push userdata first and then metatable.
|
|
|
|
// If the first push failed, unlikely we moved `data` to allocated memory.
|
2021-06-18 12:45:20 -04:00
|
|
|
push_userdata(self.state, data)?;
|
2021-07-10 17:45:32 -04:00
|
|
|
self.push_userdata_metatable::<T>()?;
|
2018-03-12 16:00:11 -04:00
|
|
|
ffi::lua_setmetatable(self.state, -2);
|
|
|
|
|
|
|
|
Ok(AnyUserData(self.pop_ref()))
|
|
|
|
}
|
2020-04-17 17:38:01 -04:00
|
|
|
|
|
|
|
pub(crate) fn clone(&self) -> Self {
|
|
|
|
Lua {
|
|
|
|
state: self.state,
|
|
|
|
main_state: self.main_state,
|
2021-07-08 12:32:20 -04:00
|
|
|
extra: self.extra,
|
2020-04-17 17:38:01 -04:00
|
|
|
ephemeral: true,
|
2020-05-10 11:56:19 -04:00
|
|
|
safe: self.safe,
|
2020-04-17 17:38:01 -04:00
|
|
|
_no_ref_unwind_safe: PhantomData,
|
|
|
|
}
|
|
|
|
}
|
2020-05-10 11:56:19 -04:00
|
|
|
|
|
|
|
fn disable_c_modules(&self) -> Result<()> {
|
|
|
|
let package: Table = self.globals().get("package")?;
|
|
|
|
|
|
|
|
package.set(
|
|
|
|
"loadlib",
|
|
|
|
self.create_function(|_, ()| -> Result<()> {
|
|
|
|
Err(Error::SafetyError(
|
|
|
|
"package.loadlib is disabled in safe mode".to_string(),
|
|
|
|
))
|
|
|
|
})?,
|
|
|
|
)?;
|
|
|
|
|
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
|
|
|
let searchers: Table = package.get("searchers")?;
|
|
|
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
|
|
|
let searchers: Table = package.get("loaders")?;
|
|
|
|
|
|
|
|
let loader = self.create_function(|_, ()| Ok("\n\tcan't load C modules in safe mode"))?;
|
|
|
|
|
|
|
|
// The third and fourth searchers looks for a loader as a C library
|
|
|
|
searchers.raw_set(3, loader.clone())?;
|
|
|
|
searchers.raw_remove(4)?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
2020-05-21 19:35:03 -04:00
|
|
|
|
2021-05-18 15:07:34 -04:00
|
|
|
pub(crate) unsafe fn make_from_ptr(state: *mut ffi::lua_State) -> Option<Self> {
|
2020-05-21 19:35:03 -04:00
|
|
|
let _sg = StackGuard::new(state);
|
2021-05-02 05:38:33 -04:00
|
|
|
assert_stack(state, 1);
|
2020-05-21 19:35:03 -04:00
|
|
|
|
2021-05-02 05:38:33 -04:00
|
|
|
let extra_key = &EXTRA_REGISTRY_KEY as *const u8 as *const c_void;
|
2021-07-08 12:32:20 -04:00
|
|
|
if ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, extra_key) != ffi::LUA_TLIGHTUSERDATA {
|
2021-05-18 15:07:34 -04:00
|
|
|
return None;
|
|
|
|
}
|
2021-07-08 12:32:20 -04:00
|
|
|
let extra = ffi::lua_touserdata(state, -1) as *mut ExtraData;
|
2020-05-21 19:35:03 -04:00
|
|
|
ffi::lua_pop(state, 1);
|
|
|
|
|
2021-05-18 15:07:34 -04:00
|
|
|
Some(Lua {
|
2020-05-21 19:35:03 -04:00
|
|
|
state,
|
|
|
|
main_state: get_main_state(state),
|
|
|
|
extra,
|
|
|
|
ephemeral: true,
|
2021-07-08 12:32:20 -04:00
|
|
|
safe: (*extra).safe,
|
2020-05-21 19:35:03 -04:00
|
|
|
_no_ref_unwind_safe: PhantomData,
|
2021-05-18 15:07:34 -04:00
|
|
|
})
|
2020-05-21 19:35:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) unsafe fn hook_callback(&self) -> Option<HookCallback> {
|
2021-07-08 12:32:20 -04:00
|
|
|
(*self.extra).hook_callback.clone()
|
2020-05-21 19:35:03 -04:00
|
|
|
}
|
2018-03-28 01:09:51 -04:00
|
|
|
}
|
2018-03-12 16:00:11 -04:00
|
|
|
|
2019-09-27 12:27:37 -04:00
|
|
|
/// Returned from [`Lua::load`] and is used to finalize loading and executing Lua main chunks.
|
|
|
|
///
|
|
|
|
/// [`Lua::load`]: struct.Lua.html#method.load
|
|
|
|
#[must_use = "`Chunk`s do nothing unless one of `exec`, `eval`, `call`, or `into_function` are called on them"]
|
|
|
|
pub struct Chunk<'lua, 'a> {
|
|
|
|
lua: &'lua Lua,
|
|
|
|
source: &'a [u8],
|
|
|
|
name: Option<CString>,
|
2021-06-21 18:19:33 -04:00
|
|
|
env: Result<Option<Value<'lua>>>,
|
2020-07-27 18:22:52 -04:00
|
|
|
mode: Option<ChunkMode>,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Represents chunk mode (text or binary).
|
2021-05-03 08:05:43 -04:00
|
|
|
#[derive(Clone, Copy, Debug)]
|
2020-07-27 18:22:52 -04:00
|
|
|
pub enum ChunkMode {
|
|
|
|
Text,
|
|
|
|
Binary,
|
2019-09-27 12:27:37 -04:00
|
|
|
}
|
|
|
|
|
2021-05-05 16:55:49 -04:00
|
|
|
/// Trait for types [loadable by Lua] and convertible to a [`Chunk`]
|
|
|
|
///
|
|
|
|
/// [loadable by Lua]: https://www.lua.org/manual/5.3/manual.html#3.3.2
|
|
|
|
/// [`Chunk`]: struct.Chunk.html
|
|
|
|
pub trait AsChunk<'lua> {
|
|
|
|
/// Returns chunk data (can be text or binary)
|
|
|
|
fn source(&self) -> &[u8];
|
|
|
|
|
|
|
|
/// Returns optional chunk name
|
|
|
|
fn name(&self) -> Option<CString> {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns optional chunk [environment]
|
|
|
|
///
|
|
|
|
/// [environment]: https://www.lua.org/manual/5.3/manual.html#2.2
|
2021-06-21 18:19:33 -04:00
|
|
|
fn env(&self, _lua: &'lua Lua) -> Result<Option<Value<'lua>>> {
|
|
|
|
Ok(None)
|
2021-05-05 16:55:49 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns optional chunk mode (text or binary)
|
|
|
|
fn mode(&self) -> Option<ChunkMode> {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-27 12:27:37 -04:00
|
|
|
impl<'lua, 'a> Chunk<'lua, 'a> {
|
|
|
|
/// Sets the name of this chunk, which results in more informative error traces.
|
2021-05-02 05:38:33 -04:00
|
|
|
pub fn set_name<S: AsRef<[u8]> + ?Sized>(mut self, name: &S) -> Result<Chunk<'lua, 'a>> {
|
2019-09-27 12:27:37 -04:00
|
|
|
let name =
|
|
|
|
CString::new(name.as_ref().to_vec()).map_err(|e| Error::ToLuaConversionError {
|
|
|
|
from: "&str",
|
|
|
|
to: "string",
|
|
|
|
message: Some(e.to_string()),
|
|
|
|
})?;
|
|
|
|
self.name = Some(name);
|
|
|
|
Ok(self)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sets the first upvalue (`_ENV`) of the loaded chunk to the given value.
|
|
|
|
///
|
|
|
|
/// Lua main chunks always have exactly one upvalue, and this upvalue is used as the `_ENV`
|
2021-05-02 05:38:33 -04:00
|
|
|
/// variable inside the chunk. By default this value is set to the global environment.
|
2019-09-27 12:27:37 -04:00
|
|
|
///
|
|
|
|
/// Calling this method changes the `_ENV` upvalue to the value provided, and variables inside
|
|
|
|
/// the chunk will refer to the given environment rather than the global one.
|
|
|
|
///
|
|
|
|
/// All global variables (including the standard library!) are looked up in `_ENV`, so it may be
|
|
|
|
/// necessary to populate the environment in order for scripts using custom environments to be
|
|
|
|
/// useful.
|
|
|
|
pub fn set_environment<V: ToLua<'lua>>(mut self, env: V) -> Result<Chunk<'lua, 'a>> {
|
2021-05-05 16:55:49 -04:00
|
|
|
// Prefer to propagate errors here and wrap to `Ok`
|
2021-06-21 18:19:33 -04:00
|
|
|
self.env = Ok(Some(env.to_lua(self.lua)?));
|
2019-09-27 12:27:37 -04:00
|
|
|
Ok(self)
|
|
|
|
}
|
|
|
|
|
2020-07-27 18:22:52 -04:00
|
|
|
/// Sets whether the chunk is text or binary (autodetected by default).
|
|
|
|
///
|
|
|
|
/// Lua does not check the consistency of binary chunks, therefore this mode is allowed only
|
|
|
|
/// for instances created with [`Lua::unsafe_new`].
|
|
|
|
///
|
|
|
|
/// [`Lua::unsafe_new`]: struct.Lua.html#method.unsafe_new
|
|
|
|
pub fn set_mode(mut self, mode: ChunkMode) -> Chunk<'lua, 'a> {
|
|
|
|
self.mode = Some(mode);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2019-09-27 12:27:37 -04:00
|
|
|
/// Execute this chunk of code.
|
|
|
|
///
|
|
|
|
/// This is equivalent to calling the chunk function with no arguments and no return values.
|
|
|
|
pub fn exec(self) -> Result<()> {
|
|
|
|
self.call(())?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-04-18 16:26:12 -04:00
|
|
|
/// Asynchronously execute this chunk of code.
|
|
|
|
///
|
|
|
|
/// See [`Chunk::exec`] for more details.
|
|
|
|
///
|
2020-05-13 21:12:22 -04:00
|
|
|
/// Requires `feature = "async"`
|
|
|
|
///
|
2020-04-18 16:26:12 -04:00
|
|
|
/// [`Chunk::exec`]: struct.Chunk.html#method.exec
|
|
|
|
#[cfg(feature = "async")]
|
2020-12-29 20:43:00 -05:00
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
2020-04-18 16:26:12 -04:00
|
|
|
pub fn exec_async<'fut>(self) -> LocalBoxFuture<'fut, Result<()>>
|
|
|
|
where
|
|
|
|
'lua: 'fut,
|
|
|
|
{
|
|
|
|
self.call_async(())
|
|
|
|
}
|
|
|
|
|
2019-09-27 12:27:37 -04:00
|
|
|
/// Evaluate the chunk as either an expression or block.
|
|
|
|
///
|
|
|
|
/// If the chunk can be parsed as an expression, this loads and executes the chunk and returns
|
2021-05-02 05:38:33 -04:00
|
|
|
/// the value that it evaluates to. Otherwise, the chunk is interpreted as a block as normal,
|
2019-09-27 12:27:37 -04:00
|
|
|
/// and this is equivalent to calling `exec`.
|
|
|
|
pub fn eval<R: FromLuaMulti<'lua>>(self) -> Result<R> {
|
2020-07-27 15:06:53 -04:00
|
|
|
// Bytecode is always interpreted as a statement.
|
|
|
|
// For source code, first try interpreting the lua as an expression by adding
|
2021-05-02 05:38:33 -04:00
|
|
|
// "return", then as a statement. This is the same thing the
|
2019-09-27 12:27:37 -04:00
|
|
|
// actual lua repl does.
|
2020-07-27 15:06:53 -04:00
|
|
|
if self.source.starts_with(ffi::LUA_SIGNATURE) {
|
|
|
|
self.call(())
|
|
|
|
} else if let Ok(function) = self.lua.load_chunk(
|
2020-04-18 16:26:12 -04:00
|
|
|
&self.expression_source(),
|
|
|
|
self.name.as_ref(),
|
2021-05-05 16:55:49 -04:00
|
|
|
self.env()?,
|
2020-07-27 18:22:52 -04:00
|
|
|
self.mode,
|
2020-04-18 16:26:12 -04:00
|
|
|
) {
|
2019-09-27 12:27:37 -04:00
|
|
|
function.call(())
|
|
|
|
} else {
|
|
|
|
self.call(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-18 16:26:12 -04:00
|
|
|
/// Asynchronously evaluate the chunk as either an expression or block.
|
|
|
|
///
|
|
|
|
/// See [`Chunk::eval`] for more details.
|
|
|
|
///
|
2020-05-13 21:12:22 -04:00
|
|
|
/// Requires `feature = "async"`
|
|
|
|
///
|
2020-04-18 16:26:12 -04:00
|
|
|
/// [`Chunk::eval`]: struct.Chunk.html#method.eval
|
|
|
|
#[cfg(feature = "async")]
|
2020-12-29 20:43:00 -05:00
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
2020-04-18 16:26:12 -04:00
|
|
|
pub fn eval_async<'fut, R>(self) -> LocalBoxFuture<'fut, Result<R>>
|
|
|
|
where
|
|
|
|
'lua: 'fut,
|
|
|
|
R: FromLuaMulti<'lua> + 'fut,
|
|
|
|
{
|
2020-07-27 15:06:53 -04:00
|
|
|
if self.source.starts_with(ffi::LUA_SIGNATURE) {
|
|
|
|
self.call_async(())
|
|
|
|
} else if let Ok(function) = self.lua.load_chunk(
|
2020-04-18 16:26:12 -04:00
|
|
|
&self.expression_source(),
|
|
|
|
self.name.as_ref(),
|
2021-05-05 16:55:49 -04:00
|
|
|
match self.env() {
|
|
|
|
Ok(env) => env,
|
|
|
|
Err(e) => return Box::pin(future::err(e)),
|
|
|
|
},
|
2020-07-27 18:22:52 -04:00
|
|
|
self.mode,
|
2020-04-18 16:26:12 -04:00
|
|
|
) {
|
|
|
|
function.call_async(())
|
|
|
|
} else {
|
|
|
|
self.call_async(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-10 14:53:38 -04:00
|
|
|
/// Load the chunk function and call it with the given arguments.
|
2019-09-27 12:27:37 -04:00
|
|
|
///
|
|
|
|
/// This is equivalent to `into_function` and calling the resulting function.
|
|
|
|
pub fn call<A: ToLuaMulti<'lua>, R: FromLuaMulti<'lua>>(self, args: A) -> Result<R> {
|
|
|
|
self.into_function()?.call(args)
|
|
|
|
}
|
|
|
|
|
2021-05-10 14:53:38 -04:00
|
|
|
/// Load the chunk function and asynchronously call it with the given arguments.
|
2020-04-18 16:26:12 -04:00
|
|
|
///
|
|
|
|
/// See [`Chunk::call`] for more details.
|
|
|
|
///
|
2020-05-13 21:12:22 -04:00
|
|
|
/// Requires `feature = "async"`
|
|
|
|
///
|
2020-04-18 16:26:12 -04:00
|
|
|
/// [`Chunk::call`]: struct.Chunk.html#method.call
|
|
|
|
#[cfg(feature = "async")]
|
2020-12-29 20:43:00 -05:00
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
2020-04-18 16:26:12 -04:00
|
|
|
pub fn call_async<'fut, A, R>(self, args: A) -> LocalBoxFuture<'fut, Result<R>>
|
|
|
|
where
|
|
|
|
'lua: 'fut,
|
|
|
|
A: ToLuaMulti<'lua>,
|
|
|
|
R: FromLuaMulti<'lua> + 'fut,
|
|
|
|
{
|
|
|
|
match self.into_function() {
|
2020-04-19 11:51:35 -04:00
|
|
|
Ok(func) => func.call_async(args),
|
|
|
|
Err(e) => Box::pin(future::err(e)),
|
2020-04-18 16:26:12 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-27 12:27:37 -04:00
|
|
|
/// Load this chunk into a regular `Function`.
|
|
|
|
///
|
|
|
|
/// This simply compiles the chunk without actually executing it.
|
|
|
|
pub fn into_function(self) -> Result<Function<'lua>> {
|
2019-09-27 12:38:24 -04:00
|
|
|
self.lua
|
2021-05-05 16:55:49 -04:00
|
|
|
.load_chunk(self.source, self.name.as_ref(), self.env()?, self.mode)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn env(&self) -> Result<Option<Value<'lua>>> {
|
2021-06-21 18:19:33 -04:00
|
|
|
self.env.clone()
|
2019-09-27 12:27:37 -04:00
|
|
|
}
|
2020-04-18 16:26:12 -04:00
|
|
|
|
|
|
|
fn expression_source(&self) -> Vec<u8> {
|
|
|
|
let mut buf = Vec::with_capacity(b"return ".len() + self.source.len());
|
|
|
|
buf.extend(b"return ");
|
|
|
|
buf.extend(self.source);
|
|
|
|
buf
|
|
|
|
}
|
2019-09-27 12:27:37 -04:00
|
|
|
}
|
|
|
|
|
2021-05-05 16:55:49 -04:00
|
|
|
impl<'lua, T: AsRef<[u8]> + ?Sized> AsChunk<'lua> for T {
|
|
|
|
fn source(&self) -> &[u8] {
|
|
|
|
self.as_ref()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-08 19:05:29 -04:00
|
|
|
// An optimized version of `callback_error` that does not allocate `WrappedFailure` userdata
|
2021-06-20 14:48:33 -04:00
|
|
|
// and instead reuses unsed and cached values from previous calls (or allocates new).
|
2021-06-30 11:50:50 -04:00
|
|
|
// It requires `get_extra` function to return `ExtraData` value.
|
|
|
|
unsafe fn callback_error_ext<E, F, R>(state: *mut ffi::lua_State, get_extra: E, f: F) -> R
|
2021-06-19 19:24:53 -04:00
|
|
|
where
|
2021-07-08 12:32:20 -04:00
|
|
|
E: Fn(*mut ffi::lua_State) -> *mut ExtraData,
|
2021-06-19 19:24:53 -04:00
|
|
|
F: FnOnce(c_int) -> Result<R>,
|
|
|
|
{
|
2021-06-30 11:50:50 -04:00
|
|
|
let upvalue_idx = ffi::lua_upvalueindex(1);
|
|
|
|
if ffi::lua_type(state, upvalue_idx) == ffi::LUA_TNIL {
|
2021-06-19 19:24:53 -04:00
|
|
|
return callback_error(state, f);
|
|
|
|
}
|
|
|
|
|
|
|
|
let nargs = ffi::lua_gettop(state);
|
|
|
|
|
|
|
|
// We need 2 extra stack spaces to store preallocated memory and error/panic metatable.
|
|
|
|
let extra_stack = if nargs < 2 { 2 - nargs } else { 1 };
|
|
|
|
ffi::luaL_checkstack(
|
|
|
|
state,
|
|
|
|
extra_stack,
|
|
|
|
cstr!("not enough stack space for callback error handling"),
|
|
|
|
);
|
|
|
|
|
2021-07-08 19:05:29 -04:00
|
|
|
enum PreallocatedFailure {
|
|
|
|
New(*mut WrappedFailure),
|
2021-06-20 14:48:33 -04:00
|
|
|
Cached(i32),
|
|
|
|
}
|
|
|
|
|
2021-06-19 19:24:53 -04:00
|
|
|
// We cannot shadow Rust errors with Lua ones, so we need to obtain pre-allocated memory
|
|
|
|
// to store a wrapped error or panic *before* we proceed.
|
2021-07-08 12:32:20 -04:00
|
|
|
let extra = &mut *get_extra(state);
|
2021-07-08 19:05:29 -04:00
|
|
|
let prealloc_failure = {
|
|
|
|
match extra.prealloc_wrapped_failures.pop() {
|
|
|
|
Some(index) => PreallocatedFailure::Cached(index),
|
2021-06-20 14:48:33 -04:00
|
|
|
None => {
|
2021-07-08 19:05:29 -04:00
|
|
|
let ud = ffi::lua_newuserdata(state, mem::size_of::<WrappedFailure>());
|
2021-06-20 14:48:33 -04:00
|
|
|
ffi::lua_rotate(state, 1, 1);
|
2021-07-08 19:05:29 -04:00
|
|
|
PreallocatedFailure::New(ud as *mut WrappedFailure)
|
2021-06-20 14:48:33 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-07-08 19:05:29 -04:00
|
|
|
let mut get_prealloc_failure = || match prealloc_failure {
|
|
|
|
PreallocatedFailure::New(ud) => {
|
2021-07-08 12:32:20 -04:00
|
|
|
ffi::lua_settop(state, 1);
|
|
|
|
ud
|
|
|
|
}
|
2021-07-08 19:05:29 -04:00
|
|
|
PreallocatedFailure::Cached(index) => {
|
2021-07-08 12:32:20 -04:00
|
|
|
ffi::lua_settop(state, 0);
|
|
|
|
ffi::lua_pushvalue(extra.ref_thread, index);
|
|
|
|
ffi::lua_xmove(extra.ref_thread, state, 1);
|
|
|
|
ffi::lua_pushnil(extra.ref_thread);
|
|
|
|
ffi::lua_replace(extra.ref_thread, index);
|
|
|
|
extra.ref_free.push(index);
|
2021-07-08 19:05:29 -04:00
|
|
|
ffi::lua_touserdata(state, -1) as *mut WrappedFailure
|
2021-06-19 19:24:53 -04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
match catch_unwind(AssertUnwindSafe(|| f(nargs))) {
|
|
|
|
Ok(Ok(r)) => {
|
2021-07-08 19:05:29 -04:00
|
|
|
// Return unused WrappedFailure to the cache
|
|
|
|
match prealloc_failure {
|
|
|
|
PreallocatedFailure::New(_) if extra.prealloc_wrapped_failures.len() < 16 => {
|
2021-06-20 14:48:33 -04:00
|
|
|
ffi::lua_rotate(state, 1, -1);
|
|
|
|
ffi::lua_xmove(state, extra.ref_thread, 1);
|
2021-07-08 12:32:20 -04:00
|
|
|
let index = ref_stack_pop(extra);
|
2021-07-08 19:05:29 -04:00
|
|
|
extra.prealloc_wrapped_failures.push(index);
|
2021-06-20 14:48:33 -04:00
|
|
|
}
|
2021-07-08 19:05:29 -04:00
|
|
|
PreallocatedFailure::New(_) => {
|
2021-06-20 14:48:33 -04:00
|
|
|
ffi::lua_remove(state, 1);
|
|
|
|
}
|
2021-07-08 19:05:29 -04:00
|
|
|
PreallocatedFailure::Cached(index)
|
|
|
|
if extra.prealloc_wrapped_failures.len() < 16 =>
|
|
|
|
{
|
|
|
|
extra.prealloc_wrapped_failures.push(index);
|
2021-06-20 14:48:33 -04:00
|
|
|
}
|
2021-07-08 19:05:29 -04:00
|
|
|
PreallocatedFailure::Cached(index) => {
|
2021-06-20 14:48:33 -04:00
|
|
|
ffi::lua_pushnil(extra.ref_thread);
|
|
|
|
ffi::lua_replace(extra.ref_thread, index);
|
|
|
|
extra.ref_free.push(index);
|
|
|
|
}
|
2021-06-19 19:24:53 -04:00
|
|
|
}
|
|
|
|
r
|
|
|
|
}
|
|
|
|
Ok(Err(err)) => {
|
2021-07-08 19:05:29 -04:00
|
|
|
let wrapped_error = get_prealloc_failure();
|
|
|
|
ptr::write(wrapped_error, WrappedFailure::Error(err));
|
|
|
|
get_gc_metatable::<WrappedFailure>(state);
|
2021-06-19 19:24:53 -04:00
|
|
|
ffi::lua_setmetatable(state, -2);
|
|
|
|
|
|
|
|
// Convert to CallbackError and attach traceback
|
|
|
|
let traceback = if ffi::lua_checkstack(state, ffi::LUA_TRACEBACK_STACK) != 0 {
|
|
|
|
ffi::luaL_traceback(state, state, ptr::null(), 0);
|
|
|
|
let traceback = util::to_string(state, -1);
|
|
|
|
ffi::lua_pop(state, 1);
|
|
|
|
traceback
|
|
|
|
} else {
|
|
|
|
"<not enough stack space for traceback>".to_string()
|
|
|
|
};
|
2021-07-08 19:05:29 -04:00
|
|
|
if let WrappedFailure::Error(ref mut err) = *wrapped_error {
|
|
|
|
let cause = Arc::new(err.clone());
|
|
|
|
*err = Error::CallbackError { traceback, cause };
|
|
|
|
}
|
2021-06-19 19:24:53 -04:00
|
|
|
|
|
|
|
ffi::lua_error(state)
|
|
|
|
}
|
|
|
|
Err(p) => {
|
2021-07-08 19:05:29 -04:00
|
|
|
let wrapped_panic = get_prealloc_failure();
|
|
|
|
ptr::write(wrapped_panic, WrappedFailure::Panic(Some(p)));
|
|
|
|
get_gc_metatable::<WrappedFailure>(state);
|
2021-06-19 19:24:53 -04:00
|
|
|
ffi::lua_setmetatable(state, -2);
|
|
|
|
ffi::lua_error(state)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-16 17:13:11 -04:00
|
|
|
// Uses 3 stack spaces
|
2021-04-09 07:05:03 -04:00
|
|
|
unsafe fn load_from_std_lib(state: *mut ffi::lua_State, libs: StdLib) -> Result<()> {
|
2021-06-16 17:13:11 -04:00
|
|
|
#[inline(always)]
|
|
|
|
pub unsafe fn requiref<S: AsRef<[u8]> + ?Sized>(
|
|
|
|
state: *mut ffi::lua_State,
|
|
|
|
modname: &S,
|
|
|
|
openf: ffi::lua_CFunction,
|
|
|
|
glb: c_int,
|
|
|
|
) -> Result<()> {
|
|
|
|
let modname = mlua_expect!(CString::new(modname.as_ref()), "modname contains nil bytes");
|
2021-07-08 13:41:10 -04:00
|
|
|
protect_lua(state, 0, 1, |state| {
|
2021-06-16 17:13:11 -04:00
|
|
|
ffi::luaL_requiref(state, modname.as_ptr() as *const c_char, openf, glb)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "luajit")]
|
|
|
|
struct GcGuard(*mut ffi::lua_State);
|
|
|
|
|
2020-06-07 13:48:22 -04:00
|
|
|
#[cfg(feature = "luajit")]
|
2021-06-16 17:13:11 -04:00
|
|
|
impl GcGuard {
|
|
|
|
fn new(state: *mut ffi::lua_State) -> Self {
|
|
|
|
// Stop collector during library initialization
|
|
|
|
unsafe { ffi::lua_gc(state, ffi::LUA_GCSTOP, 0) };
|
|
|
|
GcGuard(state)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "luajit")]
|
|
|
|
impl Drop for GcGuard {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe { ffi::lua_gc(self.0, ffi::LUA_GCRESTART, -1) };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-07 13:48:22 -04:00
|
|
|
// Stop collector during library initialization
|
2021-06-16 17:13:11 -04:00
|
|
|
#[cfg(feature = "luajit")]
|
|
|
|
let _gc_guard = GcGuard::new(state);
|
2020-06-07 13:48:22 -04:00
|
|
|
|
2020-05-08 07:42:40 -04:00
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
2019-12-26 17:51:15 -05:00
|
|
|
{
|
|
|
|
if libs.contains(StdLib::COROUTINE) {
|
2021-06-16 17:13:11 -04:00
|
|
|
requiref(state, ffi::LUA_COLIBNAME, ffi::luaopen_coroutine, 1)?;
|
2019-12-26 17:51:15 -05:00
|
|
|
ffi::lua_pop(state, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if libs.contains(StdLib::TABLE) {
|
2021-06-16 17:13:11 -04:00
|
|
|
requiref(state, ffi::LUA_TABLIBNAME, ffi::luaopen_table, 1)?;
|
2019-12-26 17:51:15 -05:00
|
|
|
ffi::lua_pop(state, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if libs.contains(StdLib::IO) {
|
2021-06-16 17:13:11 -04:00
|
|
|
requiref(state, ffi::LUA_IOLIBNAME, ffi::luaopen_io, 1)?;
|
2019-12-26 17:51:15 -05:00
|
|
|
ffi::lua_pop(state, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if libs.contains(StdLib::OS) {
|
2021-06-16 17:13:11 -04:00
|
|
|
requiref(state, ffi::LUA_OSLIBNAME, ffi::luaopen_os, 1)?;
|
2019-12-26 17:51:15 -05:00
|
|
|
ffi::lua_pop(state, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if libs.contains(StdLib::STRING) {
|
2021-06-16 17:13:11 -04:00
|
|
|
requiref(state, ffi::LUA_STRLIBNAME, ffi::luaopen_string, 1)?;
|
2019-12-26 17:51:15 -05:00
|
|
|
ffi::lua_pop(state, 1);
|
|
|
|
}
|
|
|
|
|
2020-05-08 07:42:40 -04:00
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
2019-12-26 17:51:15 -05:00
|
|
|
{
|
|
|
|
if libs.contains(StdLib::UTF8) {
|
2021-06-16 17:13:11 -04:00
|
|
|
requiref(state, ffi::LUA_UTF8LIBNAME, ffi::luaopen_utf8, 1)?;
|
2019-12-26 17:51:15 -05:00
|
|
|
ffi::lua_pop(state, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "lua52")]
|
|
|
|
{
|
|
|
|
if libs.contains(StdLib::BIT) {
|
2021-06-16 17:13:11 -04:00
|
|
|
requiref(state, ffi::LUA_BITLIBNAME, ffi::luaopen_bit32, 1)?;
|
2019-12-26 17:51:15 -05:00
|
|
|
ffi::lua_pop(state, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "luajit")]
|
|
|
|
{
|
|
|
|
if libs.contains(StdLib::BIT) {
|
2021-06-16 17:13:11 -04:00
|
|
|
requiref(state, ffi::LUA_BITLIBNAME, ffi::luaopen_bit, 1)?;
|
2019-12-26 17:51:15 -05:00
|
|
|
ffi::lua_pop(state, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if libs.contains(StdLib::MATH) {
|
2021-06-16 17:13:11 -04:00
|
|
|
requiref(state, ffi::LUA_MATHLIBNAME, ffi::luaopen_math, 1)?;
|
2019-12-26 17:51:15 -05:00
|
|
|
ffi::lua_pop(state, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if libs.contains(StdLib::DEBUG) {
|
2021-06-16 17:13:11 -04:00
|
|
|
requiref(state, ffi::LUA_DBLIBNAME, ffi::luaopen_debug, 1)?;
|
2019-12-26 17:51:15 -05:00
|
|
|
ffi::lua_pop(state, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if libs.contains(StdLib::PACKAGE) {
|
2021-06-16 17:13:11 -04:00
|
|
|
requiref(state, ffi::LUA_LOADLIBNAME, ffi::luaopen_package, 1)?;
|
2019-12-26 17:51:15 -05:00
|
|
|
ffi::lua_pop(state, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "luajit")]
|
|
|
|
{
|
|
|
|
if libs.contains(StdLib::JIT) {
|
2021-06-16 17:13:11 -04:00
|
|
|
requiref(state, ffi::LUA_JITLIBNAME, ffi::luaopen_jit, 1)?;
|
2019-12-26 17:51:15 -05:00
|
|
|
ffi::lua_pop(state, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if libs.contains(StdLib::FFI) {
|
2021-06-16 17:13:11 -04:00
|
|
|
requiref(state, ffi::LUA_FFILIBNAME, ffi::luaopen_ffi, 1)?;
|
2019-12-26 17:51:15 -05:00
|
|
|
ffi::lua_pop(state, 1);
|
|
|
|
}
|
|
|
|
}
|
2020-06-07 13:48:22 -04:00
|
|
|
|
2021-04-09 07:05:03 -04:00
|
|
|
Ok(())
|
2019-12-26 17:51:15 -05:00
|
|
|
}
|
|
|
|
|
2021-06-19 19:24:53 -04:00
|
|
|
// We move `extra` (`MutexGuard`) here to correctly drop it if panic
|
2021-07-08 12:32:20 -04:00
|
|
|
unsafe fn ref_stack_pop(extra: &mut ExtraData) -> c_int {
|
2019-10-15 07:58:02 -04:00
|
|
|
if let Some(free) = extra.ref_free.pop() {
|
|
|
|
ffi::lua_replace(extra.ref_thread, free);
|
2021-07-08 12:32:20 -04:00
|
|
|
return free;
|
2021-05-02 18:26:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Try to grow max stack size
|
|
|
|
if extra.ref_stack_top >= extra.ref_stack_size {
|
|
|
|
let mut inc = extra.ref_stack_size; // Try to double stack size
|
|
|
|
while inc > 0 && ffi::lua_checkstack(extra.ref_thread, inc) == 0 {
|
|
|
|
inc /= 2;
|
|
|
|
}
|
|
|
|
if inc == 0 {
|
|
|
|
// Pop item on top of the stack to avoid stack leaking and successfully run destructors
|
|
|
|
// during unwinding.
|
|
|
|
ffi::lua_pop(extra.ref_thread, 1);
|
|
|
|
let top = extra.ref_stack_top;
|
2018-03-28 01:09:51 -04:00
|
|
|
// It is a user error to create enough references to exhaust the Lua max stack size for
|
|
|
|
// the ref thread.
|
2021-05-02 18:26:02 -04:00
|
|
|
panic!(
|
|
|
|
"cannot create a Lua reference, out of auxiliary stack space (used {} slots)",
|
|
|
|
top
|
|
|
|
);
|
2018-03-12 22:25:45 -04:00
|
|
|
}
|
2021-05-02 18:26:02 -04:00
|
|
|
extra.ref_stack_size += inc;
|
2018-03-12 22:25:45 -04:00
|
|
|
}
|
2021-05-02 18:26:02 -04:00
|
|
|
extra.ref_stack_top += 1;
|
2021-07-08 12:32:20 -04:00
|
|
|
extra.ref_stack_top
|
2018-03-12 22:25:45 -04:00
|
|
|
}
|
|
|
|
|
2018-09-04 19:05:21 -04:00
|
|
|
struct StaticUserDataMethods<'lua, T: 'static + UserData> {
|
2019-09-27 12:27:37 -04:00
|
|
|
methods: Vec<(Vec<u8>, Callback<'lua, 'static>)>,
|
2020-04-17 17:38:01 -04:00
|
|
|
#[cfg(feature = "async")]
|
|
|
|
async_methods: Vec<(Vec<u8>, AsyncCallback<'lua, 'static>)>,
|
2019-09-27 12:27:37 -04:00
|
|
|
meta_methods: Vec<(MetaMethod, Callback<'lua, 'static>)>,
|
2018-09-04 19:05:21 -04:00
|
|
|
_type: PhantomData<T>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'lua, T: 'static + UserData> Default for StaticUserDataMethods<'lua, T> {
|
|
|
|
fn default() -> StaticUserDataMethods<'lua, T> {
|
|
|
|
StaticUserDataMethods {
|
2019-09-27 12:27:37 -04:00
|
|
|
methods: Vec::new(),
|
2020-04-17 17:38:01 -04:00
|
|
|
#[cfg(feature = "async")]
|
|
|
|
async_methods: Vec::new(),
|
2019-09-27 12:27:37 -04:00
|
|
|
meta_methods: Vec::new(),
|
2018-09-04 19:05:21 -04:00
|
|
|
_type: PhantomData,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'lua, T: 'static + UserData> UserDataMethods<'lua, T> for StaticUserDataMethods<'lua, T> {
|
2019-09-27 12:27:37 -04:00
|
|
|
fn add_method<S, A, R, M>(&mut self, name: &S, method: M)
|
2018-09-04 19:05:21 -04:00
|
|
|
where
|
2020-05-06 08:18:04 -04:00
|
|
|
S: AsRef<[u8]> + ?Sized,
|
2018-09-04 19:05:21 -04:00
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
2020-05-06 08:18:04 -04:00
|
|
|
M: 'static + MaybeSend + Fn(&'lua Lua, &T, A) -> Result<R>,
|
2018-09-04 19:05:21 -04:00
|
|
|
{
|
|
|
|
self.methods
|
2019-09-27 12:27:37 -04:00
|
|
|
.push((name.as_ref().to_vec(), Self::box_method(method)));
|
2018-09-04 19:05:21 -04:00
|
|
|
}
|
|
|
|
|
2019-09-27 12:27:37 -04:00
|
|
|
fn add_method_mut<S, A, R, M>(&mut self, name: &S, method: M)
|
2018-09-04 19:05:21 -04:00
|
|
|
where
|
2020-05-06 08:18:04 -04:00
|
|
|
S: AsRef<[u8]> + ?Sized,
|
2018-09-04 19:05:21 -04:00
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
2020-05-06 08:18:04 -04:00
|
|
|
M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<R>,
|
2018-09-04 19:05:21 -04:00
|
|
|
{
|
|
|
|
self.methods
|
2019-09-27 12:27:37 -04:00
|
|
|
.push((name.as_ref().to_vec(), Self::box_method_mut(method)));
|
2018-09-04 19:05:21 -04:00
|
|
|
}
|
|
|
|
|
2020-04-17 17:38:01 -04:00
|
|
|
#[cfg(feature = "async")]
|
|
|
|
fn add_async_method<S, A, R, M, MR>(&mut self, name: &S, method: M)
|
|
|
|
where
|
|
|
|
T: Clone,
|
2020-05-06 08:18:04 -04:00
|
|
|
S: AsRef<[u8]> + ?Sized,
|
2020-04-17 17:38:01 -04:00
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
2020-05-06 08:18:04 -04:00
|
|
|
M: 'static + MaybeSend + Fn(&'lua Lua, T, A) -> MR,
|
2020-05-05 08:03:28 -04:00
|
|
|
MR: 'lua + Future<Output = Result<R>>,
|
2020-04-17 17:38:01 -04:00
|
|
|
{
|
|
|
|
self.async_methods
|
|
|
|
.push((name.as_ref().to_vec(), Self::box_async_method(method)));
|
|
|
|
}
|
|
|
|
|
2019-09-27 12:27:37 -04:00
|
|
|
fn add_function<S, A, R, F>(&mut self, name: &S, function: F)
|
2018-09-04 19:05:21 -04:00
|
|
|
where
|
2020-05-06 08:18:04 -04:00
|
|
|
S: AsRef<[u8]> + ?Sized,
|
2018-09-04 19:05:21 -04:00
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
2020-05-06 08:18:04 -04:00
|
|
|
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> Result<R>,
|
2018-09-04 19:05:21 -04:00
|
|
|
{
|
|
|
|
self.methods
|
2019-09-27 12:27:37 -04:00
|
|
|
.push((name.as_ref().to_vec(), Self::box_function(function)));
|
2018-09-04 19:05:21 -04:00
|
|
|
}
|
|
|
|
|
2019-09-27 12:27:37 -04:00
|
|
|
fn add_function_mut<S, A, R, F>(&mut self, name: &S, function: F)
|
2018-09-04 19:05:21 -04:00
|
|
|
where
|
2020-05-06 08:18:04 -04:00
|
|
|
S: AsRef<[u8]> + ?Sized,
|
2018-09-04 19:05:21 -04:00
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
2020-05-06 08:18:04 -04:00
|
|
|
F: 'static + MaybeSend + FnMut(&'lua Lua, A) -> Result<R>,
|
2018-09-04 19:05:21 -04:00
|
|
|
{
|
|
|
|
self.methods
|
2019-09-27 12:27:37 -04:00
|
|
|
.push((name.as_ref().to_vec(), Self::box_function_mut(function)));
|
2018-09-04 19:05:21 -04:00
|
|
|
}
|
|
|
|
|
2020-04-17 17:38:01 -04:00
|
|
|
#[cfg(feature = "async")]
|
|
|
|
fn add_async_function<S, A, R, F, FR>(&mut self, name: &S, function: F)
|
|
|
|
where
|
2020-05-06 08:18:04 -04:00
|
|
|
S: AsRef<[u8]> + ?Sized,
|
2020-04-17 17:38:01 -04:00
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
2020-05-06 08:18:04 -04:00
|
|
|
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> FR,
|
2020-05-05 08:03:28 -04:00
|
|
|
FR: 'lua + Future<Output = Result<R>>,
|
2020-04-17 17:38:01 -04:00
|
|
|
{
|
|
|
|
self.async_methods
|
|
|
|
.push((name.as_ref().to_vec(), Self::box_async_function(function)));
|
|
|
|
}
|
|
|
|
|
2021-02-19 06:48:56 -05:00
|
|
|
fn add_meta_method<S, A, R, M>(&mut self, meta: S, method: M)
|
2018-09-04 19:05:21 -04:00
|
|
|
where
|
2021-02-19 06:48:56 -05:00
|
|
|
S: Into<MetaMethod>,
|
2018-09-04 19:05:21 -04:00
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
2020-05-06 08:18:04 -04:00
|
|
|
M: 'static + MaybeSend + Fn(&'lua Lua, &T, A) -> Result<R>,
|
2018-09-04 19:05:21 -04:00
|
|
|
{
|
2021-02-19 06:48:56 -05:00
|
|
|
self.meta_methods
|
|
|
|
.push((meta.into(), Self::box_method(method)));
|
2018-09-04 19:05:21 -04:00
|
|
|
}
|
|
|
|
|
2021-02-19 06:48:56 -05:00
|
|
|
fn add_meta_method_mut<S, A, R, M>(&mut self, meta: S, method: M)
|
2018-09-04 19:05:21 -04:00
|
|
|
where
|
2021-02-19 06:48:56 -05:00
|
|
|
S: Into<MetaMethod>,
|
2018-09-04 19:05:21 -04:00
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
2020-05-06 08:18:04 -04:00
|
|
|
M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<R>,
|
2018-09-04 19:05:21 -04:00
|
|
|
{
|
2021-02-19 06:48:56 -05:00
|
|
|
self.meta_methods
|
|
|
|
.push((meta.into(), Self::box_method_mut(method)));
|
2018-09-04 19:05:21 -04:00
|
|
|
}
|
|
|
|
|
2021-02-19 06:48:56 -05:00
|
|
|
fn add_meta_function<S, A, R, F>(&mut self, meta: S, function: F)
|
2018-09-04 19:05:21 -04:00
|
|
|
where
|
2021-02-19 06:48:56 -05:00
|
|
|
S: Into<MetaMethod>,
|
2018-09-04 19:05:21 -04:00
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
2020-05-06 08:18:04 -04:00
|
|
|
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> Result<R>,
|
2018-09-04 19:05:21 -04:00
|
|
|
{
|
2021-02-19 06:48:56 -05:00
|
|
|
self.meta_methods
|
|
|
|
.push((meta.into(), Self::box_function(function)));
|
2018-09-04 19:05:21 -04:00
|
|
|
}
|
|
|
|
|
2021-02-19 06:48:56 -05:00
|
|
|
fn add_meta_function_mut<S, A, R, F>(&mut self, meta: S, function: F)
|
2018-09-04 19:05:21 -04:00
|
|
|
where
|
2021-02-19 06:48:56 -05:00
|
|
|
S: Into<MetaMethod>,
|
2018-09-04 19:05:21 -04:00
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
2020-05-06 08:18:04 -04:00
|
|
|
F: 'static + MaybeSend + FnMut(&'lua Lua, A) -> Result<R>,
|
2018-09-04 19:05:21 -04:00
|
|
|
{
|
|
|
|
self.meta_methods
|
2021-02-19 06:48:56 -05:00
|
|
|
.push((meta.into(), Self::box_function_mut(function)));
|
2018-09-04 19:05:21 -04:00
|
|
|
}
|
2021-05-31 18:33:44 -04:00
|
|
|
|
|
|
|
// Below are internal methods used in generated code
|
|
|
|
|
|
|
|
fn add_callback(&mut self, name: Vec<u8>, callback: Callback<'lua, 'static>) {
|
|
|
|
self.methods.push((name, callback));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "async")]
|
|
|
|
fn add_async_callback(&mut self, name: Vec<u8>, callback: AsyncCallback<'lua, 'static>) {
|
|
|
|
self.async_methods.push((name, callback));
|
|
|
|
}
|
|
|
|
|
|
|
|
fn add_meta_callback(&mut self, meta: MetaMethod, callback: Callback<'lua, 'static>) {
|
|
|
|
self.meta_methods.push((meta, callback));
|
|
|
|
}
|
2018-09-04 19:05:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'lua, T: 'static + UserData> StaticUserDataMethods<'lua, T> {
|
|
|
|
fn box_method<A, R, M>(method: M) -> Callback<'lua, 'static>
|
|
|
|
where
|
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
2020-05-06 08:18:04 -04:00
|
|
|
M: 'static + MaybeSend + Fn(&'lua Lua, &T, A) -> Result<R>,
|
2018-09-04 19:05:21 -04:00
|
|
|
{
|
|
|
|
Box::new(move |lua, mut args| {
|
|
|
|
if let Some(front) = args.pop_front() {
|
|
|
|
let userdata = AnyUserData::from_lua(front, lua)?;
|
2021-06-20 07:38:47 -04:00
|
|
|
// Try normal userdata first
|
|
|
|
let err = match userdata.borrow::<T>() {
|
|
|
|
Ok(ud) => {
|
|
|
|
return method(lua, &ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
2021-05-31 18:33:44 -04:00
|
|
|
}
|
2021-06-20 07:38:47 -04:00
|
|
|
Err(err) => err,
|
|
|
|
};
|
|
|
|
match userdata.type_id()? {
|
|
|
|
id if id == TypeId::of::<T>() => Err(err),
|
2021-05-31 18:33:44 -04:00
|
|
|
#[cfg(not(feature = "send"))]
|
|
|
|
id if id == TypeId::of::<Rc<RefCell<T>>>() => {
|
|
|
|
let ud = userdata.borrow::<Rc<RefCell<T>>>()?;
|
|
|
|
let ud = ud.try_borrow().map_err(|_| Error::UserDataBorrowError)?;
|
|
|
|
method(lua, &ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
|
|
|
}
|
|
|
|
id if id == TypeId::of::<Arc<Mutex<T>>>() => {
|
|
|
|
let ud = userdata.borrow::<Arc<Mutex<T>>>()?;
|
|
|
|
let ud = ud.try_lock().map_err(|_| Error::UserDataBorrowError)?;
|
|
|
|
method(lua, &ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
|
|
|
}
|
|
|
|
id if id == TypeId::of::<Arc<RwLock<T>>>() => {
|
|
|
|
let ud = userdata.borrow::<Arc<RwLock<T>>>()?;
|
|
|
|
let ud = ud.try_read().map_err(|_| Error::UserDataBorrowError)?;
|
|
|
|
method(lua, &ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
|
|
|
}
|
|
|
|
_ => Err(Error::UserDataTypeMismatch),
|
|
|
|
}
|
2018-09-04 19:05:21 -04:00
|
|
|
} else {
|
|
|
|
Err(Error::FromLuaConversionError {
|
|
|
|
from: "missing argument",
|
|
|
|
to: "userdata",
|
|
|
|
message: None,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn box_method_mut<A, R, M>(method: M) -> Callback<'lua, 'static>
|
|
|
|
where
|
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
2020-05-06 08:18:04 -04:00
|
|
|
M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<R>,
|
2018-09-04 19:05:21 -04:00
|
|
|
{
|
|
|
|
let method = RefCell::new(method);
|
|
|
|
Box::new(move |lua, mut args| {
|
|
|
|
if let Some(front) = args.pop_front() {
|
|
|
|
let userdata = AnyUserData::from_lua(front, lua)?;
|
|
|
|
let mut method = method
|
|
|
|
.try_borrow_mut()
|
|
|
|
.map_err(|_| Error::RecursiveMutCallback)?;
|
2021-07-09 18:25:48 -04:00
|
|
|
// Try normal userdata first
|
|
|
|
let err = match userdata.borrow_mut::<T>() {
|
|
|
|
Ok(mut ud) => {
|
|
|
|
return method(lua, &mut ud, A::from_lua_multi(args, lua)?)?
|
|
|
|
.to_lua_multi(lua)
|
2021-05-31 18:33:44 -04:00
|
|
|
}
|
2021-07-09 18:25:48 -04:00
|
|
|
Err(err) => err,
|
|
|
|
};
|
|
|
|
match userdata.type_id()? {
|
|
|
|
id if id == TypeId::of::<T>() => Err(err),
|
2021-05-31 18:33:44 -04:00
|
|
|
#[cfg(not(feature = "send"))]
|
|
|
|
id if id == TypeId::of::<Rc<RefCell<T>>>() => {
|
|
|
|
let ud = userdata.borrow::<Rc<RefCell<T>>>()?;
|
|
|
|
let mut ud = ud
|
|
|
|
.try_borrow_mut()
|
|
|
|
.map_err(|_| Error::UserDataBorrowMutError)?;
|
|
|
|
method(lua, &mut ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
|
|
|
}
|
|
|
|
id if id == TypeId::of::<Arc<Mutex<T>>>() => {
|
|
|
|
let ud = userdata.borrow::<Arc<Mutex<T>>>()?;
|
|
|
|
let mut ud = ud.try_lock().map_err(|_| Error::UserDataBorrowMutError)?;
|
|
|
|
method(lua, &mut ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
|
|
|
}
|
|
|
|
id if id == TypeId::of::<Arc<RwLock<T>>>() => {
|
|
|
|
let ud = userdata.borrow::<Arc<RwLock<T>>>()?;
|
|
|
|
let mut ud = ud.try_write().map_err(|_| Error::UserDataBorrowMutError)?;
|
|
|
|
method(lua, &mut ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
|
|
|
}
|
|
|
|
_ => Err(Error::UserDataTypeMismatch),
|
|
|
|
}
|
2018-09-04 19:05:21 -04:00
|
|
|
} else {
|
|
|
|
Err(Error::FromLuaConversionError {
|
|
|
|
from: "missing argument",
|
|
|
|
to: "userdata",
|
|
|
|
message: None,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-04-17 17:38:01 -04:00
|
|
|
#[cfg(feature = "async")]
|
|
|
|
fn box_async_method<A, R, M, MR>(method: M) -> AsyncCallback<'lua, 'static>
|
|
|
|
where
|
|
|
|
T: Clone,
|
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
2020-05-06 08:18:04 -04:00
|
|
|
M: 'static + MaybeSend + Fn(&'lua Lua, T, A) -> MR,
|
2020-05-05 08:03:28 -04:00
|
|
|
MR: 'lua + Future<Output = Result<R>>,
|
2020-04-17 17:38:01 -04:00
|
|
|
{
|
|
|
|
Box::new(move |lua, mut args| {
|
2020-04-19 11:51:35 -04:00
|
|
|
let fut_res = || {
|
2020-04-17 17:38:01 -04:00
|
|
|
if let Some(front) = args.pop_front() {
|
|
|
|
let userdata = AnyUserData::from_lua(front, lua)?;
|
|
|
|
let userdata = userdata.borrow::<T>()?.clone();
|
|
|
|
Ok(method(lua, userdata, A::from_lua_multi(args, lua)?))
|
|
|
|
} else {
|
|
|
|
Err(Error::FromLuaConversionError {
|
|
|
|
from: "missing argument",
|
|
|
|
to: "userdata",
|
|
|
|
message: None,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
};
|
2020-04-19 11:51:35 -04:00
|
|
|
match fut_res() {
|
|
|
|
Ok(fut) => Box::pin(fut.and_then(move |ret| future::ready(ret.to_lua_multi(lua)))),
|
|
|
|
Err(e) => Box::pin(future::err(e)),
|
2020-04-17 17:38:01 -04:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-09-04 19:05:21 -04:00
|
|
|
fn box_function<A, R, F>(function: F) -> Callback<'lua, 'static>
|
|
|
|
where
|
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
2020-05-06 08:18:04 -04:00
|
|
|
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> Result<R>,
|
2018-09-04 19:05:21 -04:00
|
|
|
{
|
|
|
|
Box::new(move |lua, args| function(lua, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn box_function_mut<A, R, F>(function: F) -> Callback<'lua, 'static>
|
|
|
|
where
|
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
2020-05-06 08:18:04 -04:00
|
|
|
F: 'static + MaybeSend + FnMut(&'lua Lua, A) -> Result<R>,
|
2018-09-04 19:05:21 -04:00
|
|
|
{
|
|
|
|
let function = RefCell::new(function);
|
|
|
|
Box::new(move |lua, args| {
|
|
|
|
let function = &mut *function
|
|
|
|
.try_borrow_mut()
|
|
|
|
.map_err(|_| Error::RecursiveMutCallback)?;
|
|
|
|
function(lua, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
|
|
|
})
|
|
|
|
}
|
2020-04-17 17:38:01 -04:00
|
|
|
|
|
|
|
#[cfg(feature = "async")]
|
|
|
|
fn box_async_function<A, R, F, FR>(function: F) -> AsyncCallback<'lua, 'static>
|
|
|
|
where
|
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
2020-05-06 08:18:04 -04:00
|
|
|
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> FR,
|
2020-05-05 08:03:28 -04:00
|
|
|
FR: 'lua + Future<Output = Result<R>>,
|
2020-04-17 17:38:01 -04:00
|
|
|
{
|
|
|
|
Box::new(move |lua, args| {
|
|
|
|
let args = match A::from_lua_multi(args, lua) {
|
2020-04-19 11:51:35 -04:00
|
|
|
Ok(args) => args,
|
|
|
|
Err(e) => return Box::pin(future::err(e)),
|
2020-04-17 17:38:01 -04:00
|
|
|
};
|
2020-04-19 11:51:35 -04:00
|
|
|
Box::pin(function(lua, args).and_then(move |ret| future::ready(ret.to_lua_multi(lua))))
|
2020-04-17 17:38:01 -04:00
|
|
|
})
|
|
|
|
}
|
2018-09-04 19:05:21 -04:00
|
|
|
}
|
2021-02-19 06:48:56 -05:00
|
|
|
|
|
|
|
struct StaticUserDataFields<'lua, T: 'static + UserData> {
|
|
|
|
field_getters: Vec<(Vec<u8>, Callback<'lua, 'static>)>,
|
|
|
|
field_setters: Vec<(Vec<u8>, Callback<'lua, 'static>)>,
|
2021-03-13 15:01:25 -05:00
|
|
|
#[allow(clippy::type_complexity)]
|
2021-02-19 06:48:56 -05:00
|
|
|
meta_fields: Vec<(
|
|
|
|
MetaMethod,
|
|
|
|
Box<dyn Fn(&'lua Lua) -> Result<Value<'lua>> + 'static>,
|
|
|
|
)>,
|
|
|
|
_type: PhantomData<T>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'lua, T: 'static + UserData> Default for StaticUserDataFields<'lua, T> {
|
|
|
|
fn default() -> StaticUserDataFields<'lua, T> {
|
|
|
|
StaticUserDataFields {
|
|
|
|
field_getters: Vec::new(),
|
|
|
|
field_setters: Vec::new(),
|
|
|
|
meta_fields: Vec::new(),
|
|
|
|
_type: PhantomData,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'lua, T: 'static + UserData> UserDataFields<'lua, T> for StaticUserDataFields<'lua, T> {
|
|
|
|
fn add_field_method_get<S, R, M>(&mut self, name: &S, method: M)
|
|
|
|
where
|
|
|
|
S: AsRef<[u8]> + ?Sized,
|
|
|
|
R: ToLua<'lua>,
|
|
|
|
M: 'static + MaybeSend + Fn(&'lua Lua, &T) -> Result<R>,
|
|
|
|
{
|
|
|
|
self.field_getters.push((
|
|
|
|
name.as_ref().to_vec(),
|
|
|
|
StaticUserDataMethods::box_method(move |lua, data, ()| method(lua, data)),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
fn add_field_method_set<S, A, M>(&mut self, name: &S, method: M)
|
|
|
|
where
|
|
|
|
S: AsRef<[u8]> + ?Sized,
|
|
|
|
A: FromLua<'lua>,
|
|
|
|
M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<()>,
|
|
|
|
{
|
|
|
|
self.field_setters.push((
|
|
|
|
name.as_ref().to_vec(),
|
|
|
|
StaticUserDataMethods::box_method_mut(method),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
fn add_field_function_get<S, R, F>(&mut self, name: &S, function: F)
|
|
|
|
where
|
|
|
|
S: AsRef<[u8]> + ?Sized,
|
|
|
|
R: ToLua<'lua>,
|
|
|
|
F: 'static + MaybeSend + Fn(&'lua Lua, AnyUserData<'lua>) -> Result<R>,
|
|
|
|
{
|
|
|
|
self.field_getters.push((
|
|
|
|
name.as_ref().to_vec(),
|
|
|
|
StaticUserDataMethods::<T>::box_function(move |lua, data| function(lua, data)),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
fn add_field_function_set<S, A, F>(&mut self, name: &S, mut function: F)
|
|
|
|
where
|
|
|
|
S: AsRef<[u8]> + ?Sized,
|
|
|
|
A: FromLua<'lua>,
|
|
|
|
F: 'static + MaybeSend + FnMut(&'lua Lua, AnyUserData<'lua>, A) -> Result<()>,
|
|
|
|
{
|
|
|
|
self.field_setters.push((
|
|
|
|
name.as_ref().to_vec(),
|
|
|
|
StaticUserDataMethods::<T>::box_function_mut(move |lua, (data, val)| {
|
|
|
|
function(lua, data, val)
|
|
|
|
}),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
fn add_meta_field_with<S, R, F>(&mut self, meta: S, f: F)
|
|
|
|
where
|
|
|
|
S: Into<MetaMethod>,
|
|
|
|
R: ToLua<'lua>,
|
|
|
|
F: 'static + MaybeSend + Fn(&'lua Lua) -> Result<R>,
|
|
|
|
{
|
|
|
|
let meta = meta.into();
|
|
|
|
self.meta_fields.push((
|
|
|
|
meta.clone(),
|
|
|
|
Box::new(move |lua| {
|
|
|
|
let value = f(lua)?.to_lua(lua)?;
|
|
|
|
if meta == MetaMethod::Index || meta == MetaMethod::NewIndex {
|
|
|
|
match value {
|
|
|
|
Value::Nil | Value::Table(_) | Value::Function(_) => {}
|
|
|
|
_ => {
|
|
|
|
return Err(Error::MetaMethodTypeError {
|
|
|
|
method: meta.to_string(),
|
|
|
|
type_name: value.type_name(),
|
|
|
|
message: Some("expected nil, table or function".to_string()),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(value)
|
|
|
|
}),
|
|
|
|
));
|
|
|
|
}
|
2021-05-31 18:33:44 -04:00
|
|
|
|
|
|
|
// Below are internal methods
|
|
|
|
|
|
|
|
fn add_field_getter(&mut self, name: Vec<u8>, callback: Callback<'lua, 'static>) {
|
|
|
|
self.field_getters.push((name, callback));
|
|
|
|
}
|
|
|
|
|
|
|
|
fn add_field_setter(&mut self, name: Vec<u8>, callback: Callback<'lua, 'static>) {
|
|
|
|
self.field_setters.push((name, callback));
|
|
|
|
}
|
2021-02-19 06:48:56 -05:00
|
|
|
}
|
2021-05-31 18:33:44 -04:00
|
|
|
|
|
|
|
macro_rules! lua_userdata_impl {
|
|
|
|
($type:ty) => {
|
|
|
|
impl<T: 'static + UserData> UserData for $type {
|
|
|
|
fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) {
|
|
|
|
let mut orig_fields = StaticUserDataFields::default();
|
|
|
|
T::add_fields(&mut orig_fields);
|
|
|
|
for (name, callback) in orig_fields.field_getters {
|
|
|
|
fields.add_field_getter(name, callback);
|
|
|
|
}
|
|
|
|
for (name, callback) in orig_fields.field_setters {
|
|
|
|
fields.add_field_setter(name, callback);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
|
|
|
let mut orig_methods = StaticUserDataMethods::default();
|
|
|
|
T::add_methods(&mut orig_methods);
|
|
|
|
for (name, callback) in orig_methods.methods {
|
|
|
|
methods.add_callback(name, callback);
|
|
|
|
}
|
|
|
|
#[cfg(feature = "async")]
|
|
|
|
for (name, callback) in orig_methods.async_methods {
|
|
|
|
methods.add_async_callback(name, callback);
|
|
|
|
}
|
|
|
|
for (meta, callback) in orig_methods.meta_methods {
|
|
|
|
methods.add_meta_callback(meta, callback);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(feature = "send"))]
|
|
|
|
lua_userdata_impl!(Rc<RefCell<T>>);
|
|
|
|
lua_userdata_impl!(Arc<Mutex<T>>);
|
|
|
|
lua_userdata_impl!(Arc<RwLock<T>>);
|