From c715aec1f79bd00c8b0e1c94bea20438db9de2b2 Mon Sep 17 00:00:00 2001 From: Alex Orlenko Date: Wed, 10 Jul 2024 23:09:54 +0100 Subject: [PATCH] Do not consume `self` in `Table::pairs` and `Table::sequence_values` methods. --- src/serde/de.rs | 24 +++++++++---------- src/table.rs | 61 +++++++++++++++++++------------------------------ src/userdata.rs | 8 +++---- 3 files changed, 39 insertions(+), 54 deletions(-) diff --git a/src/serde/de.rs b/src/serde/de.rs index 9c36c87..7993d70 100644 --- a/src/serde/de.rs +++ b/src/serde/de.rs @@ -302,7 +302,7 @@ impl<'de> serde::Deserializer<'de> for Deserializer { let _guard = RecursionGuard::new(&t, &self.visited); let mut deserializer = MapDeserializer { - pairs: MapPairs::new(t, self.options.sort_keys)?, + pairs: MapPairs::new(&t, self.options.sort_keys)?, value: None, options: self.options, visited: self.visited, @@ -383,13 +383,13 @@ impl<'de> serde::Deserializer<'de> for Deserializer { } } -struct SeqDeserializer { - seq: TableSequence, +struct SeqDeserializer<'a> { + seq: TableSequence<'a, Value>, options: Options, visited: Rc>>, } -impl<'de> de::SeqAccess<'de> for SeqDeserializer { +impl<'de> de::SeqAccess<'de> for SeqDeserializer<'_> { type Error = Error; fn next_element_seed(&mut self, seed: T) -> Result> @@ -454,13 +454,13 @@ impl<'de> de::SeqAccess<'de> for VecDeserializer { } } -pub(crate) enum MapPairs { - Iter(TablePairs), +pub(crate) enum MapPairs<'a> { + Iter(TablePairs<'a, Value, Value>), Vec(Vec<(Value, Value)>), } -impl MapPairs { - pub(crate) fn new(t: Table, sort_keys: bool) -> Result { +impl<'a> MapPairs<'a> { + pub(crate) fn new(t: &'a Table, sort_keys: bool) -> Result { if sort_keys { let mut pairs = t.pairs::().collect::>>()?; pairs.sort_by(|(a, _), (b, _)| b.cmp(a)); // reverse order as we pop values from the end @@ -485,7 +485,7 @@ impl MapPairs { } } -impl Iterator for MapPairs { +impl Iterator for MapPairs<'_> { type Item = Result<(Value, Value)>; fn next(&mut self) -> Option { @@ -496,15 +496,15 @@ impl Iterator for MapPairs { } } -struct MapDeserializer { - pairs: MapPairs, +struct MapDeserializer<'a> { + pairs: MapPairs<'a>, value: Option, options: Options, visited: Rc>>, processed: usize, } -impl<'de> de::MapAccess<'de> for MapDeserializer { +impl<'de> de::MapAccess<'de> for MapDeserializer<'_> { type Error = Error; fn next_key_seed(&mut self, seed: T) -> Result> diff --git a/src/table.rs b/src/table.rs index 7f32d64..a491e1a 100644 --- a/src/table.rs +++ b/src/table.rs @@ -13,6 +13,7 @@ use { use crate::error::{Error, Result}; use crate::function::Function; use crate::private::Sealed; +use crate::state::{LuaGuard, RawLua}; use crate::types::{Integer, ValueRef}; use crate::util::{assert_stack, check_stack, StackGuard}; use crate::value::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, Nil, Value}; @@ -580,18 +581,12 @@ impl Table { self.0.to_pointer() } - /// Consume this table and return an iterator over the pairs of the table. + /// Returns an iterator over the pairs of the table. /// /// This works like the Lua `pairs` function, but does not invoke the `__pairs` metamethod. /// /// The pairs are wrapped in a [`Result`], since they are lazily converted to `K` and `V` types. /// - /// # Note - /// - /// While this method consumes the `Table` object, it can not prevent code from mutating the - /// table while the iteration is in progress. Refer to the [Lua manual] for information about - /// the consequences of such mutation. - /// /// # Examples /// /// Iterate over all globals: @@ -613,9 +608,10 @@ impl Table { /// /// [`Result`]: crate::Result /// [Lua manual]: http://www.lua.org/manual/5.4/manual.html#pdf-next - pub fn pairs(self) -> TablePairs { + pub fn pairs(&self) -> TablePairs { TablePairs { - table: self.0, + guard: self.0.lua.lock(), + table: self, key: Some(Nil), _phantom: PhantomData, } @@ -649,18 +645,12 @@ impl Table { Ok(()) } - /// Consume this table and return an iterator over all values in the sequence part of the table. + /// Returns an iterator over all values in the sequence part of the table. /// /// The iterator will yield all values `t[1]`, `t[2]` and so on, until a `nil` value is /// encountered. This mirrors the behavior of Lua's `ipairs` function but does not invoke /// any metamethods. /// - /// # Note - /// - /// While this method consumes the `Table` object, it can not prevent code from mutating the - /// table while the iteration is in progress. Refer to the [Lua manual] for information about - /// the consequences of such mutation. - /// /// # Examples /// /// ``` @@ -687,20 +677,15 @@ impl Table { /// [`pairs`]: #method.pairs /// [`Result`]: crate::Result /// [Lua manual]: http://www.lua.org/manual/5.4/manual.html#pdf-next - pub fn sequence_values(self) -> TableSequence { + pub fn sequence_values(&self) -> TableSequence { TableSequence { - table: self.0, + guard: self.0.lua.lock(), + table: self, index: 1, _phantom: PhantomData, } } - #[doc(hidden)] - #[deprecated(since = "0.9.0", note = "use `sequence_values` instead")] - pub fn raw_sequence_values(self) -> TableSequence { - self.sequence_values() - } - #[cfg(feature = "serialize")] pub(crate) fn for_each_value(&self, mut f: impl FnMut(V) -> Result<()>) -> Result<()> where @@ -782,9 +767,8 @@ impl Table { ) -> fmt::Result { visited.insert(self.to_pointer()); - let t = self.clone(); // Collect key/value pairs into a vector so we can sort them - let mut pairs = t.pairs::().flatten().collect::>(); + let mut pairs = self.pairs::().flatten().collect::>(); // Sort keys pairs.sort_by(|(a, _), (b, _)| a.cmp(b)); if pairs.is_empty() { @@ -1111,7 +1095,7 @@ impl<'a> Serialize for SerializableTable<'a> { // Fast track self.table.for_each(process_pair) } else { - MapPairs::new(self.table.clone(), self.options.sort_keys) + MapPairs::new(self.table, self.options.sort_keys) .map_err(serde::ser::Error::custom)? .try_for_each(|kv| { let (key, value) = kv?; @@ -1128,13 +1112,14 @@ impl<'a> Serialize for SerializableTable<'a> { /// This struct is created by the [`Table::pairs`] method. /// /// [`Table::pairs`]: crate::Table::pairs -pub struct TablePairs { - table: ValueRef, +pub struct TablePairs<'a, K, V> { + guard: LuaGuard, + table: &'a Table, key: Option, _phantom: PhantomData<(K, V)>, } -impl Iterator for TablePairs +impl<'a, K, V> Iterator for TablePairs<'a, K, V> where K: FromLua, V: FromLua, @@ -1143,14 +1128,14 @@ where fn next(&mut self) -> Option { if let Some(prev_key) = self.key.take() { - let lua = self.table.lua.lock(); + let lua: &RawLua = &self.guard; let state = lua.state(); let res = (|| unsafe { let _sg = StackGuard::new(state); check_stack(state, 5)?; - lua.push_ref(&self.table); + lua.push_ref(&self.table.0); lua.push_value(&prev_key)?; // It must be safe to call `lua_next` unprotected as deleting a key from a table is @@ -1187,21 +1172,21 @@ where /// This struct is created by the [`Table::sequence_values`] method. /// /// [`Table::sequence_values`]: crate::Table::sequence_values -pub struct TableSequence { - // TODO: Use `&Table` - table: ValueRef, +pub struct TableSequence<'a, V> { + guard: LuaGuard, + table: &'a Table, index: Integer, _phantom: PhantomData, } -impl Iterator for TableSequence +impl<'a, V> Iterator for TableSequence<'a, V> where V: FromLua, { type Item = Result; fn next(&mut self) -> Option { - let lua = self.table.lua.lock(); + let lua: &RawLua = &self.guard; let state = lua.state(); unsafe { let _sg = StackGuard::new(state); @@ -1209,7 +1194,7 @@ where return Some(Err(err)); } - lua.push_ref(&self.table); + lua.push_ref(&self.table.0); match ffi::lua_rawgeti(state, -1, self.index) { ffi::LUA_TNIL => None, _ => { diff --git a/src/userdata.rs b/src/userdata.rs index fdb3f49..54f5e44 100644 --- a/src/userdata.rs +++ b/src/userdata.rs @@ -1089,12 +1089,12 @@ impl UserDataMetatable { self.0.contains_key(MetaMethod::validate(key.as_ref())?) } - /// Consumes this metatable and returns an iterator over the pairs of the metatable. + /// Returns an iterator over the pairs of the metatable. /// /// The pairs are wrapped in a [`Result`], since they are lazily converted to `V` type. /// /// [`Result`]: crate::Result - pub fn pairs(self) -> UserDataMetatablePairs { + pub fn pairs(&self) -> UserDataMetatablePairs { UserDataMetatablePairs(self.0.pairs()) } } @@ -1107,9 +1107,9 @@ impl UserDataMetatable { /// /// [`UserData`]: crate::UserData /// [`UserDataMetatable::pairs`]: crate::UserDataMetatable::method.pairs -pub struct UserDataMetatablePairs(TablePairs); +pub struct UserDataMetatablePairs<'a, V>(TablePairs<'a, StdString, V>); -impl Iterator for UserDataMetatablePairs +impl<'a, V> Iterator for UserDataMetatablePairs<'a, V> where V: FromLua, {