Skip to content

Commit dd64262

Browse files
committed
Update event and attribute related structs to str
1 parent 6c11b82 commit dd64262

17 files changed

+432
-590
lines changed

Changelog.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,6 @@
419419
- [#416]: `BytesStart::to_borrowed` renamed to `BytesStart::borrow`, the same method
420420
added to all events
421421

422-
- [#421]: `decode_and_unescape*` methods now does one less allocation if unescaping is not required
423422
- [#421]: Removed ability to deserialize byte arrays from serde deserializer.
424423
XML is not able to store binary data directly, you should always use some encoding
425424
scheme, for example, HEX or Base64

benches/macrobenches.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ fn parse_document_from_str(doc: &str) -> XmlResult<()> {
5050
match criterion::black_box(r.read_event()?) {
5151
Event::Start(e) | Event::Empty(e) => {
5252
for attr in e.attributes() {
53-
criterion::black_box(attr?.decode_and_unescape_value(&r)?);
53+
criterion::black_box(attr?.unescape_value()?);
5454
}
5555
}
5656
Event::Text(e) => {
@@ -75,7 +75,7 @@ fn parse_document_from_bytes(doc: &[u8]) -> XmlResult<()> {
7575
match criterion::black_box(r.read_event_into(&mut buf)?) {
7676
Event::Start(e) | Event::Empty(e) => {
7777
for attr in e.attributes() {
78-
criterion::black_box(attr?.decode_and_unescape_value(&r)?);
78+
criterion::black_box(attr?.unescape_value()?);
7979
}
8080
}
8181
Event::Text(e) => {
@@ -101,7 +101,7 @@ fn parse_document_from_str_with_namespaces(doc: &str) -> XmlResult<()> {
101101
(resolved_ns, Event::Start(e) | Event::Empty(e)) => {
102102
criterion::black_box(resolved_ns);
103103
for attr in e.attributes() {
104-
criterion::black_box(attr?.decode_and_unescape_value(&r)?);
104+
criterion::black_box(attr?.unescape_value()?);
105105
}
106106
}
107107
(resolved_ns, Event::Text(e)) => {
@@ -129,7 +129,7 @@ fn parse_document_from_bytes_with_namespaces(doc: &[u8]) -> XmlResult<()> {
129129
(resolved_ns, Event::Start(e) | Event::Empty(e)) => {
130130
criterion::black_box(resolved_ns);
131131
for attr in e.attributes() {
132-
criterion::black_box(attr?.decode_and_unescape_value(&r)?);
132+
criterion::black_box(attr?.unescape_value()?);
133133
}
134134
}
135135
(resolved_ns, Event::Text(e)) => {

examples/custom_entities.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,20 +33,20 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
3333
loop {
3434
match reader.read_event() {
3535
Ok(Event::DocType(ref e)) => {
36-
for cap in entity_re.captures_iter(e) {
36+
for cap in entity_re.captures_iter(e.as_bytes()) {
3737
custom_entities.insert(
3838
String::from_utf8(cap[1].to_owned())?,
3939
String::from_utf8(cap[2].to_owned())?,
4040
);
4141
}
4242
}
4343
Ok(Event::Start(ref e)) => {
44-
if let b"test" = e.name().as_ref() {
44+
if let "test" = e.name().as_ref() {
4545
let attributes = e
4646
.attributes()
4747
.map(|a| {
4848
a.unwrap()
49-
.decode_and_unescape_value_with(&reader, |ent| {
49+
.unescape_value_with(|ent| {
5050
custom_entities.get(ent).map(|s| s.as_str())
5151
})
5252
.unwrap()

examples/nested_readers.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ fn main() -> Result<(), quick_xml::Error> {
2222
loop {
2323
match reader.read_event_into(&mut buf)? {
2424
Event::Start(element) => {
25-
if let b"w:tbl" = element.name().as_ref() {
25+
if let "w:tbl" = element.name().as_ref() {
2626
count += 1;
2727
let mut stats = TableStat {
2828
index: count,

examples/read_nodes.rs

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ use quick_xml::name::QName;
77
use quick_xml::reader::Reader;
88
use std::borrow::Cow;
99
use std::collections::HashMap;
10-
use std::convert::Infallible;
1110
use std::str;
1211

1312
const XML: &str = r#"
@@ -47,8 +46,8 @@ impl Translation {
4746
for attr_result in element.attributes() {
4847
let a = attr_result?;
4948
match a.key.as_ref() {
50-
b"Language" => lang = a.decode_and_unescape_value(reader)?,
51-
b"Tag" => tag = a.decode_and_unescape_value(reader)?,
49+
"Language" => lang = Cow::Owned(a.unescape_value()?.to_string()),
50+
"Tag" => tag = Cow::Owned(a.unescape_value()?.to_string()),
5251
_ => (),
5352
}
5453
}
@@ -57,7 +56,7 @@ impl Translation {
5756

5857
if let Event::Start(ref e) = event {
5958
let name = e.name();
60-
if name == QName(b"Text") {
59+
if name == QName("Text") {
6160
// note: `read_text` does not support content as CDATA
6261
let text_content = reader.read_text(e.name())?;
6362
Ok(Translation {
@@ -67,8 +66,7 @@ impl Translation {
6766
})
6867
} else {
6968
dbg!("Expected Event::Start for Text, got: {:?}", &event);
70-
let name_string = reader.decoder().decode(name.as_ref())?;
71-
Err(quick_xml::Error::UnexpectedToken(name_string.into()))
69+
Err(quick_xml::Error::UnexpectedToken(name.as_ref().to_owned()))
7270
}
7371
} else {
7472
let event_string = format!("{:?}", event);
@@ -99,24 +97,16 @@ fn main() -> Result<(), quick_xml::Error> {
9997

10098
match event {
10199
Event::Start(element) => match element.name().as_ref() {
102-
b"DefaultSettings" => {
100+
"DefaultSettings" => {
103101
// Note: real app would handle errors with good defaults or halt program with nice message
104102
// This illustrates decoding an attribute's key and value with error handling
105103
settings = element
106104
.attributes()
107105
.map(|attr_result| {
108106
match attr_result {
109107
Ok(a) => {
110-
let key = reader.decoder().decode(a.key.local_name().as_ref())
111-
.or_else(|err| {
112-
dbg!("unable to read key in DefaultSettings attribute {:?}, utf8 error {:?}", &a, err);
113-
Ok::<Cow<'_, str>, Infallible>(std::borrow::Cow::from(""))
114-
})
115-
.unwrap().to_string();
116-
let value = a.decode_and_unescape_value(&reader).or_else(|err| {
117-
dbg!("unable to read key in DefaultSettings attribute {:?}, utf8 error {:?}", &a, err);
118-
Ok::<Cow<'_, str>, Infallible>(std::borrow::Cow::from(""))
119-
}).unwrap().to_string();
108+
let key = a.key.local_name().as_ref().to_string();
109+
let value = a.unescape_value().expect("failure to unescape").to_string();
120110
(key, value)
121111
},
122112
Err(err) => {
@@ -130,7 +120,7 @@ fn main() -> Result<(), quick_xml::Error> {
130120
assert_eq!(settings["Greeting"], "HELLO");
131121
reader.read_to_end(element.name())?;
132122
}
133-
b"Translation" => {
123+
"Translation" => {
134124
translations.push(Translation::new_from_element(&mut reader, element)?);
135125
}
136126
_ => (),

src/escapei.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,9 @@ pub(crate) fn _escape<F: Fn(u8) -> bool>(raw: &str, escape_chars: F) -> Cow<str>
131131
if let Some(raw) = bytes.get(pos..) {
132132
escaped.extend_from_slice(raw);
133133
}
134-
// SAFETY: we operate on UTF-8 input and search for an one byte chars only,
135-
// so all slices that was put to the `escaped` is a valid UTF-8 encoded strings
134+
// SAFETY: we operate on UTF-8 input and search for only one-byte chars, so
135+
// the end point will always be at a character boundary, and we can yield a
136+
// valid UTF-8 slice always.
136137
// TODO: Can be replaced with `unsafe { String::from_utf8_unchecked() }`
137138
// if unsafe code will be allowed
138139
Cow::Owned(String::from_utf8(escaped).unwrap())

0 commit comments

Comments
 (0)