Skip to content

Commit 59c9abb

Browse files
committed
Fix serializing same table multiple times.
Fixes #408
1 parent 8f3de8a commit 59c9abb

File tree

3 files changed

+28
-7
lines changed

3 files changed

+28
-7
lines changed

src/serde/de.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -660,14 +660,14 @@ impl<'lua, 'de> de::VariantAccess<'de> for VariantDeserializer<'lua> {
660660

661661
// Adds `ptr` to the `visited` map and removes on drop
662662
// Used to track recursive tables but allow to traverse same tables multiple times
663-
struct RecursionGuard {
663+
pub(crate) struct RecursionGuard {
664664
ptr: *const c_void,
665665
visited: Rc<RefCell<FxHashSet<*const c_void>>>,
666666
}
667667

668668
impl RecursionGuard {
669669
#[inline]
670-
fn new(table: &Table, visited: &Rc<RefCell<FxHashSet<*const c_void>>>) -> Self {
670+
pub(crate) fn new(table: &Table, visited: &Rc<RefCell<FxHashSet<*const c_void>>>) -> Self {
671671
let visited = Rc::clone(visited);
672672
let ptr = table.to_pointer();
673673
visited.borrow_mut().insert(ptr);

src/table.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1089,7 +1089,7 @@ impl<'a, 'lua> Serialize for SerializableTable<'a, 'lua> {
10891089
where
10901090
S: Serializer,
10911091
{
1092-
use crate::serde::de::{check_value_for_skip, MapPairs};
1092+
use crate::serde::de::{check_value_for_skip, MapPairs, RecursionGuard};
10931093
use crate::value::SerializableValue;
10941094

10951095
let convert_result = |res: Result<()>, serialize_err: Option<S::Error>| match res {
@@ -1101,15 +1101,15 @@ impl<'a, 'lua> Serialize for SerializableTable<'a, 'lua> {
11011101

11021102
let options = self.options;
11031103
let visited = &self.visited;
1104-
visited.borrow_mut().insert(self.table.to_pointer());
1104+
let _guard = RecursionGuard::new(&self.table, visited);
11051105

11061106
// Array
11071107
let len = self.table.raw_len();
11081108
if len > 0 || self.table.is_array() {
11091109
let mut seq = serializer.serialize_seq(Some(len))?;
11101110
let mut serialize_err = None;
11111111
let res = self.table.for_each_value::<Value>(|value| {
1112-
let skip = check_value_for_skip(&value, self.options, &self.visited)
1112+
let skip = check_value_for_skip(&value, self.options, visited)
11131113
.map_err(|err| Error::SerializeError(err.to_string()))?;
11141114
if skip {
11151115
// continue iteration
@@ -1129,9 +1129,9 @@ impl<'a, 'lua> Serialize for SerializableTable<'a, 'lua> {
11291129
let mut map = serializer.serialize_map(None)?;
11301130
let mut serialize_err = None;
11311131
let mut process_pair = |key, value| {
1132-
let skip_key = check_value_for_skip(&key, self.options, &self.visited)
1132+
let skip_key = check_value_for_skip(&key, self.options, visited)
11331133
.map_err(|err| Error::SerializeError(err.to_string()))?;
1134-
let skip_value = check_value_for_skip(&value, self.options, &self.visited)
1134+
let skip_value = check_value_for_skip(&value, self.options, visited)
11351135
.map_err(|err| Error::SerializeError(err.to_string()))?;
11361136
if skip_key || skip_value {
11371137
// continue iteration

tests/serde.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,27 @@ fn test_serialize_globals() -> LuaResult<()> {
269269
Ok(())
270270
}
271271

272+
#[test]
273+
fn test_serialize_same_table_twice() -> LuaResult<()> {
274+
let lua = Lua::new();
275+
276+
let value = lua
277+
.load(
278+
r#"
279+
local foo = {}
280+
return {
281+
a = foo,
282+
b = foo,
283+
}
284+
"#,
285+
)
286+
.eval::<Value>()?;
287+
let json = serde_json::to_string(&value.to_serializable().sort_keys(true)).unwrap();
288+
assert_eq!(json, r#"{"a":{},"b":{}}"#);
289+
290+
Ok(())
291+
}
292+
272293
#[test]
273294
fn test_to_value_struct() -> LuaResult<()> {
274295
let lua = Lua::new();

0 commit comments

Comments
 (0)