Skip to content

Commit ad27240

Browse files
authored
Merge pull request #453 from Mingun/overlapped-with-nested-lists
Fix #435: replay only events from time of creating SeqAccess struct
2 parents c145576 + 656081b commit ad27240

File tree

4 files changed

+1439
-279
lines changed

4 files changed

+1439
-279
lines changed

src/de/map.rs

+21-5
Original file line numberDiff line numberDiff line change
@@ -553,13 +553,13 @@ where
553553
} else {
554554
TagFilter::Exclude(self.map.fields)
555555
};
556-
let seq = visitor.visit_seq(MapValueSeqAccess {
556+
visitor.visit_seq(MapValueSeqAccess {
557+
#[cfg(feature = "overlapped-lists")]
558+
checkpoint: self.map.de.skip_checkpoint(),
559+
557560
map: self.map,
558561
filter,
559-
});
560-
#[cfg(feature = "overlapped-lists")]
561-
self.map.de.start_replay();
562-
seq
562+
})
563563
}
564564

565565
#[inline]
@@ -588,6 +588,22 @@ where
588588
/// When feature `overlapped-lists` is activated, all tags, that not pass
589589
/// this check, will be skipped.
590590
filter: TagFilter<'de>,
591+
592+
/// Checkpoint after which all skipped events should be returned. All events,
593+
/// that was skipped before creating this checkpoint, will still stay buffered
594+
/// and will not be returned
595+
#[cfg(feature = "overlapped-lists")]
596+
checkpoint: usize,
597+
}
598+
599+
#[cfg(feature = "overlapped-lists")]
600+
impl<'de, 'a, 'm, R> Drop for MapValueSeqAccess<'de, 'a, 'm, R>
601+
where
602+
R: XmlRead<'de>,
603+
{
604+
fn drop(&mut self) {
605+
self.map.de.start_replay(self.checkpoint);
606+
}
591607
}
592608

593609
impl<'de, 'a, 'm, R> SeqAccess<'de> for MapValueSeqAccess<'de, 'a, 'm, R>

src/de/mod.rs

+236-12
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,14 @@ where
483483
self.reader.next()
484484
}
485485

486+
/// Returns the mark after which all events, skipped by [`Self::skip()`] call,
487+
/// should be replayed after calling [`Self::start_replay()`].
488+
#[cfg(feature = "overlapped-lists")]
489+
#[inline]
490+
fn skip_checkpoint(&self) -> usize {
491+
self.write.len()
492+
}
493+
486494
/// Extracts XML tree of events from and stores them in the skipped events
487495
/// buffer from which they can be retrieved later. You MUST call
488496
/// [`Self::start_replay()`] after calling this to give access to the skipped
@@ -530,8 +538,8 @@ where
530538
Ok(())
531539
}
532540

