Skip to content

Commit 7ab6add

Browse files
committed
Untie CDataIterator from the BytesCData to reuse it later without BytesCData
1 parent 0fd5959 commit 7ab6add

File tree

2 files changed

+54
-31
lines changed

2 files changed

+54
-31
lines changed

src/events/mod.rs

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ use crate::escape::{
5353
partial_escape, EscapeError,
5454
};
5555
use crate::name::{LocalName, QName};
56-
use crate::utils::{name_len, trim_xml_end, trim_xml_start, write_cow_string, Bytes};
56+
use crate::utils::{self, name_len, trim_xml_end, trim_xml_start, write_cow_string};
5757
use attributes::{AttrError, Attribute, Attributes};
5858

5959
/// Opening tag data (`Event::Start`), with optional attributes: `<name attr="value">`.
@@ -783,8 +783,7 @@ impl<'a> BytesCData<'a> {
783783
#[inline]
784784
pub fn escaped(content: &'a str) -> CDataIterator<'a> {
785785
CDataIterator {
786-
unprocessed: content.as_bytes(),
787-
finished: false,
786+
inner: utils::CDataIterator::new(content),
788787
}
789788
}
790789

@@ -984,41 +983,18 @@ impl<'a> arbitrary::Arbitrary<'a> for BytesCData<'a> {
984983
/// Iterator over `CDATA` sections in a string.
985984
///
986985
/// This iterator is created by the [`BytesCData::escaped`] method.
987-
#[derive(Clone)]
986+
#[derive(Debug, Clone)]
988987
pub struct CDataIterator<'a> {
989-
/// The unprocessed data which should be emitted as `BytesCData` events.
990-
/// At each iteration, the processed data is cut from this slice.
991-
unprocessed: &'a [u8],
992-
finished: bool,
993-
}
994-
995-
impl<'a> Debug for CDataIterator<'a> {
996-
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
997-
f.debug_struct("CDataIterator")
998-
.field("unprocessed", &Bytes(self.unprocessed))
999-
.field("finished", &self.finished)
1000-
.finish()
1001-
}
988+
inner: utils::CDataIterator<'a>,
1002989
}
1003990

1004991
impl<'a> Iterator for CDataIterator<'a> {
1005992
type Item = BytesCData<'a>;
1006993

1007994
fn next(&mut self) -> Option<BytesCData<'a>> {
1008-
if self.finished {
1009-
return None;
1010-
}
1011-
1012-
for gt in memchr::memchr_iter(b'>', self.unprocessed) {
1013-
if self.unprocessed[..gt].ends_with(b"]]") {
1014-
let (slice, rest) = self.unprocessed.split_at(gt);
1015-
self.unprocessed = rest;
1016-
return Some(BytesCData::wrap(slice, Decoder::utf8()));
1017-
}
1018-
}
1019-
1020-
self.finished = true;
1021-
Some(BytesCData::wrap(self.unprocessed, Decoder::utf8()))
995+
self.inner
996+
.next()
997+
.map(|slice| BytesCData::wrap(slice.as_bytes(), Decoder::utf8()))
1022998
}
1023999
}
10241000

src/utils.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::borrow::{Borrow, Cow};
22
use std::fmt::{self, Debug, Formatter};
33
use std::io;
4+
use std::iter::FusedIterator;
45
use std::ops::Deref;
56

67
#[cfg(feature = "async-tokio")]
@@ -376,6 +377,52 @@ pub const fn trim_xml_end(mut bytes: &[u8]) -> &[u8] {
376377

377378
////////////////////////////////////////////////////////////////////////////////////////////////////
378379

380+
/// Splits string into pieces which can be part of a single `CDATA` section.
381+
///
382+
/// Because CDATA cannot contain the `]]>` sequence, split the string between
383+
/// `]]` and `>`.
384+
#[derive(Debug, Clone)]
385+
pub(crate) struct CDataIterator<'a> {
386+
/// The unprocessed data which should be emitted as `BytesCData` events.
387+
/// At each iteration, the processed data is cut from this slice.
388+
unprocessed: &'a str,
389+
finished: bool,
390+
}
391+
392+
impl<'a> CDataIterator<'a> {
393+
pub fn new(value: &'a str) -> Self {
394+
Self {
395+
unprocessed: value,
396+
finished: false,
397+
}
398+
}
399+
}
400+
401+
impl<'a> Iterator for CDataIterator<'a> {
402+
type Item = &'a str;
403+
404+
fn next(&mut self) -> Option<&'a str> {
405+
if self.finished {
406+
return None;
407+
}
408+
409+
for gt in memchr::memchr_iter(b'>', self.unprocessed.as_bytes()) {
410+
let (slice, rest) = self.unprocessed.split_at(gt);
411+
if slice.ends_with("]]") {
412+
self.unprocessed = rest;
413+
return Some(slice);
414+
}
415+
}
416+
417+
self.finished = true;
418+
Some(self.unprocessed)
419+
}
420+
}
421+
422+
impl FusedIterator for CDataIterator<'_> {}
423+
424+
////////////////////////////////////////////////////////////////////////////////////////////////////
425+
379426
#[cfg(test)]
380427
mod tests {
381428
use super::*;

0 commit comments

Comments
 (0)