Skip to content

Commit 656081b

Browse files
committed
#435: Fix incorrect results when nesting start_replay() calls
1 parent 9ecbec4 commit 656081b

File tree

3 files changed

+72
-14
lines changed

3 files changed

+72
-14
lines changed

src/de/map.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,9 @@ where
554554
TagFilter::Exclude(self.map.fields)
555555
};
556556
visitor.visit_seq(MapValueSeqAccess {
557+
#[cfg(feature = "overlapped-lists")]
558+
checkpoint: self.map.de.skip_checkpoint(),
559+
557560
map: self.map,
558561
filter,
559562
})
@@ -585,6 +588,12 @@ where
585588
/// When feature `overlapped-lists` is activated, all tags, that not pass
586589
/// this check, will be skipped.
587590
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,
588597
}
589598

590599
#[cfg(feature = "overlapped-lists")]
@@ -593,7 +602,7 @@ where
593602
R: XmlRead<'de>,
594603
{
595604
fn drop(&mut self) {
596-
self.map.de.start_replay();
605+
self.map.de.start_replay(self.checkpoint);
597606
}
598607
}
599608

src/de/mod.rs

Lines changed: 48 additions & 11 deletions
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> {
@@ -1021,6 +1035,10 @@ mod tests {
10211035
assert_eq!(de.next().unwrap(), Start(BytesStart::new("root")));
10221036
assert_eq!(de.peek().unwrap(), &Start(BytesStart::new("inner")));
10231037

1038+
// Mark that start_replay() should begin replay from this point
1039+
let checkpoint = de.skip_checkpoint();
1040+
assert_eq!(checkpoint, 0);
1041+
10241042
// Should skip first <inner> tree
10251043
de.skip().unwrap();
10261044
assert_eq!(de.read, vec![]);
@@ -1057,7 +1075,7 @@ mod tests {
10571075
//
10581076
// <target/>
10591077
// </root>
1060-
de.start_replay();
1078+
de.start_replay(checkpoint);
10611079
assert_eq!(
10621080
de.read,
10631081
vec![
@@ -1071,6 +1089,10 @@ mod tests {
10711089
assert_eq!(de.write, vec![]);
10721090
assert_eq!(de.next().unwrap(), Start(BytesStart::new("inner")));
10731091

1092+
// Mark that start_replay() should begin replay from this point
1093+
let checkpoint = de.skip_checkpoint();
1094+
assert_eq!(checkpoint, 0);
1095+
10741096
// Skip `#text` node and consume <inner/> after it
10751097
de.skip().unwrap();
10761098
assert_eq!(
@@ -1102,7 +1124,7 @@ mod tests {
11021124
//
11031125
// <target/>
11041126
// </root>
1105-
de.start_replay();
1127+
de.start_replay(checkpoint);
11061128
assert_eq!(
11071129
de.read,
11081130
vec![
@@ -1142,6 +1164,10 @@ mod tests {
11421164

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

1167+
// Mark that start_replay() should begin replay from this point
1168+
let checkpoint = de.skip_checkpoint();
1169+
assert_eq!(checkpoint, 0);
1170+
11451171
// Skip the <skip> tree
11461172
de.skip().unwrap();
11471173
assert_eq!(de.read, vec![]);
@@ -1187,7 +1213,7 @@ mod tests {
11871213
// and after that stream that messages:
11881214
//
11891215
// </root>
1190-
de.start_replay();
1216+
de.start_replay(checkpoint);
11911217
assert_eq!(
11921218
de.read,
11931219
vec![
@@ -1232,6 +1258,10 @@ mod tests {
12321258

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

1261+
// start_replay() should start replay from this point
1262+
let checkpoint1 = de.skip_checkpoint();
1263+
assert_eq!(checkpoint1, 0);
1264+
12351265
// Should skip first and second <skipped-N/> elements
12361266
de.skip().unwrap(); // skipped-1
12371267
de.skip().unwrap(); // skipped-2
@@ -1268,18 +1298,23 @@ mod tests {
12681298
]
12691299
);
12701300

1301+
// start_replay() should start replay from this point
1302+
let checkpoint2 = de.skip_checkpoint();
1303+
assert_eq!(checkpoint2, 4);
1304+
12711305
// Should skip third and forth <skipped-N/> elements
12721306
de.skip().unwrap(); // skipped-3
12731307
de.skip().unwrap(); // skipped-4
12741308
assert_eq!(de.read, vec![]);
12751309
assert_eq!(
12761310
de.write,
12771311
vec![
1312+
// checkpoint 1
12781313
Start(BytesStart::new("skipped-1")),
12791314
End(BytesEnd::new("skipped-1")),
12801315
Start(BytesStart::new("skipped-2")),
12811316
End(BytesEnd::new("skipped-2")),
1282-
// split point
1317+
// checkpoint 2
12831318
Start(BytesStart::new("skipped-3")),
12841319
End(BytesEnd::new("skipped-3")),
12851320
Start(BytesStart::new("skipped-4")),
@@ -1313,7 +1348,8 @@ mod tests {
13131348
]
13141349
);
13151350

1316-
de.start_replay();
1351+
// Start replay events from checkpoint 2
1352+
de.start_replay(checkpoint2);
13171353
assert_eq!(
13181354
de.read,
13191355
vec![
@@ -1369,7 +1405,8 @@ mod tests {
13691405
]
13701406
);
13711407

1372-
de.start_replay();
1408+
// Start replay events from checkpoint 1
1409+
de.start_replay(checkpoint1);
13731410
assert_eq!(
13741411
de.read,
13751412
vec![

src/de/seq.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,12 @@ where
8282
/// When feature `overlapped-lists` is activated, all tags, that not pass
8383
/// this check, will be skipped.
8484
filter: TagFilter<'de>,
85+
86+
/// Checkpoint after which all skipped events should be returned. All events,
87+
/// that was skipped before creating this checkpoint, will still stay buffered
88+
/// and will not be returned
89+
#[cfg(feature = "overlapped-lists")]
90+
checkpoint: usize,
8591
}
8692

8793
impl<'a, 'de, R> TopLevelSeqAccess<'de, 'a, R>
@@ -96,7 +102,13 @@ where
96102
} else {
97103
TagFilter::Exclude(&[])
98104
};
99-
Ok(Self { de, filter })
105+
Ok(Self {
106+
#[cfg(feature = "overlapped-lists")]
107+
checkpoint: de.skip_checkpoint(),
108+
109+
de,
110+
filter,
111+
})
100112
}
101113
}
102114

@@ -106,7 +118,7 @@ where
106118
R: XmlRead<'de>,
107119
{
108120
fn drop(&mut self) {
109-
self.de.start_replay();
121+
self.de.start_replay(self.checkpoint);
110122
}
111123
}
112124

0 commit comments

Comments
 (0)