533-
/// Moves all buffered events to the end of [`Self::write`] buffer and swaps
534-
/// read and write buffers.
541+
/// Moves buffered events, skipped after given `checkpoint` from [`Self::write`]
542+
/// skip buffer to [`Self::read`] buffer.
535543
///
536544
/// After calling this method, [`Self::peek()`] and [`Self::next()`] starts
537545
/// return events that was skipped previously by calling [`Self::skip()`],
@@ -541,9 +549,15 @@ where
541549
/// This method MUST be called if any number of [`Self::skip()`] was called
542550
/// after [`Self::new()`] or `start_replay()` or you'll lost events.
543551
#[cfg(feature = "overlapped-lists")]
544-
fn start_replay(&mut self) {
545-
self.write.append(&mut self.read);
546-
std::mem::swap(&mut self.read, &mut self.write);
552+
fn start_replay(&mut self, checkpoint: usize) {
553+
if checkpoint == 0 {
554+
self.write.append(&mut self.read);
555+
std::mem::swap(&mut self.read, &mut self.write);
556+
} else {
557+
let mut read = self.write.split_off(checkpoint);
558+
read.append(&mut self.read);
559+
self.read = read;
560+
}
547561
}
548562

549563
fn next_start(&mut self) -> Result<Option<BytesStart<'de>>, DeError> {
@@ -828,10 +842,7 @@ where
828842
where
829843
V: Visitor<'de>,
830844
{
831-
let seq = visitor.visit_seq(seq::TopLevelSeqAccess::new(self)?);
832-
#[cfg(feature = "overlapped-lists")]
833-
self.start_replay();
834-
seq
845+
visitor.visit_seq(seq::TopLevelSeqAccess::new(self)?)
835846
}
836847

837848
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, DeError>
@@ -1024,6 +1035,10 @@ mod tests {
10241035
assert_eq!(de.next().unwrap(), Start(BytesStart::new("root")));
10251036
assert_eq!(de.peek().unwrap(), &Start(BytesStart::new("inner")));
10261037

1038+
// Mark that start_replay() should begin replay from this point
1039+
let checkpoint = de.skip_checkpoint();
1040+
assert_eq!(checkpoint, 0);
1041+
10271042
// Should skip first <inner> tree
10281043
de.skip().unwrap();
10291044
assert_eq!(de.read, vec![]);
@@ -1060,7 +1075,7 @@ mod tests {
10601075
//
10611076
// <target/>
10621077
// </root>
1063-
de.start_replay();
1078+
de.start_replay(checkpoint);
10641079
assert_eq!(
10651080
de.read,
10661081
vec![
@@ -1074,6 +1089,10 @@ mod tests {
10741089
assert_eq!(de.write, vec![]);
10751090
assert_eq!(de.next().unwrap(), Start(BytesStart::new("inner")));
10761091

1092+
// Mark that start_replay() should begin replay from this point
1093+
let checkpoint = de.skip_checkpoint();
1094+
assert_eq!(checkpoint, 0);
1095+
10771096
// Skip `#text` node and consume <inner/> after it
10781097
de.skip().unwrap();
10791098
assert_eq!(
@@ -1105,7 +1124,7 @@ mod tests {
11051124
//
11061125
// <target/>
11071126
// </root>
1108-
de.start_replay();
1127+
de.start_replay(checkpoint);
11091128
assert_eq!(
11101129
de.read,
11111130
vec![
@@ -1119,6 +1138,7 @@ mod tests {
11191138
assert_eq!(de.next().unwrap(), Start(BytesStart::new("target")));
11201139
assert_eq!(de.next().unwrap(), End(BytesEnd::new("target")));
11211140
assert_eq!(de.next().unwrap(), End(BytesEnd::new("root")));
1141+
assert_eq!(de.next().unwrap(), Eof);
11221142
}
11231143

11241144
/// Checks that `read_to_end()` behaves correctly after `skip()`
@@ -1144,6 +1164,10 @@ mod tests {
11441164

11451165
assert_eq!(de.next().unwrap(), Start(BytesStart::new("root")));
11461166

1167+
// Mark that start_replay() should begin replay from this point
1168+
let checkpoint = de.skip_checkpoint();
1169+
assert_eq!(checkpoint, 0);
1170+
11471171
// Skip the <skip> tree
11481172
de.skip().unwrap();
11491173
assert_eq!(de.read, vec![]);
@@ -1189,7 +1213,7 @@ mod tests {
11891213
// and after that stream that messages:
11901214
//
11911215
// </root>
1192-
de.start_replay();
1216+
de.start_replay(checkpoint);
11931217
assert_eq!(
11941218
de.read,
11951219
vec![
@@ -1206,6 +1230,206 @@ mod tests {
12061230
de.read_to_end(QName(b"skip")).unwrap();
12071231

12081232
assert_eq!(de.next().unwrap(), End(BytesEnd::new("root")));
1233+
assert_eq!(de.next().unwrap(), Eof);
1234+
}
1235+
1236+
/// Checks that replay replayes only part of events
1237+
/// Test for https://github.com/tafia/quick-xml/issues/435
1238+
#[test]
1239+
fn partial_replay() {
1240+
let mut de = Deserializer::from_str(
1241+
r#"
1242+
<root>
1243+
<skipped-1/>
1244+
<skipped-2/>
1245+
<inner>
1246+
<skipped-3/>
1247+
<skipped-4/>
1248+
<target-2/>
1249+
</inner>
1250+
<target-1/>
1251+
</root>
1252+
"#,
1253+
);
1254+
1255+
// Initial conditions - both are empty
1256+
assert_eq!(de.read, vec![]);
1257+
assert_eq!(de.write, vec![]);
1258+
1259+
assert_eq!(de.next().unwrap(), Start(BytesStart::new("root")));
1260+
1261+
// start_replay() should start replay from this point
1262+
let checkpoint1 = de.skip_checkpoint();
1263+
assert_eq!(checkpoint1, 0);
1264+
1265+
// Should skip first and second <skipped-N/> elements
1266+
de.skip().unwrap(); // skipped-1
1267+
de.skip().unwrap(); // skipped-2
1268+
assert_eq!(de.read, vec![]);
1269+
assert_eq!(
1270+
de.write,
1271+
vec![
1272+
Start(BytesStart::new("skipped-1")),
1273+
End(BytesEnd::new("skipped-1")),
1274+
Start(BytesStart::new("skipped-2")),
1275+
End(BytesEnd::new("skipped-2")),
1276+
]
1277+
);
1278+
1279+
////////////////////////////////////////////////////////////////////////////////////////
1280+
1281+
assert_eq!(de.next().unwrap(), Start(BytesStart::new("inner")));
1282+
assert_eq!(de.peek().unwrap(), &Start(BytesStart::new("skipped-3")));
1283+
assert_eq!(
1284+
de.read,
1285+
vec![
1286+
// This comment here to keep the same formatting of both arrays
1287+
// otherwise rustfmt suggest one-line it
1288+
Start(BytesStart::new("skipped-3")),
1289+
]
1290+
);
1291+
assert_eq!(
1292+
de.write,
1293+
vec![
1294+
Start(BytesStart::new("skipped-1")),
1295+
End(BytesEnd::new("skipped-1")),
1296+
Start(BytesStart::new("skipped-2")),
1297+
End(BytesEnd::new("skipped-2")),
1298+
]
1299+
);
1300+
1301+
// start_replay() should start replay from this point
1302+
let checkpoint2 = de.skip_checkpoint();
1303+
assert_eq!(checkpoint2, 4);
1304+
1305+
// Should skip third and forth <skipped-N/> elements
1306+
de.skip().unwrap(); // skipped-3
1307+
de.skip().unwrap(); // skipped-4
1308+
assert_eq!(de.read, vec![]);
1309+
assert_eq!(
1310+
de.write,
1311+
vec![
1312+
// checkpoint 1
1313+
Start(BytesStart::new("skipped-1")),
1314+
End(BytesEnd::new("skipped-1")),
1315+
Start(BytesStart::new("skipped-2")),
1316+
End(BytesEnd::new("skipped-2")),
1317+
// checkpoint 2
1318+
Start(BytesStart::new("skipped-3")),
1319+
End(BytesEnd::new("skipped-3")),
1320+
Start(BytesStart::new("skipped-4")),
1321+
End(BytesEnd::new("skipped-4")),
1322+
]
1323+
);
1324+
assert_eq!(de.next().unwrap(), Start(BytesStart::new("target-2")));
1325+
assert_eq!(de.next().unwrap(), End(BytesEnd::new("target-2")));
1326+
assert_eq!(de.peek().unwrap(), &End(BytesEnd::new("inner")));
1327+
assert_eq!(
1328+
de.read,
1329+
vec![
1330+
// This comment here to keep the same formatting of both arrays
1331+
// otherwise rustfmt suggest one-line it
1332+
End(BytesEnd::new("inner")),
1333+
]
1334+
);
1335+
assert_eq!(
1336+
de.write,
1337+
vec![
1338+
// checkpoint 1
1339+
Start(BytesStart::new("skipped-1")),
1340+
End(BytesEnd::new("skipped-1")),
1341+
Start(BytesStart::new("skipped-2")),
1342+
End(BytesEnd::new("skipped-2")),
1343+
// checkpoint 2
1344+
Start(BytesStart::new("skipped-3")),
1345+
End(BytesEnd::new("skipped-3")),
1346+
Start(BytesStart::new("skipped-4")),
1347+
End(BytesEnd::new("skipped-4")),
1348+
]
1349+
);
1350+
1351+
// Start replay events from checkpoint 2
1352+
de.start_replay(checkpoint2);
1353+
assert_eq!(
1354+
de.read,
1355+
vec![
1356+
Start(BytesStart::new("skipped-3")),
1357+
End(BytesEnd::new("skipped-3")),
1358+
Start(BytesStart::new("skipped-4")),
1359+
End(BytesEnd::new("skipped-4")),
1360+
End(BytesEnd::new("inner")),
1361+
]
1362+
);
1363+
assert_eq!(
1364+
de.write,
1365+
vec![
1366+
Start(BytesStart::new("skipped-1")),
1367+
End(BytesEnd::new("skipped-1")),
1368+
Start(BytesStart::new("skipped-2")),
1369+
End(BytesEnd::new("skipped-2")),
1370+
]
1371+
);
1372+
1373+
// Replayed events
1374+
assert_eq!(de.next().unwrap(), Start(BytesStart::new("skipped-3")));
1375+
assert_eq!(de.next().unwrap(), End(BytesEnd::new("skipped-3")));
1376+
assert_eq!(de.next().unwrap(), Start(BytesStart::new("skipped-4")));
1377+
assert_eq!(de.next().unwrap(), End(BytesEnd::new("skipped-4")));
1378+
1379+
assert_eq!(de.next().unwrap(), End(BytesEnd::new("inner")));
1380+
assert_eq!(de.read, vec![]);
1381+
assert_eq!(
1382+
de.write,
1383+
vec![
1384+
Start(BytesStart::new("skipped-1")),
1385+
End(BytesEnd::new("skipped-1")),
1386+
Start(BytesStart::new("skipped-2")),
1387+
End(BytesEnd::new("skipped-2")),
1388+
]
1389+
);
1390+
1391+
////////////////////////////////////////////////////////////////////////////////////////
1392+
1393+
// New events
1394+
assert_eq!(de.next().unwrap(), Start(BytesStart::new("target-1")));
1395+
assert_eq!(de.next().unwrap(), End(BytesEnd::new("target-1")));
1396+
1397+
assert_eq!(de.read, vec![]);
1398+
assert_eq!(
1399+
de.write,
1400+
vec![
1401+
Start(BytesStart::new("skipped-1")),
1402+
End(BytesEnd::new("skipped-1")),
1403+
Start(BytesStart::new("skipped-2")),
1404+
End(BytesEnd::new("skipped-2")),
1405+
]
1406+
);
1407+
1408+
// Start replay events from checkpoint 1
1409+
de.start_replay(checkpoint1);
1410+
assert_eq!(
1411+
de.read,
1412+
vec![
1413+
Start(BytesStart::new("skipped-1")),
1414+
End(BytesEnd::new("skipped-1")),
1415+
Start(BytesStart::new("skipped-2")),
1416+
End(BytesEnd::new("skipped-2")),
1417+
]
1418+
);
1419+
assert_eq!(de.write, vec![]);
1420+
1421+
// Replayed events
1422+
assert_eq!(de.next().unwrap(), Start(BytesStart::new("skipped-1")));
1423+
assert_eq!(de.next().unwrap(), End(BytesEnd::new("skipped-1")));
1424+
assert_eq!(de.next().unwrap(), Start(BytesStart::new("skipped-2")));
1425+
assert_eq!(de.next().unwrap(), End(BytesEnd::new("skipped-2")));
1426+
1427+
assert_eq!(de.read, vec![]);
1428+
assert_eq!(de.write, vec![]);
1429+
1430+
// New events
1431+
assert_eq!(de.next().unwrap(), End(BytesEnd::new("root")));
1432+
assert_eq!(de.next().unwrap(), Eof);
12091433
}
12101434

12111435
/// Checks that limiting buffer size works correctly

0 commit comments

Comments
 (0)