diff --git a/src/lua.rs b/src/lua.rs index b1d6f37..dd04cc6 100644 --- a/src/lua.rs +++ b/src/lua.rs @@ -1,5 +1,6 @@ use std::any::TypeId; use std::cell::{Cell, RefCell, UnsafeCell}; +use std::collections::VecDeque; use std::ffi::{CStr, CString}; use std::fmt; use std::marker::PhantomData; @@ -105,7 +106,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, @@ -3255,13 +3256,13 @@ impl LuaInner { } #[inline] - pub(crate) fn pop_multivalue_from_pool(&self) -> Option> { + pub(crate) fn pop_multivalue_from_pool(&self) -> Option> { let extra = unsafe { &mut *self.extra.get() }; extra.multivalue_pool.pop() } #[inline] - pub(crate) fn push_multivalue_to_pool(&self, mut multivalue: Vec) { + pub(crate) fn push_multivalue_to_pool(&self, mut multivalue: VecDeque) { 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 f9b9a93..c321078 100644 --- a/src/multi.rs +++ b/src/multi.rs @@ -12,28 +12,17 @@ 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::with_lua_and_capacity(lua, 2); match self { - Ok(v) => result.push_front(v.into_lua(lua)?), - Err(e) => { - result.push_front(e.into_lua(lua)?); - result.push_front(Nil); - } + Ok(val) => (val,).into_lua_multi(lua), + Err(err) => (Nil, err).into_lua_multi(lua), } - Ok(result) } #[inline] unsafe fn push_into_stack_multi(self, lua: &'lua Lua) -> Result { match self { - Ok(v) => v.push_into_stack(lua).map(|_| 1), - Err(e) => { - let state = lua.state(); - check_stack(state, 3)?; - ffi::lua_pushnil(state); - e.push_into_stack(lua)?; - Ok(2) - } + Ok(val) => (val,).push_into_stack_multi(lua), + Err(err) => (Nil, err).push_into_stack_multi(lua), } } } @@ -42,13 +31,8 @@ impl<'lua, E: IntoLua<'lua>> IntoLuaMulti<'lua> for StdResult<(), E> { #[inline] fn into_lua_multi(self, lua: &'lua Lua) -> Result> { match self { - Ok(_) => return Ok(MultiValue::new()), - Err(e) => { - let mut result = MultiValue::with_lua_and_capacity(lua, 2); - result.push_front(e.into_lua(lua)?); - result.push_front(Nil); - Ok(result) - } + Ok(_) => Ok(MultiValue::new()), + Err(err) => (Nil, err).into_lua_multi(lua), } } @@ -56,13 +40,7 @@ impl<'lua, E: IntoLua<'lua>> IntoLuaMulti<'lua> for StdResult<(), E> { unsafe fn push_into_stack_multi(self, lua: &'lua Lua) -> Result { match self { Ok(_) => Ok(0), - Err(e) => { - let state = lua.state(); - check_stack(state, 3)?; - ffi::lua_pushnil(state); - e.push_into_stack(lua)?; - Ok(2) - } + Err(err) => (Nil, err).push_into_stack_multi(lua), } } } @@ -71,7 +49,7 @@ impl<'lua, T: IntoLua<'lua>> IntoLuaMulti<'lua> for T { #[inline] fn into_lua_multi(self, lua: &'lua Lua) -> Result> { let mut v = MultiValue::with_lua_and_capacity(lua, 1); - v.push_front(self.into_lua(lua)?); + v.push_back(self.into_lua(lua)?); Ok(v) } @@ -209,7 +187,7 @@ impl<'lua, T: IntoLua<'lua>> IntoLuaMulti<'lua> for Variadic { #[inline] fn into_lua_multi(self, lua: &'lua Lua) -> Result> { let mut values = MultiValue::with_lua_and_capacity(lua, self.0.len()); - values.refill(self.0.into_iter().map(|e| e.into_lua(lua)))?; + values.extend_from_values(self.0.into_iter().map(|val| val.into_lua(lua)))?; Ok(values) } } @@ -218,8 +196,8 @@ impl<'lua, T: FromLua<'lua>> FromLuaMulti<'lua> for Variadic { #[inline] fn from_lua_multi(mut values: MultiValue<'lua>, lua: &'lua Lua) -> Result { values - .drain_all() - .map(|e| T::from_lua(e, lua)) + .drain(..) + .map(|val| T::from_lua(val, lua)) .collect::>>() .map(Variadic) } diff --git a/src/value.rs b/src/value.rs index 94a562a..8ebfc42 100644 --- a/src/value.rs +++ b/src/value.rs @@ -1,12 +1,11 @@ use std::borrow::Cow; use std::cmp::Ordering; -use std::collections::HashSet; -use std::iter; -use std::ops::Index; +use std::collections::{vec_deque, HashSet, VecDeque}; +use std::ops::{Deref, DerefMut}; use std::os::raw::{c_int, c_void}; use std::string::String as StdString; use std::sync::Arc; -use std::{fmt, mem, ptr, slice, str, vec}; +use std::{fmt, mem, ptr, str}; use num_traits::FromPrimitive; @@ -751,45 +750,19 @@ 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: Vec>, + deque: VecDeque>, lua: Option<&'lua Lua>, } impl Drop for MultiValue<'_> { fn drop(&mut self) { if let Some(lua) = self.lua { - let vec = mem::take(&mut self.vec); + let vec = mem::take(&mut self.deque); 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: Vec::new(), - lua: None, - } - } - - /// Similar to `new` but can reuse previously used container with allocated capacity. - #[inline] - 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), - } - } -} - impl<'lua> Default for MultiValue<'lua> { #[inline] fn default() -> MultiValue<'lua> { @@ -797,121 +770,88 @@ impl<'lua> Default for MultiValue<'lua> { } } +impl<'lua> Deref for MultiValue<'lua> { + type Target = VecDeque>; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.deque + } +} + +impl<'lua> DerefMut for MultiValue<'lua> { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.deque + } +} + +impl<'lua> MultiValue<'lua> { + /// Creates an empty `MultiValue` containing no values. + pub const fn new() -> MultiValue<'lua> { + MultiValue { + deque: VecDeque::new(), + lua: None, + } + } + + /// Similar to `new` but can reuse previously used container with allocated capacity. + #[inline] + pub(crate) fn with_lua_and_capacity(lua: &'lua Lua, capacity: usize) -> MultiValue<'lua> { + let deque = lua + .pop_multivalue_from_pool() + .map(|mut deque| { + if capacity > 0 { + deque.reserve(capacity); + } + deque + }) + .unwrap_or_else(|| VecDeque::with_capacity(capacity)); + MultiValue { + deque, + lua: Some(lua), + } + } + + #[inline] + pub(crate) fn extend_from_values( + &mut self, + iter: impl IntoIterator>>, + ) -> Result<()> { + for value in iter { + self.push_back(value?); + } + Ok(()) + } +} + impl<'lua> FromIterator> for MultiValue<'lua> { #[inline] fn from_iter>>(iter: I) -> Self { - MultiValue::from_vec(Vec::from_iter(iter)) + let deque = VecDeque::from_iter(iter); + MultiValue { deque, lua: None } } } impl<'lua> IntoIterator for MultiValue<'lua> { type Item = Value<'lua>; - type IntoIter = iter::Rev>>; + type IntoIter = vec_deque::IntoIter>; #[inline] fn into_iter(mut self) -> Self::IntoIter { - let vec = mem::take(&mut self.vec); + let deque = mem::take(&mut self.deque); mem::forget(self); - vec.into_iter().rev() + deque.into_iter() } } impl<'a, 'lua> IntoIterator for &'a MultiValue<'lua> { type Item = &'a Value<'lua>; - type IntoIter = iter::Rev>>; + type IntoIter = vec_deque::Iter<'a, Value<'lua>>; #[inline] fn into_iter(self) -> Self::IntoIter { - self.vec.iter().rev() - } -} - -impl<'lua> Index for MultiValue<'lua> { - type Output = Value<'lua>; - - #[inline] - fn index(&self, index: usize) -> &Self::Output { - if let Some(result) = self.get(index) { - result - } else { - panic!( - "index out of bounds: the len is {} but the index is {}", - self.len(), - index - ) - } - } -} - -impl<'lua> MultiValue<'lua> { - #[inline] - pub fn from_vec(mut vec: Vec>) -> MultiValue<'lua> { - vec.reverse(); - MultiValue { vec, lua: None } - } - - #[inline] - pub fn into_vec(mut self) -> Vec> { - let mut vec = mem::take(&mut self.vec); - mem::forget(self); - vec.reverse(); - vec - } - - #[inline] - pub fn get(&self, index: usize) -> Option<&Value<'lua>> { - if index < self.vec.len() { - return self.vec.get(self.vec.len() - index - 1); - } - None - } - - #[inline] - pub fn pop_front(&mut self) -> Option> { - self.vec.pop() - } - - #[inline] - pub fn push_front(&mut self, value: Value<'lua>) { - self.vec.push(value); - } - - #[inline] - pub fn clear(&mut self) { - self.vec.clear(); - } - - #[inline] - pub fn len(&self) -> usize { - self.vec.len() - } - - #[inline] - pub fn is_empty(&self) -> bool { - self.vec.is_empty() - } - - #[inline] - pub fn iter(&self) -> iter::Rev>> { - self.vec.iter().rev() - } - - #[inline] - pub(crate) fn drain_all(&mut self) -> iter::Rev>> { - self.vec.drain(..).rev() - } - - #[inline] - pub(crate) fn refill( - &mut self, - iter: impl IntoIterator>>, - ) -> Result<()> { - self.vec.clear(); - for value in iter { - self.vec.push(value?); - } - self.vec.reverse(); - Ok(()) + self.deque.iter() } } @@ -975,8 +915,8 @@ pub trait FromLuaMulti<'lua>: Sized { #[inline] unsafe fn from_stack_multi(nvals: c_int, lua: &'lua Lua) -> Result { let mut values = MultiValue::with_lua_and_capacity(lua, nvals as usize); - for idx in 1..=nvals { - values.push_front(lua.stack_value(-idx)); + for idx in 0..nvals { + values.push_back(lua.stack_value(-nvals + idx)); } if nvals > 0 { // It's safe to clear the stack as all references moved to ref thread