Skip to content

Commit 47c4b55

Browse files
committed
Accept &str instead of &[u8] in escape functions
1 parent 6588d38 commit 47c4b55

File tree

5 files changed

+39
-39
lines changed

5 files changed

+39
-39
lines changed

Changelog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,10 @@
134134
scheme, for example, HEX or Base64
135135
- [#421]: All unescaping functions now accepts and returns strings instead of byte slices
136136

137+
- [#423]: All escaping functions now accepts strings instead of byte slices
138+
- [#423]: Removed `BytesText::from_plain` because it internally did escaping of a byte array,
139+
but since now escaping works on strings. Use `BytesText::from_plain_str` instead
140+
137141
### New Tests
138142

139143
- [#9]: Added tests for incorrect nested tags in input
@@ -162,6 +166,7 @@
162166
[#416]: https://github.com/tafia/quick-xml/pull/416
163167
[#418]: https://github.com/tafia/quick-xml/pull/418
164168
[#421]: https://github.com/tafia/quick-xml/pull/421
169+
[#423]: https://github.com/tafia/quick-xml/pull/423
165170

166171
## 0.23.0 -- 2022-05-08
167172

benches/microbenches.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -293,26 +293,26 @@ fn escaping(c: &mut Criterion) {
293293

294294
group.bench_function("no_chars_to_escape_long", |b| {
295295
b.iter(|| {
296-
criterion::black_box(escape(LOREM_IPSUM_TEXT.as_bytes()));
296+
criterion::black_box(escape(LOREM_IPSUM_TEXT));
297297
})
298298
});
299299

300300
group.bench_function("no_chars_to_escape_short", |b| {
301301
b.iter(|| {
302-
criterion::black_box(escape(b"just bit of text"));
302+
criterion::black_box(escape("just bit of text"));
303303
})
304304
});
305305

306306
group.bench_function("escaped_chars_short", |b| {
307307
b.iter(|| {
308-
criterion::black_box(escape(b"age > 72 && age < 21"));
309-
criterion::black_box(escape(b"\"what's that?\""));
308+
criterion::black_box(escape("age > 72 && age < 21"));
309+
criterion::black_box(escape("\"what's that?\""));
310310
})
311311
});
312312

313313
group.bench_function("escaped_chars_long", |b| {
314314
let lorem_ipsum_with_escape_chars =
315-
b"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt
315+
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt
316316
ut labore et dolore magna aliqua. & Hac habitasse platea dictumst vestibulum rhoncus est pellentesque.
317317
Risus ultricies tristique nulla aliquet enim tortor at. Fermentum odio eu feugiat pretium nibh ipsum.
318318
Volutpat sed cras ornare arcu dui. Scelerisque fermentum dui faucibus in ornare quam. Arcu cursus

src/escapei.rs

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ impl std::fmt::Display for EscapeError {
5959

6060
impl std::error::Error for EscapeError {}
6161

62-
/// Escapes a `&[u8]` and replaces all xml special characters (`<`, `>`, `&`, `'`, `"`)
62+
/// Escapes an `&str` and replaces all xml special characters (`<`, `>`, `&`, `'`, `"`)
6363
/// with their corresponding xml escaped value.
6464
///
6565
/// This function performs following replacements:
@@ -71,11 +71,11 @@ impl std::error::Error for EscapeError {}
7171
/// | `&` | `&amp;`
7272
/// | `'` | `&apos;`
7373
/// | `"` | `&quot;`
74-
pub fn escape(raw: &[u8]) -> Cow<[u8]> {
74+
pub fn escape(raw: &str) -> Cow<[u8]> {
7575
_escape(raw, |ch| matches!(ch, b'<' | b'>' | b'&' | b'\'' | b'\"'))
7676
}
7777

78-
/// Escapes a `&[u8]` and replaces xml special characters (`<`, `>`, `&`)
78+
/// Escapes an `&str` and replaces xml special characters (`<`, `>`, `&`)
7979
/// with their corresponding xml escaped value.
8080
///
8181
/// Should only be used for escaping text content. In XML text content, it is allowed
@@ -88,13 +88,14 @@ pub fn escape(raw: &[u8]) -> Cow<[u8]> {
8888
/// | `<` | `&lt;`
8989
/// | `>` | `&gt;`
9090
/// | `&` | `&amp;`
91-
pub fn partial_escape(raw: &[u8]) -> Cow<[u8]> {
91+
pub fn partial_escape(raw: &str) -> Cow<[u8]> {
9292
_escape(raw, |ch| matches!(ch, b'<' | b'>' | b'&'))
9393
}
9494

95-
/// Escapes a `&[u8]` and replaces a subset of xml special characters (`<`, `>`,
95+
/// Escapes an `&str` and replaces a subset of xml special characters (`<`, `>`,
9696
/// `&`, `'`, `"`) with their corresponding xml escaped value.
97-
fn _escape<F: Fn(u8) -> bool>(raw: &[u8], escape_chars: F) -> Cow<[u8]> {
97+
fn _escape<F: Fn(u8) -> bool>(raw: &str, escape_chars: F) -> Cow<[u8]> {
98+
let raw = raw.as_bytes();
9899
let mut escaped = None;
99100
let mut bytes = raw.iter();
100101
let mut pos = 0;
@@ -1744,24 +1745,24 @@ fn test_unescape_with() {
17441745

17451746
#[test]
17461747
fn test_escape() {
1747-
assert_eq!(&*escape(b"test"), b"test");
1748-
assert_eq!(&*escape(b"<test>"), b"&lt;test&gt;");
1749-
assert_eq!(&*escape(b"\"a\"bc"), b"&quot;a&quot;bc");
1750-
assert_eq!(&*escape(b"\"a\"b&c"), b"&quot;a&quot;b&amp;c");
1748+
assert_eq!(&*escape("test"), b"test");
1749+
assert_eq!(&*escape("<test>"), b"&lt;test&gt;");
1750+
assert_eq!(&*escape("\"a\"bc"), b"&quot;a&quot;bc");
1751+
assert_eq!(&*escape("\"a\"b&c"), b"&quot;a&quot;b&amp;c");
17511752
assert_eq!(
1752-
&*escape(b"prefix_\"a\"b&<>c"),
1753+
&*escape("prefix_\"a\"b&<>c"),
17531754
"prefix_&quot;a&quot;b&amp;&lt;&gt;c".as_bytes()
17541755
);
17551756
}
17561757

17571758
#[test]
17581759
fn test_partial_escape() {
1759-
assert_eq!(&*partial_escape(b"test"), b"test");
1760-
assert_eq!(&*partial_escape(b"<test>"), b"&lt;test&gt;");
1761-
assert_eq!(&*partial_escape(b"\"a\"bc"), b"\"a\"bc");
1762-
assert_eq!(&*partial_escape(b"\"a\"b&c"), b"\"a\"b&amp;c");
1760+
assert_eq!(&*partial_escape("test"), b"test");
1761+
assert_eq!(&*partial_escape("<test>"), b"&lt;test&gt;");
1762+
assert_eq!(&*partial_escape("\"a\"bc"), b"\"a\"bc");
1763+
assert_eq!(&*partial_escape("\"a\"b&c"), b"\"a\"b&amp;c");
17631764
assert_eq!(
1764-
&*partial_escape(b"prefix_\"a\"b&<>c"),
1765+
&*partial_escape("prefix_\"a\"b&<>c"),
17651766
"prefix_\"a\"b&amp;&lt;&gt;c".as_bytes()
17661767
);
17671768
}

src/events/attributes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ impl<'a> From<(&'a str, &'a str)> for Attribute<'a> {
143143
fn from(val: (&'a str, &'a str)) -> Attribute<'a> {
144144
Attribute {
145145
key: QName(val.0.as_bytes()),
146-
value: escape(val.1.as_bytes()),
146+
value: escape(val.1),
147147
}
148148
}
149149
}

src/events/mod.rs

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -681,15 +681,6 @@ impl<'a> BytesText<'a> {
681681
}
682682
}
683683

684-
/// Creates a new `BytesText` from a byte sequence. The byte sequence is
685-
/// expected not to be escaped.
686-
#[inline]
687-
pub fn from_plain(content: &'a [u8]) -> Self {
688-
Self {
689-
content: escape(content),
690-
}
691-
}
692-
693684
/// Creates a new `BytesText` from an escaped string.
694685
#[inline]
695686
pub fn from_escaped_str<C: Into<Cow<'a, str>>>(content: C) -> Self {
@@ -703,7 +694,9 @@ impl<'a> BytesText<'a> {
703694
/// be escaped.
704695
#[inline]
705696
pub fn from_plain_str(content: &'a str) -> Self {
706-
Self::from_plain(content.as_bytes())
697+
Self {
698+
content: escape(content),
699+
}
707700
}
708701

709702
/// Ensures that all data is owned to extend the object's lifetime if
@@ -901,11 +894,12 @@ impl<'a> BytesCData<'a> {
901894
/// | `&` | `&amp;`
902895
/// | `'` | `&apos;`
903896
/// | `"` | `&quot;`
904-
pub fn escape(self) -> BytesText<'a> {
905-
BytesText::from_escaped(match escape(&self.content) {
897+
pub fn escape(self, decoder: Decoder) -> Result<BytesText<'a>> {
898+
let decoded = self.decode(decoder)?;
899+
Ok(BytesText::from_escaped(match escape(&decoded) {
906900
Cow::Borrowed(_) => self.content,
907901
Cow::Owned(escaped) => Cow::Owned(escaped),
908-
})
902+
}))
909903
}
910904

911905
/// Converts this CDATA content to an escaped version, that can be written
@@ -921,15 +915,15 @@ impl<'a> BytesCData<'a> {
921915
/// | `<` | `&lt;`
922916
/// | `>` | `&gt;`
923917
/// | `&` | `&amp;`
924-
pub fn partial_escape(self) -> BytesText<'a> {
925-
BytesText::from_escaped(match partial_escape(&self.content) {
918+
pub fn partial_escape(self, decoder: Decoder) -> Result<BytesText<'a>> {
919+
let decoded = self.decode(decoder)?;
920+
Ok(BytesText::from_escaped(match partial_escape(&decoded) {
926921
Cow::Borrowed(_) => self.content,
927922
Cow::Owned(escaped) => Cow::Owned(escaped),
928-
})
923+
}))
929924
}
930925

931926
/// Gets content of this text buffer in the specified encoding
932-
#[cfg(feature = "serialize")]
933927
pub(crate) fn decode(&self, decoder: Decoder) -> Result<Cow<'a, str>> {
934928
Ok(match &self.content {
935929
Cow::Borrowed(bytes) => decoder.decode(bytes)?,

0 commit comments

Comments
 (0)