Skip to content

Commit 8a9c4f0

Browse files
committed
Optimize table array traversal during serialization
1 parent 34db5f9 commit 8a9c4f0

File tree

1 file changed

+41
-32
lines changed

1 file changed

+41
-32
lines changed

src/table.rs

Lines changed: 41 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -721,7 +721,6 @@ impl<'lua> Table<'lua> {
721721
TableSequence {
722722
table: self.0,
723723
index: 1,
724-
len: None,
725724
_phantom: PhantomData,
726725
}
727726
}
@@ -733,17 +732,25 @@ impl<'lua> Table<'lua> {
733732
}
734733

735734
#[cfg(feature = "serialize")]
736-
pub(crate) fn sequence_values_by_len<V: FromLua<'lua>>(
737-
self,
738-
len: Option<usize>,
739-
) -> TableSequence<'lua, V> {
740-
let len = len.unwrap_or_else(|| self.raw_len()) as Integer;
741-
TableSequence {
742-
table: self.0,
743-
index: 1,
744-
len: Some(len),
745-
_phantom: PhantomData,
735+
pub(crate) fn for_each_value<V>(&self, mut f: impl FnMut(V) -> Result<()>) -> Result<()>
736+
where
737+
V: FromLua<'lua>,
738+
{
739+
let lua = self.0.lua;
740+
let state = lua.state();
741+
unsafe {
742+
let _sg = StackGuard::new(state);
743+
check_stack(state, 4)?;
744+
745+
lua.push_ref(&self.0);
746+
let len = ffi::lua_rawlen(state, -1);
747+
for i in 1..=len {
748+
ffi::lua_rawgeti(state, -1, i as _);
749+
f(V::from_stack(-1, lua)?)?;
750+
ffi::lua_pop(state, 1);
751+
}
746752
}
753+
Ok(())
747754
}
748755

749756
/// Sets element value at position `idx` without invoking metamethods.
@@ -1085,6 +1092,13 @@ impl<'a, 'lua> Serialize for SerializableTable<'a, 'lua> {
10851092
use crate::serde::de::{check_value_for_skip, MapPairs};
10861093
use crate::value::SerializableValue;
10871094

1095+
let convert_result = |res: Result<()>, serialize_err: Option<S::Error>| match res {
1096+
Ok(v) => Ok(v),
1097+
Err(Error::SerializeError(_)) if serialize_err.is_some() => Err(serialize_err.unwrap()),
1098+
Err(Error::SerializeError(msg)) => Err(serde::ser::Error::custom(msg)),
1099+
Err(err) => Err(serde::ser::Error::custom(err.to_string())),
1100+
};
1101+
10881102
let options = self.options;
10891103
let visited = &self.visited;
10901104
visited.borrow_mut().insert(self.table.to_pointer());
@@ -1093,15 +1107,21 @@ impl<'a, 'lua> Serialize for SerializableTable<'a, 'lua> {
10931107
let len = self.table.raw_len();
10941108
if len > 0 || self.table.is_array() {
10951109
let mut seq = serializer.serialize_seq(Some(len))?;
1096-
for value in self.table.clone().sequence_values_by_len::<Value>(None) {
1097-
let value = &value.map_err(serde::ser::Error::custom)?;
1098-
let skip = check_value_for_skip(value, self.options, &self.visited)
1099-
.map_err(serde::ser::Error::custom)?;
1110+
let mut serialize_err = None;
1111+
let res = self.table.for_each_value::<Value>(|value| {
1112+
let skip = check_value_for_skip(&value, self.options, &self.visited)
1113+
.map_err(|err| Error::SerializeError(err.to_string()))?;
11001114
if skip {
1101-
continue;
1115+
// continue iteration
1116+
return Ok(());
11021117
}
1103-
seq.serialize_element(&SerializableValue::new(value, options, Some(visited)))?;
1104-
}
1118+
seq.serialize_element(&SerializableValue::new(&value, options, Some(visited)))
1119+
.map_err(|err| {
1120+
serialize_err = Some(err);
1121+
Error::SerializeError(String::new())
1122+
})
1123+
});
1124+
convert_result(res, serialize_err)?;
11051125
return seq.end();
11061126
}
11071127

@@ -1138,18 +1158,7 @@ impl<'a, 'lua> Serialize for SerializableTable<'a, 'lua> {
11381158
process_pair(key, value)
11391159
})
11401160
};
1141-
match res {
1142-
Ok(_) => {}
1143-
Err(Error::SerializeError(_)) if serialize_err.is_some() => {
1144-
return Err(serialize_err.unwrap());
1145-
}
1146-
Err(Error::SerializeError(msg)) => {
1147-
return Err(serde::ser::Error::custom(msg));
1148-
}
1149-
Err(err) => {
1150-
return Err(serde::ser::Error::custom(err.to_string()));
1151-
}
1152-
}
1161+
convert_result(res, serialize_err)?;
11531162
map.end()
11541163
}
11551164
}
@@ -1219,9 +1228,9 @@ where
12191228
///
12201229
/// [`Table::sequence_values`]: crate::Table::sequence_values
12211230
pub struct TableSequence<'lua, V> {
1231+
// TODO: Use `&Table`
12221232
table: LuaRef<'lua>,
12231233
index: Integer,
1224-
len: Option<Integer>,
12251234
_phantom: PhantomData<V>,
12261235
}
12271236

@@ -1242,7 +1251,7 @@ where
12421251

12431252
lua.push_ref(&self.table);
12441253
match ffi::lua_rawgeti(state, -1, self.index) {
1245-
ffi::LUA_TNIL if self.index > self.len.unwrap_or(0) => None,
1254+
ffi::LUA_TNIL => None,
12461255
_ => {
12471256
self.index += 1;
12481257
Some(V::from_stack(-1, lua))

0 commit comments

Comments
 (0)