mlua/src/lua.rs

1836 lines
64 KiB
Rust
Raw Normal View History

2018-08-05 08:51:39 -05:00
use std::any::TypeId;
use std::cell::{RefCell, UnsafeCell};
2018-08-05 08:51:39 -05:00
use std::collections::HashMap;
use std::ffi::CString;
2017-05-21 18:50:59 -05:00
use std::marker::PhantomData;
use std::os::raw::{c_char, c_int};
2020-05-05 20:32:05 -05:00
use std::sync::{Arc, Mutex};
2018-08-05 08:51:39 -05:00
use std::{mem, ptr, str};
2017-05-21 18:50:59 -05:00
use crate::error::{Error, Result};
use crate::ffi;
use crate::function::Function;
use crate::stdlib::StdLib;
use crate::string::String;
use crate::table::Table;
use crate::thread::Thread;
use crate::types::{Callback, Integer, LightUserData, LuaRef, Number, RegistryKey};
use crate::userdata::{AnyUserData, MetaMethod, UserData, UserDataMethods};
use crate::util::{
assert_stack, callback_error, check_stack, get_gc_userdata, get_main_state,
get_meta_gc_userdata, get_wrapped_error, init_error_registry, init_gc_metatable_for,
init_userdata_metatable, pop_error, protect_lua, protect_lua_closure, push_gc_userdata,
push_meta_gc_userdata, push_string, push_userdata, push_wrapped_error, StackGuard,
2018-08-05 08:51:39 -05:00
};
use crate::value::{FromLua, FromLuaMulti, MultiValue, Nil, ToLua, ToLuaMulti, Value};
2017-05-21 18:50:59 -05:00
#[cfg(feature = "async")]
use {
crate::types::AsyncCallback,
2020-04-19 10:51:35 -05:00
futures_core::{
future::{Future, LocalBoxFuture},
task::{Context, Poll, Waker},
},
2020-04-19 10:51:35 -05:00
futures_task::noop_waker,
futures_util::future::{self, TryFutureExt},
};
2017-06-17 20:23:17 -05:00
/// Top level Lua struct which holds the Lua state itself.
2017-05-21 18:50:59 -05:00
pub struct Lua {
pub(crate) state: *mut ffi::lua_State,
main_state: *mut ffi::lua_State,
2020-05-05 20:32:05 -05:00
extra: Arc<Mutex<ExtraData>>,
2019-10-15 10:39:30 -05:00
ephemeral: bool,
// Lua has lots of interior mutability, should not be RefUnwindSafe
_no_ref_unwind_safe: PhantomData<UnsafeCell<()>>,
2017-05-21 18:50:59 -05:00
}
// Data associated with the lua_State.
struct ExtraData {
registered_userdata: HashMap<TypeId, c_int>,
2020-05-05 20:32:05 -05:00
registry_unref_list: Arc<Mutex<Option<Vec<c_int>>>>,
ref_thread: *mut ffi::lua_State,
ref_stack_size: c_int,
ref_stack_max: c_int,
ref_free: Vec<c_int>,
}
2020-05-05 20:32:05 -05:00
unsafe impl Send for Lua {}
#[cfg(feature = "async")]
pub(crate) struct AsyncPollPending;
#[cfg(feature = "async")]
pub(crate) static WAKER_REGISTRY_KEY: u8 = 0;
2019-10-15 10:39:30 -05:00
impl Drop for Lua {
fn drop(&mut self) {
unsafe {
if !self.ephemeral {
2020-05-05 20:32:05 -05:00
let mut extra = mlua_expect!(self.extra.lock(), "extra is poisoned");
2019-10-15 10:39:30 -05:00
mlua_debug_assert!(
ffi::lua_gettop(extra.ref_thread) == extra.ref_stack_max
&& extra.ref_stack_max as usize == extra.ref_free.len(),
"reference leak detected"
);
2020-05-05 20:32:05 -05:00
*mlua_expect!(extra.registry_unref_list.lock(), "unref list poisoned") = None;
ffi::lua_close(self.main_state);
2019-10-15 10:39:30 -05:00
}
}
}
}
2017-05-21 18:50:59 -05:00
impl Lua {
2019-10-15 10:39:30 -05:00
/// Creates a new Lua state and loads standard library without the `debug` library.
2019-10-14 16:21:30 -05:00
pub fn new() -> Lua {
Self::new_with(StdLib::ALL_NO_DEBUG)
}
/// Creates a new Lua state and loads the specified set of standard libraries.
///
/// Use the [`StdLib`] flags to specifiy the libraries you want to load.
///
/// [`StdLib`]: struct.StdLib.html
pub fn new_with(libs: StdLib) -> Lua {
2019-10-14 16:21:30 -05:00
unsafe {
let state = ffi::luaL_newstate();
ffi::luaL_requiref(state, cstr!("_G"), ffi::luaopen_base, 1);
ffi::lua_pop(state, 1);
2019-10-14 16:21:30 -05:00
2019-10-15 10:39:30 -05:00
let mut lua = Lua::init_from_ptr(state);
lua.ephemeral = false;
mlua_expect!(
protect_lua_closure(lua.main_state, 0, 0, |state| {
load_from_std_lib(state, libs);
}),
"Error during loading standard libraries"
);
2019-10-15 10:39:30 -05:00
lua
2019-10-14 16:21:30 -05: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)
}
/// Loads the specified set of standard libraries into an existing Lua state.
///
/// Use the [`StdLib`] flags to specifiy the libraries you want to load.
///
/// [`StdLib`]: struct.StdLib.html
pub fn load_from_std_lib(&self, libs: StdLib) -> Result<()> {
unsafe {
protect_lua_closure(self.main_state, 0, 0, |state| {
load_from_std_lib(state, libs);
})
}
}
/// Constructs a new Lua instance from the existing state.
pub unsafe fn init_from_ptr(state: *mut ffi::lua_State) -> Lua {
let main_state = get_main_state(state);
let main_state_top = ffi::lua_gettop(state);
2017-05-21 18:50:59 -05:00
2019-10-01 10:11:12 -05:00
let ref_thread = mlua_expect!(
protect_lua_closure(main_state, 0, 0, |state| {
init_error_registry(state);
// Create the internal metatables and place them in the registry
// to prevent them from being garbage collected.
init_gc_metatable_for::<Callback>(state, None);
init_gc_metatable_for::<Lua>(state, None);
#[cfg(feature = "async")]
{
init_gc_metatable_for::<AsyncCallback>(state, None);
init_gc_metatable_for::<LocalBoxFuture<Result<MultiValue>>>(state, None);
init_gc_metatable_for::<AsyncPollPending>(state, None);
init_gc_metatable_for::<Waker>(state, None);
}
// Create ref stack thread and place it in the registry to prevent it from being garbage
// collected.
let _ref_thread = ffi::lua_newthread(state);
ffi::luaL_ref(state, ffi::LUA_REGISTRYINDEX);
_ref_thread
}),
"Error during Lua construction",
);
// Create ExtraData
2020-05-05 20:32:05 -05:00
let extra = Arc::new(Mutex::new(ExtraData {
registered_userdata: HashMap::new(),
2020-05-05 20:32:05 -05:00
registry_unref_list: Arc::new(Mutex::new(Some(Vec::new()))),
ref_thread,
// We need 1 extra stack space to move values in and out of the ref stack.
ref_stack_size: ffi::LUA_MINSTACK - 1,
ref_stack_max: 0,
ref_free: Vec::new(),
}));
2019-10-01 10:11:12 -05:00
mlua_debug_assert!(
ffi::lua_gettop(main_state) == main_state_top,
2019-09-27 11:38:24 -05:00
"stack leak during creation"
);
assert_stack(main_state, ffi::LUA_MINSTACK);
Lua {
state,
main_state: main_state,
extra: extra,
2019-10-15 10:39:30 -05:00
ephemeral: true,
_no_ref_unwind_safe: PhantomData,
}
}
2019-10-01 12:11:51 -05:00
// Executes module entrypoint function, which returns only one Value.
// The returned value then pushed to the Lua stack.
#[doc(hidden)]
pub fn entrypoint1<'lua, 'callback, R, F>(&'lua self, func: F) -> Result<c_int>
where
2020-05-04 05:56:42 -05:00
'lua: 'callback,
2019-10-01 12:11:51 -05:00
R: ToLua<'callback>,
2020-05-05 20:32:05 -05:00
F: 'static + Send + Fn(&'callback Lua) -> Result<R>,
2019-10-01 12:11:51 -05:00
{
let cb = self.create_callback(Box::new(move |lua, _| func(lua)?.to_lua_multi(lua)))?;
unsafe { self.push_value(cb.call(())?).map(|_| 1) }
}
/// Returns true if the garbage collector is currently running automatically.
2019-11-29 07:26:30 -06:00
#[cfg(any(feature = "lua53", feature = "lua52"))]
pub fn gc_is_running(&self) -> bool {
unsafe { ffi::lua_gc(self.main_state, ffi::LUA_GCISRUNNING, 0) != 0 }
}
/// Stop the Lua GC from running
pub fn gc_stop(&self) {
unsafe {
ffi::lua_gc(self.main_state, ffi::LUA_GCSTOP, 0);
}
}
/// Restarts the Lua GC if it is not running
pub fn gc_restart(&self) {
unsafe {
ffi::lua_gc(self.main_state, ffi::LUA_GCRESTART, 0);
}
}
/// Perform a full garbage-collection cycle.
///
/// It may be necessary to call this function twice to collect all currently unreachable
/// objects. Once to finish the current gc cycle, and once to start and finish the next cycle.
pub fn gc_collect(&self) -> Result<()> {
unsafe {
protect_lua_closure(self.main_state, 0, 0, |state| {
ffi::lua_gc(state, ffi::LUA_GCCOLLECT, 0);
})
}
}
/// Steps the garbage collector one indivisible step.
2017-06-17 20:23:17 -05: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 20:23:17 -05:00
///
/// if `kbytes` is 0, then this is the same as calling `gc_step`. Returns true if this step has
/// finished a collection cycle.
pub fn gc_step_kbytes(&self, kbytes: c_int) -> Result<bool> {
unsafe {
protect_lua_closure(self.main_state, 0, 0, |state| {
ffi::lua_gc(state, ffi::LUA_GCSTEP, kbytes) != 0
})
}
}
/// Sets the 'pause' value of the collector.
///
/// Returns the previous value of 'pause'. More information can be found in the [Lua 5.3
/// 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 {
unsafe { ffi::lua_gc(self.main_state, ffi::LUA_GCSETPAUSE, pause) }
}
/// Sets the 'step multiplier' value of the collector.
///
/// Returns the previous value of the 'step multiplier'. More information can be found in the
/// [Lua 5.3 documentation][lua_doc].
///
/// [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 {
unsafe { ffi::lua_gc(self.main_state, ffi::LUA_GCSETSTEPMUL, step_multiplier) }
}
/// 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
/// similar on the returned builder. Code is not even parsed until one of these methods is
/// called.
///
/// [`Chunk::exec`]: struct.Chunk.html#method.exec
pub fn load<'lua, 'a, S>(&'lua self, source: &'a S) -> Chunk<'lua, 'a>
where
S: ?Sized + AsRef<[u8]>,
{
Chunk {
lua: self,
source: source.as_ref(),
name: None,
env: None,
}
}
fn load_chunk<'lua>(
&'lua self,
source: &[u8],
name: Option<&CString>,
2019-09-27 11:38:24 -05:00
env: Option<Value<'lua>>,
) -> Result<Function<'lua>> {
2017-05-21 18:50:59 -05:00
unsafe {
let _sg = StackGuard::new(self.state);
assert_stack(self.state, 1);
match if let Some(name) = name {
ffi::luaL_loadbufferx(
self.state,
source.as_ptr() as *const c_char,
source.len(),
name.as_ptr() as *const c_char,
cstr!("t"),
)
} else {
ffi::luaL_loadbufferx(
self.state,
source.as_ptr() as *const c_char,
source.len(),
ptr::null(),
cstr!("t"),
)
} {
ffi::LUA_OK => {
if let Some(env) = env {
self.push_value(env)?;
2019-11-29 07:26:30 -06:00
#[cfg(any(feature = "lua53", feature = "lua52"))]
ffi::lua_setupvalue(self.state, -2, 1);
#[cfg(any(feature = "lua51", feature = "luajit"))]
2019-10-14 16:21:30 -05:00
ffi::lua_setfenv(self.state, -2);
}
Ok(Function(self.pop_ref()))
}
err => Err(pop_error(self.state, err)),
}
2017-05-21 18:50:59 -05:00
}
}
2018-09-30 14:42:04 -05:00
/// Create and return an interned Lua string. Lua strings can be arbitrary [u8] data including
/// embedded nulls, so in addition to `&str` and `&String`, you can also pass plain `&[u8]`
/// here.
pub fn create_string<S>(&self, s: &S) -> Result<String>
where
S: ?Sized + AsRef<[u8]>,
{
2017-05-21 18:50:59 -05:00
unsafe {
let _sg = StackGuard::new(self.state);
assert_stack(self.state, 4);
push_string(self.state, s)?;
Ok(String(self.pop_ref()))
2017-05-21 18:50:59 -05:00
}
}
2017-06-17 20:23:17 -05:00
/// Creates and returns a new table.
pub fn create_table(&self) -> Result<Table> {
2017-05-21 18:50:59 -05:00
unsafe {
let _sg = StackGuard::new(self.state);
assert_stack(self.state, 3);
unsafe extern "C" fn new_table(state: *mut ffi::lua_State) -> c_int {
ffi::lua_newtable(state);
1
}
protect_lua(self.state, 0, new_table)?;
Ok(Table(self.pop_ref()))
2017-05-21 18:50:59 -05:00
}
}
2017-06-17 20:23:17 -05:00
/// Creates a table and fills it with values from an iterator.
pub fn create_table_from<'lua, K, V, I>(&'lua self, cont: I) -> Result<Table<'lua>>
2017-06-15 09:26:39 -05:00
where
K: ToLua<'lua>,
V: ToLua<'lua>,
I: IntoIterator<Item = (K, V)>,
2017-05-21 18:50:59 -05:00
{
unsafe {
let _sg = StackGuard::new(self.state);
// `Lua` instance assumes that on any callback, the Lua stack has at least LUA_MINSTACK
// slots available to avoid panics.
check_stack(self.state, 5 + ffi::LUA_MINSTACK)?;
unsafe extern "C" fn new_table(state: *mut ffi::lua_State) -> c_int {
ffi::lua_newtable(state);
1
}
protect_lua(self.state, 0, new_table)?;
for (k, v) in cont {
self.push_value(k.to_lua(self)?)?;
self.push_value(v.to_lua(self)?)?;
unsafe extern "C" fn raw_set(state: *mut ffi::lua_State) -> c_int {
ffi::lua_rawset(state, -3);
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 22:20:10 -05:00
1
}
protect_lua(self.state, 3, raw_set)?;
}
Ok(Table(self.pop_ref()))
2017-05-21 18:50:59 -05:00
}
}
2017-06-17 20:23:17 -05:00
/// Creates a table from an iterator of values, using `1..` as the keys.
pub fn create_sequence_from<'lua, T, I>(&'lua self, cont: I) -> Result<Table<'lua>>
2017-06-15 09:26:39 -05:00
where
T: ToLua<'lua>,
I: IntoIterator<Item = T>,
2017-05-21 18:50:59 -05:00
{
self.create_table_from(cont.into_iter().enumerate().map(|(k, v)| (k + 1, v)))
2017-05-21 18:50:59 -05:00
}
2017-06-17 20:23:17 -05:00
/// Wraps a Rust function or closure, creating a callable Lua function handle to it.
2017-07-25 18:54:40 -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 18:54:40 -05:00
/// # Examples
///
/// Create a function which prints its argument:
///
/// ```
2019-10-01 10:11:12 -05:00
/// # use mlua::{Lua, Result};
/// # fn main() -> Result<()> {
2019-10-17 10:59:33 -05:00
/// # let lua = Lua::new();
/// let greet = lua.create_function(|_, name: String| {
2017-07-25 18:54:40 -05:00
/// println!("Hello, {}!", name);
/// Ok(())
2017-07-25 18:54:40 -05:00
/// });
/// # let _ = greet; // used
/// # Ok(())
/// # }
/// ```
///
/// Use tuples to accept multiple arguments:
2017-07-25 18:54:40 -05:00
///
/// ```
2019-10-01 10:11:12 -05:00
/// # use mlua::{Lua, Result};
/// # fn main() -> Result<()> {
2019-10-17 10:59:33 -05:00
/// # let lua = Lua::new();
/// let print_person = lua.create_function(|_, (name, age): (String, u8)| {
2017-07-25 18:54:40 -05:00
/// println!("{} is {} years old!", name, age);
/// Ok(())
2017-07-25 18:54:40 -05:00
/// });
/// # let _ = print_person; // used
/// # Ok(())
/// # }
/// ```
///
/// [`ToLua`]: trait.ToLua.html
/// [`ToLuaMulti`]: trait.ToLuaMulti.html
pub fn create_function<'lua, 'callback, A, R, F>(&'lua self, func: F) -> Result<Function<'lua>>
2017-06-15 09:26:39 -05:00
where
2020-05-04 05:56:42 -05:00
'lua: 'callback,
A: FromLuaMulti<'callback>,
R: ToLuaMulti<'callback>,
2020-05-05 20:32:05 -05:00
F: 'static + Send + Fn(&'callback Lua, A) -> Result<R>,
2017-05-21 18:50:59 -05:00
{
self.create_callback(Box::new(move |lua, args| {
func(lua, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
}))
2017-05-21 18:50:59 -05:00
}
2018-02-11 16:54:17 -06:00
/// Wraps a Rust mutable closure, creating a callable Lua function handle to it.
///
/// This is a version of [`create_function`] that accepts a FnMut argument. Refer to
/// [`create_function`] for more information about the implementation.
///
/// [`create_function`]: #method.create_function
pub fn create_function_mut<'lua, 'callback, A, R, F>(
&'lua self,
func: F,
) -> Result<Function<'lua>>
where
2020-05-04 05:56:42 -05:00
'lua: 'callback,
A: FromLuaMulti<'callback>,
R: ToLuaMulti<'callback>,
2020-05-05 20:32:05 -05:00
F: 'static + Send + FnMut(&'callback Lua, A) -> Result<R>,
{
let func = RefCell::new(func);
self.create_function(move |lua, args| {
2018-08-05 08:51:39 -05:00
(&mut *func
.try_borrow_mut()
.map_err(|_| Error::RecursiveMutCallback)?)(lua, args)
})
}
/// 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
/// `yield()` passing internal representation of a `Poll::Pending` value.
///
/// 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
/// in that case. Otherwise noop waker will be used if try to call the function outside of Rust
/// executors.
///
/// The family of `call_async()` functions takes care about creating [`Thread`].
///
/// # Examples
///
/// Non blocking sleep:
///
/// ```
/// use std::time::Duration;
/// use futures_timer::Delay;
/// use mlua::{Lua, Result};
///
/// async fn sleep(_lua: &Lua, n: u64) -> Result<&'static str> {
/// Delay::new(Duration::from_millis(n)).await;
/// Ok("done")
/// }
///
/// #[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(())
/// }
/// ```
///
/// [`Thread`]: struct.Thread.html
/// [`ThreadStream`]: struct.ThreadStream.html
#[cfg(feature = "async")]
pub fn create_async_function<'lua, 'callback, A, R, F, FR>(
&'lua self,
func: F,
) -> Result<Function<'lua>>
where
2020-05-04 05:56:42 -05:00
'lua: 'callback,
A: FromLuaMulti<'callback>,
R: ToLuaMulti<'callback>,
2020-05-05 20:32:05 -05:00
F: 'static + Send + Fn(&'callback Lua, A) -> FR,
FR: 'lua + Future<Output = Result<R>>,
{
self.create_async_callback(Box::new(move |lua, args| {
let args = match A::from_lua_multi(args, lua) {
2020-04-19 10:51:35 -05:00
Ok(args) => args,
Err(e) => return Box::pin(future::err(e)),
};
2020-04-19 10:51:35 -05:00
Box::pin(func(lua, args).and_then(move |ret| future::ready(ret.to_lua_multi(lua))))
}))
}
2017-06-17 20:23:17 -05:00
/// Wraps a Lua function into a new thread (or coroutine).
///
/// Equivalent to `coroutine.create`.
pub fn create_thread<'lua>(&'lua self, func: Function<'lua>) -> Result<Thread<'lua>> {
unsafe {
let _sg = StackGuard::new(self.state);
assert_stack(self.state, 2);
let thread_state =
protect_lua_closure(self.state, 0, 1, |state| ffi::lua_newthread(state))?;
self.push_ref(&func.0);
ffi::lua_xmove(self.state, thread_state, 1);
Ok(Thread(self.pop_ref()))
}
}
2017-06-17 20:23:17 -05:00
/// Create a Lua userdata object from a custom userdata type.
pub fn create_userdata<T>(&self, data: T) -> Result<AnyUserData>
2017-06-15 09:26:39 -05:00
where
2020-05-05 20:32:05 -05:00
T: 'static + Send + UserData,
2017-05-21 18:50:59 -05:00
{
unsafe { self.make_userdata(data) }
2017-05-21 18:50:59 -05:00
}
2017-06-17 20:23:17 -05:00
/// Returns a handle to the global environment.
pub fn globals(&self) -> Table {
2017-05-21 18:50:59 -05:00
unsafe {
let _sg = StackGuard::new(self.state);
assert_stack(self.state, 2);
2019-11-29 07:26:30 -06:00
#[cfg(any(feature = "lua53", feature = "lua52"))]
ffi::lua_rawgeti(self.state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS);
#[cfg(any(feature = "lua51", feature = "luajit"))]
2019-10-14 16:21:30 -05:00
ffi::lua_pushvalue(self.state, ffi::LUA_GLOBALSINDEX);
Table(self.pop_ref())
2017-05-21 18:50:59 -05:00
}
}
/// Returns a handle to the active `Thread`. For calls to `Lua` this will be the main Lua thread,
/// for parameters given to a callback, this will be whatever Lua thread called the callback.
pub fn current_thread<'lua>(&'lua self) -> Thread<'lua> {
unsafe {
ffi::lua_pushthread(self.state);
Thread(self.pop_ref())
}
}
/// Attempts to coerce a Lua value into a String in a manner consistent with Lua's internal
/// behavior.
2017-06-17 20:23:17 -05:00
///
/// To succeed, the value must be a string (in which case this is a no-op), an integer, or a
/// number.
pub fn coerce_string<'lua>(&'lua self, v: Value<'lua>) -> Result<Option<String<'lua>>> {
Ok(match v {
Value::String(s) => Some(s),
2017-05-21 18:50:59 -05:00
v => unsafe {
let _sg = StackGuard::new(self.state);
assert_stack(self.state, 4);
self.push_value(v)?;
if protect_lua_closure(self.state, 1, 1, |state| {
!ffi::lua_tostring(state, -1).is_null()
})? {
Some(String(self.pop_ref()))
} else {
None
}
2017-05-21 18:50:59 -05:00
},
})
2017-05-21 18:50:59 -05:00
}
/// Attempts to coerce a Lua value into an integer in a manner consistent with Lua's internal
/// behavior.
2017-06-17 20:23:17 -05: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.
pub fn coerce_integer(&self, v: Value) -> Result<Option<Integer>> {
Ok(match v {
Value::Integer(i) => Some(i),
2017-05-21 18:50:59 -05:00
v => unsafe {
let _sg = StackGuard::new(self.state);
assert_stack(self.state, 2);
self.push_value(v)?;
let mut isint = 0;
let i = ffi::lua_tointegerx(self.state, -1, &mut isint);
if isint == 0 {
None
} else {
Some(i)
}
2017-05-21 18:50:59 -05:00
},
})
2017-05-21 18:50:59 -05:00
}
/// Attempts to coerce a Lua value into a Number in a manner consistent with Lua's internal
/// behavior.
2017-06-17 20:23:17 -05: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.
pub fn coerce_number(&self, v: Value) -> Result<Option<Number>> {
Ok(match v {
Value::Number(n) => Some(n),
2017-05-21 18:50:59 -05:00
v => unsafe {
let _sg = StackGuard::new(self.state);
assert_stack(self.state, 2);
self.push_value(v)?;
let mut isnum = 0;
let n = ffi::lua_tonumberx(self.state, -1, &mut isnum);
if isnum == 0 {
None
} else {
Some(n)
}
2017-05-21 18:50:59 -05:00
},
})
2017-05-21 18:50:59 -05: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 18:50:59 -05:00
t.to_lua(self)
}
/// 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 18:50:59 -05:00
T::from_lua(value, self)
}
/// 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 18:50:59 -05:00
t.to_lua_multi(self)
}
/// 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 18:50:59 -05:00
T::from_lua_multi(value, self)
}
2017-12-16 17:05:53 -06:00
/// Set a value in the Lua registry based on a string name.
///
/// This value will be available to rust from all `Lua` instances which share the same main
/// state.
2019-09-27 11:38:24 -05:00
pub fn set_named_registry_value<'lua, S, T>(&'lua self, name: &S, t: T) -> Result<()>
where
S: ?Sized + AsRef<[u8]>,
T: ToLua<'lua>,
{
let t = t.to_lua(self)?;
unsafe {
let _sg = StackGuard::new(self.state);
assert_stack(self.state, 5);
push_string(self.state, name)?;
self.push_value(t)?;
unsafe extern "C" fn set_registry(state: *mut ffi::lua_State) -> c_int {
ffi::lua_rawset(state, ffi::LUA_REGISTRYINDEX);
0
}
protect_lua(self.state, 2, set_registry)
}
}
2017-12-16 17:05:53 -06:00
/// Get a value from the Lua registry based on a string name.
///
2018-02-11 16:54:17 -06: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
pub fn named_registry_value<'lua, S, T>(&'lua self, name: &S) -> Result<T>
where
S: ?Sized + AsRef<[u8]>,
T: FromLua<'lua>,
{
let value = unsafe {
let _sg = StackGuard::new(self.state);
assert_stack(self.state, 4);
push_string(self.state, name)?;
unsafe extern "C" fn get_registry(state: *mut ffi::lua_State) -> c_int {
ffi::lua_rawget(state, ffi::LUA_REGISTRYINDEX);
1
}
protect_lua(self.state, 1, get_registry)?;
self.pop_value()
};
T::from_lua(value, self)
}
/// Removes a named value in the Lua registry.
2017-12-16 17:05:53 -06:00
///
2018-02-11 17:17:15 -06:00
/// Equivalent to calling [`set_named_registry_value`] with a value of Nil.
2018-02-11 16:54:17 -06:00
///
/// [`set_named_registry_value`]: #method.set_named_registry_value
2020-05-04 05:56:42 -05:00
pub fn unset_named_registry_value<S>(&self, name: &S) -> Result<()>
where
S: ?Sized + AsRef<[u8]>,
{
2017-12-16 17:05:53 -06:00
self.set_named_registry_value(name, Nil)
}
/// 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
/// state.
///
/// Be warned, garbage collection of values held inside the registry is not automatic, see
/// [`RegistryKey`] for more details.
///
/// [`RegistryKey`]: struct.RegistryKey.html
pub fn create_registry_value<'lua, T: ToLua<'lua>>(&'lua self, t: T) -> Result<RegistryKey> {
let t = t.to_lua(self)?;
unsafe {
let _sg = StackGuard::new(self.state);
assert_stack(self.state, 2);
self.push_value(t)?;
let registry_id = protect_lua_closure(self.state, 1, 0, |state| {
ffi::luaL_ref(state, ffi::LUA_REGISTRYINDEX)
})?;
2020-05-05 20:32:05 -05:00
let extra = mlua_expect!(self.extra.lock(), "extra is poisoned");
Ok(RegistryKey {
registry_id,
2020-05-05 20:32:05 -05:00
unref_list: extra.registry_unref_list.clone(),
})
}
}
/// Get a value from the Lua registry by its `RegistryKey`
///
2018-02-11 16:54:17 -06: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
pub fn registry_value<'lua, T: FromLua<'lua>>(&'lua self, key: &RegistryKey) -> Result<T> {
let value = unsafe {
if !self.owns_registry_value(key) {
return Err(Error::MismatchedRegistryKey);
}
let _sg = StackGuard::new(self.state);
assert_stack(self.state, 2);
ffi::lua_rawgeti(
self.state,
ffi::LUA_REGISTRYINDEX,
key.registry_id as ffi::lua_Integer,
);
self.pop_value()
};
T::from_lua(value, self)
}
/// Removes a value from the Lua registry.
///
/// You may call this function to manually remove a value placed in the registry with
2018-02-11 16:54:17 -06: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
/// `RegistryKey`s have been dropped.
2018-02-11 16:54:17 -06: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 22:20:10 -05:00
pub fn remove_registry_value(&self, key: RegistryKey) -> Result<()> {
unsafe {
if !self.owns_registry_value(&key) {
return Err(Error::MismatchedRegistryKey);
}
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 22:20:10 -05:00
ffi::luaL_unref(self.state, ffi::LUA_REGISTRYINDEX, key.take());
Ok(())
}
}
/// Returns true if the given `RegistryKey` was created by a `Lua` which shares the underlying
/// main state with this `Lua` instance.
///
/// 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.
pub fn owns_registry_value(&self, key: &RegistryKey) -> bool {
2020-05-05 20:32:05 -05:00
let extra = mlua_expect!(self.extra.lock(), "extra is poisoned");
Arc::ptr_eq(&key.unref_list, &extra.registry_unref_list)
}
2018-02-11 16:54:17 -06:00
/// Remove any registry values whose `RegistryKey`s have all been dropped.
///
/// 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`.
pub fn expire_registry_values(&self) {
unsafe {
2020-05-05 20:32:05 -05:00
let mut extra = mlua_expect!(self.extra.lock(), "extra is poisoned");
let unref_list = mem::replace(
2020-05-05 20:32:05 -05:00
&mut *mlua_expect!(extra.registry_unref_list.lock(), "unref list poisoned"),
Some(Vec::new()),
);
2019-10-01 10:11:12 -05:00
for id in mlua_expect!(unref_list, "unref list not set") {
ffi::luaL_unref(self.state, ffi::LUA_REGISTRYINDEX, id);
}
}
}
// Uses 2 stack spaces, does not call checkstack
2019-10-01 12:11:51 -05:00
pub(crate) unsafe fn push_value(&self, value: Value) -> Result<()> {
match value {
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 22:20:10 -05:00
ffi::lua_pushnil(self.state);
}
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 22:20:10 -05:00
ffi::lua_pushboolean(self.state, if b { 1 } else { 0 });
}
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 22:20:10 -05:00
ffi::lua_pushlightuserdata(self.state, ud.0);
}
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 22:20:10 -05:00
ffi::lua_pushinteger(self.state, i);
}
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 22:20:10 -05:00
ffi::lua_pushnumber(self.state, n);
}
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 22:20:10 -05:00
self.push_ref(&s.0);
}
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 22:20:10 -05:00
self.push_ref(&t.0);
}
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 22:20:10 -05:00
self.push_ref(&f.0);
}
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 22:20:10 -05:00
self.push_ref(&t.0);
}
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 22:20:10 -05:00
self.push_ref(&ud.0);
}
Value::Error(e) => {
push_wrapped_error(self.state, e)?;
}
}
Ok(())
}
// Uses 2 stack spaces, does not call checkstack
2019-10-01 12:11:51 -05:00
pub(crate) unsafe fn pop_value(&self) -> Value {
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 22:20:10 -05:00
match ffi::lua_type(self.state, -1) {
ffi::LUA_TNIL => {
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 22:20:10 -05:00
ffi::lua_pop(self.state, 1);
Nil
}
ffi::LUA_TBOOLEAN => {
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 22:20:10 -05:00
let b = Value::Boolean(ffi::lua_toboolean(self.state, -1) != 0);
ffi::lua_pop(self.state, 1);
b
}
ffi::LUA_TLIGHTUSERDATA => {
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 22:20:10 -05:00
let ud = Value::LightUserData(LightUserData(ffi::lua_touserdata(self.state, -1)));
ffi::lua_pop(self.state, 1);
ud
}
ffi::LUA_TNUMBER => {
if ffi::lua_isinteger(self.state, -1) != 0 {
let i = Value::Integer(ffi::lua_tointeger(self.state, -1));
ffi::lua_pop(self.state, 1);
i
} else {
let n = Value::Number(ffi::lua_tonumber(self.state, -1));
ffi::lua_pop(self.state, 1);
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 22:20:10 -05:00
ffi::LUA_TSTRING => Value::String(String(self.pop_ref())),
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 22:20:10 -05:00
ffi::LUA_TTABLE => Value::Table(Table(self.pop_ref())),
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 22:20:10 -05:00
ffi::LUA_TFUNCTION => Value::Function(Function(self.pop_ref())),
ffi::LUA_TUSERDATA => {
// It should not be possible to interact with userdata types other than custom
// UserData types OR a WrappedError. WrappedPanic should not be here.
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 22:20:10 -05:00
if let Some(err) = get_wrapped_error(self.state, -1).as_ref() {
let err = err.clone();
ffi::lua_pop(self.state, 1);
Value::Error(err)
} else {
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 22:20:10 -05:00
Value::UserData(AnyUserData(self.pop_ref()))
}
}
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 22:20:10 -05:00
ffi::LUA_TTHREAD => Value::Thread(Thread(self.pop_ref())),
2019-10-01 10:11:12 -05:00
_ => mlua_panic!("LUA_TNONE in pop_value"),
}
}
// 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>) {
assert!(
lref.lua.main_state == self.main_state,
"Lua instance passed Value created from a different main Lua state"
);
2020-05-05 20:32:05 -05:00
let extra = mlua_expect!(self.extra.lock(), "extra is poisoned");
ffi::lua_pushvalue(extra.ref_thread, lref.index);
ffi::lua_xmove(extra.ref_thread, self.state, 1);
}
// Pops the topmost element of the stack and stores a reference to it. This pins the object,
// preventing garbage collection until the returned `LuaRef` is dropped.
//
// References are stored in the stack of a specially created auxiliary thread that exists only
// to store reference values. This is much faster than storing these in the registry, and also
// much more flexible and requires less bookkeeping than storing them directly in the currently
// used stack. The implementation is somewhat biased towards the use case of a relatively small
// number of short term references being created, and `RegistryKey` being used for long term
// references.
pub(crate) unsafe fn pop_ref<'lua>(&'lua self) -> LuaRef<'lua> {
2020-05-05 20:32:05 -05:00
let mut extra = mlua_expect!(self.extra.lock(), "extra is poisoned");
ffi::lua_xmove(self.state, extra.ref_thread, 1);
let index = ref_stack_pop(&mut extra);
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 22:20:10 -05: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 22:20:10 -05:00
unsafe {
2020-05-05 20:32:05 -05:00
let mut extra = mlua_expect!(self.extra.lock(), "extra is poisoned");
ffi::lua_pushvalue(extra.ref_thread, lref.index);
let index = ref_stack_pop(&mut extra);
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 22:20:10 -05: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 22:20:10 -05:00
unsafe {
2020-05-05 20:32:05 -05:00
let mut extra = mlua_expect!(self.extra.lock(), "extra is poisoned");
ffi::lua_pushnil(extra.ref_thread);
ffi::lua_replace(extra.ref_thread, lref.index);
extra.ref_free.push(lref.index);
}
}
pub(crate) unsafe fn userdata_metatable<T: 'static + UserData>(&self) -> Result<c_int> {
2020-05-05 20:32:05 -05:00
if let Some(table_id) = mlua_expect!(self.extra.lock(), "extra is poisoned")
.registered_userdata
.get(&TypeId::of::<T>())
{
return Ok(*table_id);
}
let _sg = StackGuard::new(self.state);
assert_stack(self.state, 8);
2017-05-21 18:50:59 -05:00
let mut methods = StaticUserDataMethods::default();
T::add_methods(&mut methods);
protect_lua_closure(self.state, 0, 1, |state| {
ffi::lua_newtable(state);
})?;
for (k, m) in methods.meta_methods {
push_string(self.state, k.name())?;
self.push_value(Value::Function(self.create_callback(m)?))?;
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 22:20:10 -05:00
protect_lua_closure(self.state, 3, 1, |state| {
ffi::lua_rawset(state, -3);
})?;
}
2017-05-21 18:50:59 -05:00
#[cfg(feature = "async")]
let no_methods = methods.methods.is_empty() && methods.async_methods.is_empty();
#[cfg(not(feature = "async"))]
let no_methods = methods.methods.is_empty();
if no_methods {
init_userdata_metatable::<RefCell<T>>(self.state, -1, None)?;
} else {
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 22:20:10 -05:00
protect_lua_closure(self.state, 0, 1, |state| {
ffi::lua_newtable(state);
})?;
for (k, m) in methods.methods {
push_string(self.state, &k)?;
self.push_value(Value::Function(self.create_callback(m)?))?;
protect_lua_closure(self.state, 3, 1, |state| {
ffi::lua_rawset(state, -3);
})?;
}
#[cfg(feature = "async")]
for (k, m) in methods.async_methods {
push_string(self.state, &k)?;
self.push_value(Value::Function(self.create_async_callback(m)?))?;
protect_lua_closure(self.state, 3, 1, |state| {
ffi::lua_rawset(state, -3);
})?;
}
init_userdata_metatable::<RefCell<T>>(self.state, -2, Some(-1))?;
ffi::lua_pop(self.state, 1);
}
2017-05-21 18:50:59 -05:00
let id = protect_lua_closure(self.state, 1, 0, |state| {
ffi::luaL_ref(state, ffi::LUA_REGISTRYINDEX)
})?;
2020-05-05 20:32:05 -05:00
mlua_expect!(self.extra.lock(), "extra is poisoned")
.registered_userdata
.insert(TypeId::of::<T>(), id);
Ok(id)
2017-05-21 18:50:59 -05: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
// cannot easily deal with the "correct" callback type of:
//
// Box<for<'lua> Fn(&'lua Lua, MultiValue<'lua>) -> Result<MultiValue<'lua>>)>
//
2018-09-04 18:09:09 -05:00
// So we instead use a caller provided lifetime, which without the 'static requirement would be
// unsafe.
pub(crate) fn create_callback<'lua, 'callback>(
&'lua self,
func: Callback<'callback, 'static>,
2020-05-04 05:56:42 -05:00
) -> Result<Function<'lua>>
where
'lua: 'callback,
{
unsafe extern "C" fn call_callback(state: *mut ffi::lua_State) -> c_int {
callback_error(state, |nargs| {
let func =
get_meta_gc_userdata::<Callback, Callback>(state, ffi::lua_upvalueindex(1));
let lua = get_gc_userdata::<Lua>(state, ffi::lua_upvalueindex(2));
if func.is_null() || lua.is_null() {
return Err(Error::CallbackDestructed);
}
if nargs < ffi::LUA_MINSTACK {
check_stack(state, ffi::LUA_MINSTACK - nargs)?;
}
let lua = &mut *lua;
lua.state = state;
let mut args = MultiValue::new();
args.reserve(nargs as usize);
for _ in 0..nargs {
args.push_front(lua.pop_value());
}
let results = (*func)(lua, args)?;
let nresults = results.len() as c_int;
check_stack(state, nresults)?;
for r in results {
lua.push_value(r)?;
}
Ok(nresults)
})
}
unsafe {
let _sg = StackGuard::new(self.state);
assert_stack(self.state, 6);
push_meta_gc_userdata::<Callback, _>(self.state, func)?;
push_gc_userdata(self.state, self.clone())?;
protect_lua_closure(self.state, 2, 1, |state| {
ffi::lua_pushcclosure(state, call_callback, 2);
})?;
Ok(Function(self.pop_ref()))
}
}
#[cfg(feature = "async")]
pub(crate) fn create_async_callback<'lua, 'callback>(
&'lua self,
func: AsyncCallback<'callback, 'static>,
2020-05-04 05:56:42 -05:00
) -> Result<Function<'lua>>
where
'lua: 'callback,
{
#[cfg(any(feature = "lua53", feature = "lua52"))]
self.load_from_std_lib(StdLib::COROUTINE)?;
unsafe extern "C" fn call_callback(state: *mut ffi::lua_State) -> c_int {
callback_error(state, |nargs| {
let func = get_meta_gc_userdata::<AsyncCallback, AsyncCallback>(
state,
ffi::lua_upvalueindex(1),
);
let lua = get_gc_userdata::<Lua>(state, ffi::lua_upvalueindex(2));
if func.is_null() || lua.is_null() {
return Err(Error::CallbackDestructed);
}
if nargs < ffi::LUA_MINSTACK {
check_stack(state, ffi::LUA_MINSTACK - nargs)?;
}
let lua = &mut *lua;
lua.state = state;
let mut args = MultiValue::new();
args.reserve(nargs as usize);
for _ in 0..nargs {
args.push_front(lua.pop_value());
}
let fut = (*func)(lua, args);
push_gc_userdata(state, fut)?;
push_gc_userdata(state, lua.clone())?;
ffi::lua_pushcclosure(state, poll_future, 2);
Ok(1)
})
}
unsafe extern "C" fn poll_future(state: *mut ffi::lua_State) -> c_int {
callback_error(state, |nargs| {
let fut = get_gc_userdata::<LocalBoxFuture<Result<MultiValue>>>(
state,
ffi::lua_upvalueindex(1),
);
let lua = get_gc_userdata::<Lua>(state, ffi::lua_upvalueindex(2));
if fut.is_null() || lua.is_null() {
return Err(Error::CallbackDestructed);
}
if nargs < ffi::LUA_MINSTACK {
check_stack(state, ffi::LUA_MINSTACK - nargs)?;
}
let lua = &mut *lua;
let mut waker = noop_waker();
// Try to get an outer poll waker
ffi::lua_pushlightuserdata(
state,
&WAKER_REGISTRY_KEY as *const u8 as *mut ::std::os::raw::c_void,
);
ffi::lua_rawget(state, ffi::LUA_REGISTRYINDEX);
if let Some(w) = get_gc_userdata::<Waker>(state, -1).as_ref() {
waker = (*w).clone();
}
ffi::lua_pop(state, 1);
let mut ctx = Context::from_waker(&waker);
match (*fut).as_mut().poll(&mut ctx) {
Poll::Pending => {
check_stack(state, 6)?;
ffi::lua_pushboolean(state, 0);
push_gc_userdata(state, AsyncPollPending)?;
Ok(2)
}
Poll::Ready(results) => {
let results = lua.create_sequence_from(results?)?;
check_stack(state, 2)?;
ffi::lua_pushboolean(state, 1);
lua.push_value(Value::Table(results))?;
Ok(2)
}
}
})
}
let get_poll = unsafe {
let _sg = StackGuard::new(self.state);
assert_stack(self.state, 6);
push_meta_gc_userdata::<AsyncCallback, _>(self.state, func)?;
push_gc_userdata(self.state, self.clone())?;
protect_lua_closure(self.state, 2, 1, |state| {
ffi::lua_pushcclosure(state, call_callback, 2);
})?;
Function(self.pop_ref())
};
let coroutine = self.globals().get::<_, Table>("coroutine")?;
let env = self.create_table()?;
env.set("get_poll", get_poll)?;
env.set("yield", coroutine.get::<_, Function>("yield")?)?;
env.set(
"unpack",
self.create_function(|_, tbl: Table| {
Ok(MultiValue::from_vec(
tbl.sequence_values().collect::<Result<Vec<Value>>>()?,
))
})?,
)?;
self.load(
r#"
local poll = get_poll(...)
while true do
ready, res = poll()
if ready then
return unpack(res)
end
yield(res)
end
"#,
)
.set_name("_mlua_async_poll")?
.set_environment(env)?
.into_function()
}
pub(crate) unsafe fn make_userdata<T>(&self, data: T) -> Result<AnyUserData>
where
T: 'static + UserData,
{
let _sg = StackGuard::new(self.state);
assert_stack(self.state, 4);
let ud_index = self.userdata_metatable::<T>()?;
push_userdata::<RefCell<T>>(self.state, RefCell::new(data))?;
ffi::lua_rawgeti(
self.state,
ffi::LUA_REGISTRYINDEX,
ud_index as ffi::lua_Integer,
);
ffi::lua_setmetatable(self.state, -2);
Ok(AnyUserData(self.pop_ref()))
}
pub(crate) fn clone(&self) -> Self {
Lua {
state: self.state,
main_state: self.main_state,
extra: self.extra.clone(),
ephemeral: true,
_no_ref_unwind_safe: PhantomData,
}
}
}
/// 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>,
env: Option<Value<'lua>>,
}
impl<'lua, 'a> Chunk<'lua, 'a> {
/// Sets the name of this chunk, which results in more informative error traces.
pub fn set_name<S: ?Sized + AsRef<[u8]>>(mut self, name: &S) -> Result<Chunk<'lua, 'a>> {
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`
/// variable inside the chunk. By default this value is set to the global environment.
///
/// 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>> {
self.env = Some(env.to_lua(self.lua)?);
Ok(self)
}
/// 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(())
}
/// Asynchronously execute this chunk of code.
///
/// See [`Chunk::exec`] for more details.
///
/// [`Chunk::exec`]: struct.Chunk.html#method.exec
#[cfg(feature = "async")]
pub fn exec_async<'fut>(self) -> LocalBoxFuture<'fut, Result<()>>
where
'lua: 'fut,
{
self.call_async(())
}
/// 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
/// the value that it evaluates to. Otherwise, the chunk is interpreted as a block as normal,
/// and this is equivalent to calling `exec`.
pub fn eval<R: FromLuaMulti<'lua>>(self) -> Result<R> {
// First, try interpreting the lua as an expression by adding
// "return", then as a statement. This is the same thing the
// actual lua repl does.
if let Ok(function) = self.lua.load_chunk(
&self.expression_source(),
self.name.as_ref(),
self.env.clone(),
) {
function.call(())
} else {
self.call(())
}
}
/// Asynchronously evaluate the chunk as either an expression or block.
///
/// See [`Chunk::eval`] for more details.
///
/// [`Chunk::eval`]: struct.Chunk.html#method.eval
#[cfg(feature = "async")]
pub fn eval_async<'fut, R>(self) -> LocalBoxFuture<'fut, Result<R>>
where
'lua: 'fut,
R: FromLuaMulti<'lua> + 'fut,
{
if let Ok(function) = self.lua.load_chunk(
&self.expression_source(),
self.name.as_ref(),
self.env.clone(),
) {
function.call_async(())
} else {
self.call_async(())
}
}
/// Load the chunk function and call it with the given arguemnts.
///
/// 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)
}
/// Load the chunk function and asynchronously call it with the given arguemnts.
///
/// See [`Chunk::call`] for more details.
///
/// [`Chunk::call`]: struct.Chunk.html#method.call
#[cfg(feature = "async")]
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 10:51:35 -05:00
Ok(func) => func.call_async(args),
Err(e) => Box::pin(future::err(e)),
}
}
/// 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 11:38:24 -05:00
self.lua
.load_chunk(self.source, self.name.as_ref(), self.env)
}
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
}
}
unsafe fn load_from_std_lib(state: *mut ffi::lua_State, libs: StdLib) {
#[cfg(any(feature = "lua53", feature = "lua52"))]
{
if libs.contains(StdLib::COROUTINE) {
let colib_name = CString::new(ffi::LUA_COLIBNAME).unwrap();
ffi::luaL_requiref(state, colib_name.as_ptr(), ffi::luaopen_coroutine, 1);
ffi::lua_pop(state, 1);
}
}
if libs.contains(StdLib::TABLE) {
let tablib_name = CString::new(ffi::LUA_TABLIBNAME).unwrap();
ffi::luaL_requiref(state, tablib_name.as_ptr(), ffi::luaopen_table, 1);
ffi::lua_pop(state, 1);
}
if libs.contains(StdLib::IO) {
let iolib_name = CString::new(ffi::LUA_IOLIBNAME).unwrap();
ffi::luaL_requiref(state, iolib_name.as_ptr(), ffi::luaopen_io, 1);
ffi::lua_pop(state, 1);
}
if libs.contains(StdLib::OS) {
let oslib_name = CString::new(ffi::LUA_OSLIBNAME).unwrap();
ffi::luaL_requiref(state, oslib_name.as_ptr(), ffi::luaopen_os, 1);
ffi::lua_pop(state, 1);
}
if libs.contains(StdLib::STRING) {
let strlib_name = CString::new(ffi::LUA_STRLIBNAME).unwrap();
ffi::luaL_requiref(state, strlib_name.as_ptr(), ffi::luaopen_string, 1);
ffi::lua_pop(state, 1);
}
#[cfg(feature = "lua53")]
{
if libs.contains(StdLib::UTF8) {
let utf8lib_name = CString::new(ffi::LUA_UTF8LIBNAME).unwrap();
ffi::luaL_requiref(state, utf8lib_name.as_ptr(), ffi::luaopen_utf8, 1);
ffi::lua_pop(state, 1);
}
}
#[cfg(feature = "lua52")]
{
if libs.contains(StdLib::BIT) {
let bitlib_name = CString::new(ffi::LUA_BITLIBNAME).unwrap();
ffi::luaL_requiref(state, bitlib_name.as_ptr(), ffi::luaopen_bit32, 1);
ffi::lua_pop(state, 1);
}
}
#[cfg(feature = "luajit")]
{
if libs.contains(StdLib::BIT) {
let bitlib_name = CString::new(ffi::LUA_BITLIBNAME).unwrap();
ffi::luaL_requiref(state, bitlib_name.as_ptr(), ffi::luaopen_bit, 1);
ffi::lua_pop(state, 1);
}
}
if libs.contains(StdLib::MATH) {
let mathlib_name = CString::new(ffi::LUA_MATHLIBNAME).unwrap();
ffi::luaL_requiref(state, mathlib_name.as_ptr(), ffi::luaopen_math, 1);
ffi::lua_pop(state, 1);
}
if libs.contains(StdLib::DEBUG) {
let dblib_name = CString::new(ffi::LUA_DBLIBNAME).unwrap();
ffi::luaL_requiref(state, dblib_name.as_ptr(), ffi::luaopen_debug, 1);
ffi::lua_pop(state, 1);
}
if libs.contains(StdLib::PACKAGE) {
let loadlib_name = CString::new(ffi::LUA_LOADLIBNAME).unwrap();
ffi::luaL_requiref(state, loadlib_name.as_ptr(), ffi::luaopen_package, 1);
ffi::lua_pop(state, 1);
}
#[cfg(feature = "luajit")]
{
if libs.contains(StdLib::JIT) {
let jitlib_name = CString::new(ffi::LUA_JITLIBNAME).unwrap();
ffi::luaL_requiref(state, jitlib_name.as_ptr(), ffi::luaopen_jit, 1);
ffi::lua_pop(state, 1);
}
if libs.contains(StdLib::FFI) {
let ffilib_name = CString::new(ffi::LUA_FFILIBNAME).unwrap();
ffi::luaL_requiref(state, ffilib_name.as_ptr(), ffi::luaopen_ffi, 1);
ffi::lua_pop(state, 1);
}
}
}
unsafe fn ref_stack_pop(extra: &mut ExtraData) -> c_int {
if let Some(free) = extra.ref_free.pop() {
ffi::lua_replace(extra.ref_thread, free);
free
} else {
if extra.ref_stack_max >= extra.ref_stack_size {
// It is a user error to create enough references to exhaust the Lua max stack size for
// the ref thread.
if ffi::lua_checkstack(extra.ref_thread, extra.ref_stack_size) == 0 {
2019-10-01 10:11:12 -05:00
mlua_panic!("cannot create a Lua reference, out of auxiliary stack space");
}
extra.ref_stack_size *= 2;
}
extra.ref_stack_max += 1;
extra.ref_stack_max
}
}
struct StaticUserDataMethods<'lua, T: 'static + UserData> {
methods: Vec<(Vec<u8>, Callback<'lua, 'static>)>,
#[cfg(feature = "async")]
async_methods: Vec<(Vec<u8>, AsyncCallback<'lua, 'static>)>,
meta_methods: Vec<(MetaMethod, Callback<'lua, 'static>)>,
_type: PhantomData<T>,
}
impl<'lua, T: 'static + UserData> Default for StaticUserDataMethods<'lua, T> {
fn default() -> StaticUserDataMethods<'lua, T> {
StaticUserDataMethods {
methods: Vec::new(),
#[cfg(feature = "async")]
async_methods: Vec::new(),
meta_methods: Vec::new(),
_type: PhantomData,
}
}
}
impl<'lua, T: 'static + UserData> UserDataMethods<'lua, T> for StaticUserDataMethods<'lua, T> {
fn add_method<S, A, R, M>(&mut self, name: &S, method: M)
where
S: ?Sized + AsRef<[u8]>,
A: FromLuaMulti<'lua>,
R: ToLuaMulti<'lua>,
2020-05-05 20:32:05 -05:00
M: 'static + Send + Fn(&'lua Lua, &T, A) -> Result<R>,
{
self.methods
.push((name.as_ref().to_vec(), Self::box_method(method)));
}
fn add_method_mut<S, A, R, M>(&mut self, name: &S, method: M)
where
S: ?Sized + AsRef<[u8]>,
A: FromLuaMulti<'lua>,
R: ToLuaMulti<'lua>,
2020-05-05 20:32:05 -05:00
M: 'static + Send + FnMut(&'lua Lua, &mut T, A) -> Result<R>,
{
self.methods
.push((name.as_ref().to_vec(), Self::box_method_mut(method)));
}
#[cfg(feature = "async")]
fn add_async_method<S, A, R, M, MR>(&mut self, name: &S, method: M)
where
T: Clone,
S: ?Sized + AsRef<[u8]>,
A: FromLuaMulti<'lua>,
R: ToLuaMulti<'lua>,
2020-05-05 20:32:05 -05:00
M: 'static + Send + Fn(&'lua Lua, T, A) -> MR,
MR: 'lua + Future<Output = Result<R>>,
{
self.async_methods
.push((name.as_ref().to_vec(), Self::box_async_method(method)));
}
fn add_function<S, A, R, F>(&mut self, name: &S, function: F)
where
S: ?Sized + AsRef<[u8]>,
A: FromLuaMulti<'lua>,
R: ToLuaMulti<'lua>,
2020-05-05 20:32:05 -05:00
F: 'static + Send + Fn(&'lua Lua, A) -> Result<R>,
{
self.methods
.push((name.as_ref().to_vec(), Self::box_function(function)));
}
fn add_function_mut<S, A, R, F>(&mut self, name: &S, function: F)
where
S: ?Sized + AsRef<[u8]>,
A: FromLuaMulti<'lua>,
R: ToLuaMulti<'lua>,
2020-05-05 20:32:05 -05:00
F: 'static + Send + FnMut(&'lua Lua, A) -> Result<R>,
{
self.methods
.push((name.as_ref().to_vec(), Self::box_function_mut(function)));
}
#[cfg(feature = "async")]
fn add_async_function<S, A, R, F, FR>(&mut self, name: &S, function: F)
where
T: Clone,
S: ?Sized + AsRef<[u8]>,
A: FromLuaMulti<'lua>,
R: ToLuaMulti<'lua>,
2020-05-05 20:32:05 -05:00
F: 'static + Send + Fn(&'lua Lua, A) -> FR,
FR: 'lua + Future<Output = Result<R>>,
{
self.async_methods
.push((name.as_ref().to_vec(), Self::box_async_function(function)));
}
fn add_meta_method<A, R, M>(&mut self, meta: MetaMethod, method: M)
where
A: FromLuaMulti<'lua>,
R: ToLuaMulti<'lua>,
2020-05-05 20:32:05 -05:00
M: 'static + Send + Fn(&'lua Lua, &T, A) -> Result<R>,
{
self.meta_methods.push((meta, Self::box_method(method)));
}
fn add_meta_method_mut<A, R, M>(&mut self, meta: MetaMethod, method: M)
where
A: FromLuaMulti<'lua>,
R: ToLuaMulti<'lua>,
2020-05-05 20:32:05 -05:00
M: 'static + Send + FnMut(&'lua Lua, &mut T, A) -> Result<R>,
{
self.meta_methods.push((meta, Self::box_method_mut(method)));
}
fn add_meta_function<A, R, F>(&mut self, meta: MetaMethod, function: F)
where
A: FromLuaMulti<'lua>,
R: ToLuaMulti<'lua>,
2020-05-05 20:32:05 -05:00
F: 'static + Send + Fn(&'lua Lua, A) -> Result<R>,
{
self.meta_methods.push((meta, Self::box_function(function)));
}
fn add_meta_function_mut<A, R, F>(&mut self, meta: MetaMethod, function: F)
where
A: FromLuaMulti<'lua>,
R: ToLuaMulti<'lua>,
2020-05-05 20:32:05 -05:00
F: 'static + Send + FnMut(&'lua Lua, A) -> Result<R>,
{
self.meta_methods
.push((meta, Self::box_function_mut(function)));
}
}
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-05 20:32:05 -05:00
M: 'static + Send + Fn(&'lua Lua, &T, A) -> Result<R>,
{
Box::new(move |lua, mut args| {
if let Some(front) = args.pop_front() {
let userdata = AnyUserData::from_lua(front, lua)?;
let userdata = userdata.borrow::<T>()?;
method(lua, &userdata, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
} 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-05 20:32:05 -05:00
M: 'static + Send + FnMut(&'lua Lua, &mut T, A) -> Result<R>,
{
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 userdata = userdata.borrow_mut::<T>()?;
let mut method = method
.try_borrow_mut()
.map_err(|_| Error::RecursiveMutCallback)?;
(&mut *method)(lua, &mut userdata, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
} else {
Err(Error::FromLuaConversionError {
from: "missing argument",
to: "userdata",
message: None,
})
}
})
}
#[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-05 20:32:05 -05:00
M: 'static + Send + Fn(&'lua Lua, T, A) -> MR,
MR: 'lua + Future<Output = Result<R>>,
{
Box::new(move |lua, mut args| {
2020-04-19 10:51:35 -05:00
let fut_res = || {
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 10:51:35 -05: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)),
}
})
}
fn box_function<A, R, F>(function: F) -> Callback<'lua, 'static>
where
A: FromLuaMulti<'lua>,
R: ToLuaMulti<'lua>,
2020-05-05 20:32:05 -05:00
F: 'static + Send + Fn(&'lua Lua, A) -> Result<R>,
{
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-05 20:32:05 -05:00
F: 'static + Send + FnMut(&'lua Lua, A) -> Result<R>,
{
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)
})
}
#[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-05 20:32:05 -05:00
F: 'static + Send + Fn(&'lua Lua, A) -> FR,
FR: 'lua + Future<Output = Result<R>>,
{
Box::new(move |lua, args| {
let args = match A::from_lua_multi(args, lua) {
2020-04-19 10:51:35 -05:00
Ok(args) => args,
Err(e) => return Box::pin(future::err(e)),
};
2020-04-19 10:51:35 -05:00
Box::pin(function(lua, args).and_then(move |ret| future::ready(ret.to_lua_multi(lua))))
})
}
}