Skip to content

Commit e27feab

Browse files
committed
Remove StartText
StartText would be out of place once all events are expected to contain UTF-8. Additionally the decoder implementation strips BOM bytes out of the bytestream so there's no good way to access them.
1 parent 11e483a commit e27feab

File tree

10 files changed

+10
-282
lines changed

10 files changed

+10
-282
lines changed

Changelog.md

-11
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@
2020
- [#180]: Make `Decoder` struct public. You already had access to it via the
2121
`Reader::decoder()` method, but could not name it in the code. Now the preferred
2222
way to access decoding functionality is via this struct
23-
- [#191]: New event variant `StartText` emitted for bytes before the XML declaration
24-
or a start comment or a tag. For streams with BOM this event will contain a BOM
2523
- [#395]: Add support for XML Schema `xs:list`
2624
- [#324]: `Reader::from_str` / `Deserializer::from_str` / `from_str` now ignore
2725
the XML declared encoding and always use UTF-8
@@ -100,15 +98,6 @@
10098
`Decoder::decode()` and `Decoder::decode_with_bom_removal()`.
10199
Use `reader.decoder().decode_*(...)` instead of `reader.decode_*(...)` for now.
102100
`Reader::encoding()` is replaced by `Decoder::encoding()` as well
103-
- [#191]: Remove poorly designed `BytesText::unescape_and_decode_without_bom()` and
104-
`BytesText::unescape_and_decode_without_bom_with_custom_entities()`. Although these methods worked
105-
as expected, this was only due to good luck. They was replaced by the
106-
`BytesStartText::decode_with_bom_removal()`:
107-
- conceptually, you should decode BOM only for the first `Text` event from the
108-
reader (since now `StartText` event is emitted instead for this)
109-
- text before the first tag is not an XML content at all, so it is meaningless
110-
to try to unescape something in it
111-
112101
- [#180]: Eliminated the differences in the decoding API when feature `encoding` enabled and when it is
113102
disabled. Signatures of functions are now the same regardless of whether or not the feature is
114103
enabled, and an error will be returned instead of performing replacements for invalid characters

benches/microbenches.rs

-14
Original file line numberDiff line numberDiff line change
@@ -118,20 +118,6 @@ fn read_resolved_event_into(c: &mut Criterion) {
118118
/// Benchmarks, how fast individual event parsed
119119
fn one_event(c: &mut Criterion) {
120120
let mut group = c.benchmark_group("One event");
121-
group.bench_function("StartText", |b| {
122-
let src = "Hello world!".repeat(512 / 12);
123-
b.iter(|| {
124-
let mut r = Reader::from_str(&src);
125-
let mut nbtxt = criterion::black_box(0);
126-
r.check_end_names(false).check_comments(false);
127-
match r.read_event() {
128-
Ok(Event::StartText(e)) => nbtxt += e.len(),
129-
something_else => panic!("Did not expect {:?}", something_else),
130-
};
131-
132-
assert_eq!(nbtxt, 504);
133-
})
134-
});
135121

136122
group.bench_function("Start", |b| {
137123
let src = format!(r#"<hello target="{}">"#, "world".repeat(512 / 5));

src/de/mod.rs

-8
Original file line numberDiff line numberDiff line change
@@ -929,10 +929,6 @@ impl<'i, R: BufRead> XmlRead<'i> for IoReader<R> {
929929
let event = loop {
930930
let e = self.reader.read_event_into(&mut self.buf)?;
931931
match e {
932-
//TODO: Probably not the best idea treat StartText as usual text
933-
// Usually this event will represent a BOM
934-
// Changing this requires review of the serde-de::top_level::one_element test
935-
Event::StartText(e) => break Ok(DeEvent::Text(e.into_owned().into())),
936932
Event::Start(e) => break Ok(DeEvent::Start(e.into_owned())),
937933
Event::End(e) => break Ok(DeEvent::End(e.into_owned())),
938934
Event::Text(e) => break Ok(DeEvent::Text(e.into_owned())),
@@ -974,10 +970,6 @@ impl<'de> XmlRead<'de> for SliceReader<'de> {
974970
loop {
975971
let e = self.reader.read_event()?;
976972
match e {
977-
//TODO: Probably not the best idea treat StartText as usual text
978-
// Usually this event will represent a BOM
979-
// Changing this requires review of the serde-de::top_level::one_element test
980-
Event::StartText(e) => break Ok(DeEvent::Text(e.into())),
981973
Event::Start(e) => break Ok(DeEvent::Start(e)),
982974
Event::End(e) => break Ok(DeEvent::End(e)),
983975
Event::Text(e) => break Ok(DeEvent::Text(e)),

src/events/mod.rs

-122
Original file line numberDiff line numberDiff line change
@@ -50,69 +50,6 @@ use crate::name::{LocalName, QName};
5050
use crate::utils::write_cow_string;
5151
use attributes::{Attribute, Attributes};
5252

53-
/// Text that appeared before an XML declaration, a start element or a comment.
54-
///
55-
/// In well-formed XML it could contain a Byte-Order-Mark (BOM). If this event
56-
/// contains something else except BOM, the XML should be considered ill-formed.
57-
///
58-
/// This is a reader-only event. If you need to write a text before the first tag,
59-
/// use the [`BytesText`] event.
60-
#[derive(Debug, Clone, Eq, PartialEq)]
61-
pub struct BytesStartText<'a> {
62-
content: BytesText<'a>,
63-
}
64-
65-
impl<'a> BytesStartText<'a> {
66-
/// Converts the event into an owned event.
67-
pub fn into_owned(self) -> BytesStartText<'static> {
68-
BytesStartText {
69-
content: self.content.into_owned(),
70-
}
71-
}
72-
73-
/// Extracts the inner `Cow` from the `BytesStartText` event container.
74-
#[inline]
75-
pub fn into_inner(self) -> Cow<'a, [u8]> {
76-
self.content.into_inner()
77-
}
78-
79-
/// Converts the event into a borrowed event.
80-
#[inline]
81-
pub fn borrow(&self) -> BytesStartText {
82-
BytesStartText {
83-
content: self.content.borrow(),
84-
}
85-
}
86-
87-
/// Decodes bytes of event, stripping byte order mark (BOM) if it is presented
88-
/// in the event.
89-
///
90-
/// This method does not unescapes content, because no escape sequences can
91-
/// appeared in the BOM or in the text before the first tag.
92-
pub fn decode_with_bom_removal(&self) -> Result<String> {
93-
//TODO: Fix lifetime issue - it should be possible to borrow string
94-
let decoded = self.content.decoder.decode_with_bom_removal(&*self)?;
95-
96-
Ok(decoded.to_string())
97-
}
98-
}
99-
100-
impl<'a> Deref for BytesStartText<'a> {
101-
type Target = BytesText<'a>;
102-
103-
fn deref(&self) -> &Self::Target {
104-
&self.content
105-
}
106-
}
107-
108-
impl<'a> From<BytesText<'a>> for BytesStartText<'a> {
109-
fn from(content: BytesText<'a>) -> Self {
110-
Self { content }
111-
}
112-
}
113-
114-
////////////////////////////////////////////////////////////////////////////////////////////////////
115-
11653
/// Opening tag data (`Event::Start`), with optional attributes.
11754
///
11855
/// `<name attr="value">`.
@@ -797,12 +734,6 @@ impl<'a> Deref for BytesText<'a> {
797734
}
798735
}
799736

800-
impl<'a> From<BytesStartText<'a>> for BytesText<'a> {
801-
fn from(content: BytesStartText<'a>) -> Self {
802-
content.content
803-
}
804-
}
805-
806737
////////////////////////////////////////////////////////////////////////////////////////////////////
807738

808739
/// CDATA content contains unescaped data from the reader. If you want to write them as a text,
@@ -941,56 +872,6 @@ impl<'a> Deref for BytesCData<'a> {
941872
/// [`Reader::read_event_into`]: crate::reader::Reader::read_event_into
942873
#[derive(Clone, Debug, Eq, PartialEq)]
943874
pub enum Event<'a> {
944-
/// Text that appeared before the first opening tag or an [XML declaration].
945-
/// [According to the XML standard][std], no text allowed before the XML
946-
/// declaration. However, if there is a BOM in the stream, some data may be
947-
/// present.
948-
///
949-
/// When this event is generated, it is the very first event emitted by the
950-
/// [`Reader`], and there can be the only one such event.
951-
///
952-
/// The [`Writer`] writes content of this event "as is" without encoding or
953-
/// escaping. If you write it, it should be written first and only one time
954-
/// (but writer does not enforce that).
955-
///
956-
/// # Examples
957-
///
958-
/// ```
959-
/// # use pretty_assertions::assert_eq;
960-
/// use std::borrow::Cow;
961-
/// use quick_xml::events::Event;
962-
/// use quick_xml::reader::Reader;
963-
///
964-
/// // XML in UTF-8 with BOM
965-
/// let xml = b"\xEF\xBB\xBF<?xml version='1.0'?>".as_ref();
966-
/// let mut reader = Reader::from_reader(xml);
967-
/// let mut buf = Vec::new();
968-
/// let mut events_processed = 0;
969-
/// loop {
970-
/// match reader.read_event_into(&mut buf) {
971-
/// Ok(Event::StartText(e)) => {
972-
/// assert_eq!(events_processed, 0);
973-
/// // Content contains BOM
974-
/// assert_eq!(e.into_inner(), Cow::Borrowed(b"\xEF\xBB\xBF"));
975-
/// }
976-
/// Ok(Event::Decl(_)) => {
977-
/// assert_eq!(events_processed, 1);
978-
/// }
979-
/// Ok(Event::Eof) => {
980-
/// assert_eq!(events_processed, 2);
981-
/// break;
982-
/// }
983-
/// e => panic!("Unexpected event {:?}", e),
984-
/// }
985-
/// events_processed += 1;
986-
/// }
987-
/// ```
988-
///
989-
/// [XML declaration]: Event::Decl
990-
/// [std]: https://www.w3.org/TR/xml11/#NT-document
991-
/// [`Reader`]: crate::reader::Reader
992-
/// [`Writer`]: crate::writer::Writer
993-
StartText(BytesStartText<'a>),
994875
/// Start tag (with attributes) `<tag attr="value">`.
995876
Start(BytesStart<'a>),
996877
/// End tag `</tag>`.
@@ -1018,7 +899,6 @@ impl<'a> Event<'a> {
1018899
/// buffer used when reading but incurring a new, separate allocation.
1019900
pub fn into_owned(self) -> Event<'static> {
1020901
match self {
1021-
Event::StartText(e) => Event::StartText(e.into_owned()),
1022902
Event::Start(e) => Event::Start(e.into_owned()),
1023903
Event::End(e) => Event::End(e.into_owned()),
1024904
Event::Empty(e) => Event::Empty(e.into_owned()),
@@ -1036,7 +916,6 @@ impl<'a> Event<'a> {
1036916
#[inline]
1037917
pub fn borrow(&self) -> Event {
1038918
match self {
1039-
Event::StartText(e) => Event::StartText(e.borrow()),
1040919
Event::Start(e) => Event::Start(e.borrow()),
1041920
Event::End(e) => Event::End(e.borrow()),
1042921
Event::Empty(e) => Event::Empty(e.borrow()),
@@ -1056,7 +935,6 @@ impl<'a> Deref for Event<'a> {
1056935

1057936
fn deref(&self) -> &[u8] {
1058937
match *self {
1059-
Event::StartText(ref e) => &*e,
1060938
Event::Start(ref e) | Event::Empty(ref e) => &*e,
1061939
Event::End(ref e) => &*e,
1062940
Event::Text(ref e) => &*e,

src/reader/mod.rs

+6-18
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ pub type Span = Range<usize>;
286286
/// subgraph _
287287
/// direction LR
288288
///
289-
/// Init -- "(no event)"\nStartText --> OpenedTag
289+
/// Init -- "(no event)"\n --> OpenedTag
290290
/// OpenedTag -- Decl, DocType, PI\nComment, CData\nStart, Empty, End --> ClosedTag
291291
/// ClosedTag -- "#lt;false#gt;\n(no event)"\nText --> OpenedTag
292292
/// end
@@ -297,13 +297,13 @@ pub type Span = Range<usize>;
297297
#[derive(Clone)]
298298
enum ParseState {
299299
/// Initial state in which reader stay after creation. Transition from that
300-
/// state could produce a `StartText`, `Decl`, `Comment` or `Start` event.
301-
/// The next state is always `OpenedTag`. The reader will never return to this
302-
/// state. The event emitted during transition to `OpenedTag` is a `StartEvent`
303-
/// if the first symbol not `<`, otherwise no event are emitted.
300+
/// state could produce a `Text`, `Decl`, `Comment` or `Start` event. The next
301+
/// state is always `OpenedTag`. The reader will never return to this state. The
302+
/// event emitted during transition to `OpenedTag` is a `StartEvent` if the
303+
/// first symbol not `<`, otherwise no event are emitted.
304304
Init,
305305
/// State after seeing the `<` symbol. Depending on the next symbol all other
306-
/// events (except `StartText`) could be generated.
306+
/// events could be generated.
307307
///
308308
/// After generating one event the reader moves to the `ClosedTag` state.
309309
OpenedTag,
@@ -553,8 +553,6 @@ impl<R> Reader<R> {
553553
}
554554

555555
/// Read until '<' is found and moves reader to an `OpenedTag` state.
556-
///
557-
/// Return a `StartText` event if `first` is `true` and a `Text` event otherwise
558556
fn read_until_open<'i, B>(&mut self, buf: B, first: bool) -> Result<Event<'i>>
559557
where
560558
R: XmlSource<'i, B>,
@@ -1573,16 +1571,6 @@ mod test {
15731571
use crate::reader::Reader;
15741572
use pretty_assertions::assert_eq;
15751573

1576-
#[$test]
1577-
$($async)? fn start_text() {
1578-
let mut reader = Reader::from_str("bom");
1579-
1580-
assert_eq!(
1581-
reader.$read_event($buf) $(.$await)? .unwrap(),
1582-
Event::StartText(BytesText::from_escaped("bom").into())
1583-
);
1584-
}
1585-
15861574
#[$test]
15871575
$($async)? fn declaration() {
15881576
let mut reader = Reader::from_str("<?xml ?>");

src/reader/parser.rs

+2-13
Original file line numberDiff line numberDiff line change
@@ -61,17 +61,11 @@ pub(super) struct Parser {
6161
}
6262

6363
impl Parser {
64-
/// Trims whitespaces from `bytes`, if required, and returns a [`StartText`]
65-
/// or a [`Text`] event. When [`StartText`] is returned, the method can change
66-
/// the encoding of the reader, detecting it from the beginning of the stream.
64+
/// Trims whitespaces from `bytes`, if required, and returns a [`Text`] event.
6765
///
6866
/// # Parameters
6967
/// - `bytes`: data from the start of stream to the first `<` or from `>` to `<`
70-
/// - `first`: if `true`, then this is the first call of that function,
71-
/// i. e. data from the start of stream and [`StartText`] will be returned,
72-
/// otherwise [`Text`] will be returned
7368
///
74-
/// [`StartText`]: Event::StartText
7569
/// [`Text`]: Event::Text
7670
pub fn read_text<'b>(&mut self, bytes: &'b [u8], first: bool) -> Result<Event<'b>> {
7771
#[cfg(feature = "encoding")]
@@ -91,12 +85,7 @@ impl Parser {
9185
} else {
9286
bytes
9387
};
94-
95-
Ok(if first {
96-
Event::StartText(BytesText::wrap(content, self.decoder()).into())
97-
} else {
98-
Event::Text(BytesText::wrap(content, self.decoder()))
99-
})
88+
Ok(Event::Text(BytesText::wrap(content, self.decoder())))
10089
}
10190

10291
/// reads `BytesElement` starting with a `!`,

src/writer.rs

-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ impl<W: Write> Writer<W> {
9090
pub fn write_event<'a, E: AsRef<Event<'a>>>(&mut self, event: E) -> Result<()> {
9191
let mut next_should_line_break = true;
9292
let result = match *event.as_ref() {
93-
Event::StartText(ref e) => self.write(&e),
9493
Event::Start(ref e) => {
9594
let result = self.write_wrapped(b"<", e, b">");
9695
if let Some(i) = self.indent.as_mut() {

tests/test.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ fn test_issue94() {
111111
fn test_no_trim() {
112112
let mut reader = Reader::from_str(" <tag> text </tag> ");
113113

114-
assert!(matches!(reader.read_event().unwrap(), StartText(_)));
114+
assert!(matches!(reader.read_event().unwrap(), Text(_)));
115115
assert!(matches!(reader.read_event().unwrap(), Start(_)));
116116
assert!(matches!(reader.read_event().unwrap(), Text(_)));
117117
assert!(matches!(reader.read_event().unwrap(), End(_)));
@@ -123,7 +123,7 @@ fn test_trim_end() {
123123
let mut reader = Reader::from_str(" <tag> text </tag> ");
124124
reader.trim_text_end(true);
125125

126-
assert!(matches!(reader.read_event().unwrap(), StartText(_)));
126+
assert!(matches!(reader.read_event().unwrap(), Text(_)));
127127
assert!(matches!(reader.read_event().unwrap(), Start(_)));
128128
assert!(matches!(reader.read_event().unwrap(), Text(_)));
129129
assert!(matches!(reader.read_event().unwrap(), End(_)));

0 commit comments

Comments
 (0)