diff --git a/src/lua.rs b/src/lua.rs index 259a69f..d3a96bc 100644 --- a/src/lua.rs +++ b/src/lua.rs @@ -107,7 +107,7 @@ pub(crate) struct ExtraData { // Pool of `WrappedFailure` enums in the ref thread (as userdata) wrapped_failure_pool: Vec, // Pool of `MultiValue` containers - multivalue_pool: Vec>, + multivalue_pool: Vec>>, // Pool of `Thread`s (coroutines) for async execution #[cfg(feature = "async")] thread_pool: Vec, @@ -2898,8 +2898,7 @@ impl Lua { let lua: &Lua = mem::transmute((*extra).inner.assume_init_ref()); let _guard = StateGuard::new(&lua.0, state); - let mut args = MultiValue::new_or_pooled(lua); - args.reserve(nargs as usize); + let mut args = MultiValue::with_lua_and_capacity(lua, nargs as usize); for _ in 0..nargs { args.push_front(lua.pop_value()); } @@ -2943,7 +2942,6 @@ impl Lua { for r in results.drain_all() { lua.push_value(r)?; } - MultiValue::return_to_pool(results, lua); Ok(nresults as c_int + 1) } _ => { @@ -3184,13 +3182,13 @@ impl LuaInner { } #[inline] - pub(crate) fn new_multivalue_from_pool(&self) -> MultiValue { + pub(crate) fn pop_multivalue_from_pool(&self) -> Option> { let extra = unsafe { &mut *self.extra.get() }; - extra.multivalue_pool.pop().unwrap_or_default() + extra.multivalue_pool.pop() } #[inline] - pub(crate) fn return_multivalue_to_pool(&self, mut multivalue: MultiValue) { + pub(crate) fn push_multivalue_to_pool(&self, mut multivalue: Vec) { let extra = unsafe { &mut *self.extra.get() }; if extra.multivalue_pool.len() < MULTIVALUE_POOL_SIZE { multivalue.clear(); diff --git a/src/multi.rs b/src/multi.rs index 2145693..485e626 100644 --- a/src/multi.rs +++ b/src/multi.rs @@ -13,7 +13,7 @@ use crate::value::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, MultiValue, Nil impl<'lua, T: IntoLua<'lua>, E: IntoLua<'lua>> IntoLuaMulti<'lua> for StdResult { #[inline] fn into_lua_multi(self, lua: &'lua Lua) -> Result> { - let mut result = MultiValue::new_or_pooled(lua); + let mut result = MultiValue::with_lua_and_capacity(lua, 2); match self { Ok(v) => result.push_front(v.into_lua(lua)?), Err(e) => { @@ -28,7 +28,7 @@ impl<'lua, T: IntoLua<'lua>, E: IntoLua<'lua>> IntoLuaMulti<'lua> for StdResult< impl<'lua, T: IntoLua<'lua>> IntoLuaMulti<'lua> for T { #[inline] fn into_lua_multi(self, lua: &'lua Lua) -> Result> { - let mut v = MultiValue::new_or_pooled(lua); + let mut v = MultiValue::with_lua_and_capacity(lua, 1); v.push_front(self.into_lua(lua)?); Ok(v) } @@ -43,9 +43,7 @@ impl<'lua, T: IntoLua<'lua>> IntoLuaMulti<'lua> for T { impl<'lua, T: FromLua<'lua>> FromLuaMulti<'lua> for T { #[inline] fn from_lua_multi(mut values: MultiValue<'lua>, lua: &'lua Lua) -> Result { - let res = T::from_lua(values.pop_front().unwrap_or(Nil), lua); - MultiValue::return_to_pool(values, lua); - res + T::from_lua(values.pop_front().unwrap_or(Nil), lua) } #[inline] @@ -55,9 +53,7 @@ impl<'lua, T: FromLua<'lua>> FromLuaMulti<'lua> for T { to: Option<&str>, lua: &'lua Lua, ) -> Result { - let res = T::from_lua_arg(args.pop_front().unwrap_or(Nil), i, to, lua); - MultiValue::return_to_pool(args, lua); - res + T::from_lua_arg(args.pop_front().unwrap_or(Nil), i, to, lua) } #[inline] @@ -170,7 +166,7 @@ impl DerefMut for Variadic { impl<'lua, T: IntoLua<'lua>> IntoLuaMulti<'lua> for Variadic { #[inline] fn into_lua_multi(self, lua: &'lua Lua) -> Result> { - let mut values = MultiValue::new_or_pooled(lua); + let mut values = MultiValue::with_lua_and_capacity(lua, self.0.len()); values.refill(self.0.into_iter().map(|e| e.into_lua(lua)))?; Ok(values) } @@ -179,13 +175,11 @@ impl<'lua, T: IntoLua<'lua>> IntoLuaMulti<'lua> for Variadic { impl<'lua, T: FromLua<'lua>> FromLuaMulti<'lua> for Variadic { #[inline] fn from_lua_multi(mut values: MultiValue<'lua>, lua: &'lua Lua) -> Result { - let res = values + values .drain_all() .map(|e| T::from_lua(e, lua)) .collect::>>() - .map(Variadic); - MultiValue::return_to_pool(values, lua); - res + .map(Variadic) } } @@ -194,7 +188,7 @@ macro_rules! impl_tuple { impl<'lua> IntoLuaMulti<'lua> for () { #[inline] fn into_lua_multi(self, lua: &'lua Lua) -> Result> { - Ok(MultiValue::new_or_pooled(lua)) + Ok(MultiValue::with_lua_and_capacity(lua, 0)) } #[inline] @@ -205,8 +199,7 @@ macro_rules! impl_tuple { impl<'lua> FromLuaMulti<'lua> for () { #[inline] - fn from_lua_multi(values: MultiValue<'lua>, lua: &'lua Lua) -> Result { - MultiValue::return_to_pool(values, lua); + fn from_lua_multi(_values: MultiValue<'lua>, _lua: &'lua Lua) -> Result { Ok(()) } diff --git a/src/value.rs b/src/value.rs index 2a3ee19..2caa98e 100644 --- a/src/value.rs +++ b/src/value.rs @@ -5,7 +5,7 @@ use std::ops::Index; use std::os::raw::{c_int, c_void}; use std::string::String as StdString; use std::sync::Arc; -use std::{fmt, ptr, slice, str, vec}; +use std::{fmt, mem, ptr, slice, str, vec}; #[cfg(feature = "serialize")] use { @@ -379,24 +379,43 @@ pub trait FromLua<'lua>: Sized { /// Multiple Lua values used for both argument passing and also for multiple return values. #[derive(Debug, Clone)] -pub struct MultiValue<'lua>(Vec>); +pub struct MultiValue<'lua> { + vec: Vec>, + lua: Option<&'lua Lua>, +} + +impl Drop for MultiValue<'_> { + fn drop(&mut self) { + if let Some(lua) = self.lua { + let vec = mem::replace(&mut self.vec, Vec::new()); + lua.push_multivalue_to_pool(vec); + } + } +} impl<'lua> MultiValue<'lua> { /// Creates an empty `MultiValue` containing no values. pub const fn new() -> MultiValue<'lua> { - MultiValue(Vec::new()) + MultiValue { + vec: Vec::new(), + lua: None, + } } - /// Similar to `new` but can return previously used container with allocated capacity. + /// Similar to `new` but can reuse previously used container with allocated capacity. #[inline] - pub(crate) fn new_or_pooled(lua: &'lua Lua) -> MultiValue<'lua> { - lua.new_multivalue_from_pool() - } - - /// Clears and returns previously allocated multivalue container to the pool. - #[inline] - pub(crate) fn return_to_pool(multivalue: Self, lua: &Lua) { - lua.return_multivalue_to_pool(multivalue); + pub(crate) fn with_lua_and_capacity(lua: &'lua Lua, capacity: usize) -> MultiValue<'lua> { + let vec = lua + .pop_multivalue_from_pool() + .map(|mut vec| { + vec.reserve(capacity); + vec + }) + .unwrap_or_else(|| Vec::with_capacity(capacity)); + MultiValue { + vec, + lua: Some(lua), + } } } @@ -419,8 +438,10 @@ impl<'lua> IntoIterator for MultiValue<'lua> { type IntoIter = iter::Rev>>; #[inline] - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter().rev() + fn into_iter(mut self) -> Self::IntoIter { + let vec = mem::replace(&mut self.vec, Vec::new()); + mem::forget(self); + vec.into_iter().rev() } } @@ -430,7 +451,7 @@ impl<'a, 'lua> IntoIterator for &'a MultiValue<'lua> { #[inline] fn into_iter(self) -> Self::IntoIter { - self.0.iter().rev() + self.vec.iter().rev() } } @@ -453,64 +474,60 @@ impl<'lua> Index for MultiValue<'lua> { impl<'lua> MultiValue<'lua> { #[inline] - pub fn from_vec(mut v: Vec>) -> MultiValue<'lua> { - v.reverse(); - MultiValue(v) + pub fn from_vec(mut vec: Vec>) -> MultiValue<'lua> { + vec.reverse(); + MultiValue { vec, lua: None } } #[inline] - pub fn into_vec(self) -> Vec> { - let mut v = self.0; - v.reverse(); - v + pub fn into_vec(mut self) -> Vec> { + let mut vec = mem::replace(&mut self.vec, Vec::new()); + mem::forget(self); + vec.reverse(); + vec } #[inline] pub fn get(&self, index: usize) -> Option<&Value<'lua>> { - if index < self.0.len() { - return self.0.get(self.0.len() - index - 1); + if index < self.vec.len() { + return self.vec.get(self.vec.len() - index - 1); } None } - #[inline] - pub(crate) fn reserve(&mut self, size: usize) { - self.0.reserve(size); - } - #[inline] pub fn pop_front(&mut self) -> Option> { - self.0.pop() + self.vec.pop() } #[inline] pub fn push_front(&mut self, value: Value<'lua>) { - self.0.push(value); + self.vec.push(value); } #[inline] pub fn clear(&mut self) { - self.0.clear(); + self.vec.clear(); } #[inline] pub fn len(&self) -> usize { - self.0.len() + self.vec.len() } #[inline] pub fn is_empty(&self) -> bool { - self.0.is_empty() + self.vec.is_empty() } #[inline] pub fn iter(&self) -> iter::Rev>> { - self.0.iter().rev() + self.vec.iter().rev() } #[inline] pub(crate) fn drain_all(&mut self) -> iter::Rev>> { - self.0.drain(..).rev() + self.vec.drain(..).rev() } #[inline] @@ -518,11 +535,11 @@ impl<'lua> MultiValue<'lua> { &mut self, iter: impl IntoIterator>>, ) -> Result<()> { - self.0.clear(); + self.vec.clear(); for value in iter { - self.0.push(value?); + self.vec.push(value?); } - self.0.reverse(); + self.vec.reverse(); Ok(()) } } @@ -543,15 +560,12 @@ pub trait IntoLuaMulti<'lua>: Sized { unsafe fn push_into_stack_multi(self, lua: &'lua Lua) -> Result { let mut values = self.into_lua_multi(lua)?; let len: c_int = values.len().try_into().unwrap(); - unsafe { check_stack(lua.state(), len + 1)?; for v in values.drain_all() { lua.push_value(v)?; } } - MultiValue::return_to_pool(values, lua); - Ok(len) } } @@ -589,8 +603,7 @@ pub trait FromLuaMulti<'lua>: Sized { #[doc(hidden)] #[inline] unsafe fn from_stack_multi(nvals: c_int, lua: &'lua Lua) -> Result { - let mut values = MultiValue::new_or_pooled(lua); - values.reserve(nvals as usize); + let mut values = MultiValue::with_lua_and_capacity(lua, nvals as usize); for idx in 1..=nvals { values.push_front(lua.stack_value(-idx)); }