Skip to content

Commit

Permalink
Convert namespace-related structs to str
Browse files Browse the repository at this point in the history
  • Loading branch information
dralley committed Aug 14, 2022
1 parent 182d794 commit 553a9ef
Show file tree
Hide file tree
Showing 25 changed files with 424 additions and 471 deletions.
2 changes: 1 addition & 1 deletion benches/microbenches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ fn attributes(c: &mut Criterion) {
let mut count = criterion::black_box(0);
loop {
match r.read_event() {
Ok(Event::Empty(e)) if e.name() == QName(b"player") => {
Ok(Event::Empty(e)) if e.name() == QName("player") => {
for name in ["num", "status", "avg"] {
if let Some(_attr) = e.try_get_attribute(name).unwrap() {
count += 1
Expand Down
2 changes: 1 addition & 1 deletion examples/custom_entities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
}
}
Ok(Event::Start(ref e)) => match e.name().as_ref() {
b"test" => {
"test" => {
let attributes = e
.attributes()
.map(|a| {
Expand Down
13 changes: 5 additions & 8 deletions examples/nested_readers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ fn main() -> Result<(), quick_xml::Error> {
loop {
match reader.read_event_into(&mut buf)? {
Event::Start(element) => match element.name().as_ref() {
b"w:tbl" => {
"w:tbl" => {
count += 1;
let mut stats = TableStat {
index: count,
Expand All @@ -35,20 +35,17 @@ fn main() -> Result<(), quick_xml::Error> {
skip_buf.clear();
match reader.read_event_into(&mut skip_buf)? {
Event::Start(element) => match element.name().as_ref() {
b"w:tr" => {
"w:tr" => {
stats.rows.push(vec![]);
row_index = stats.rows.len() - 1;
}
b"w:tc" => {
stats.rows[row_index].push(
String::from_utf8(element.name().as_ref().to_vec())
.unwrap(),
);
"w:tc" => {
stats.rows[row_index].push(element.name().as_ref().to_owned());
}
_ => {}
},
Event::End(element) => {
if element.name().as_ref() == b"w:tbl" {
if element.name().as_ref() == "w:tbl" {
found_tables.push(stats);
break;
}
Expand Down
4 changes: 1 addition & 3 deletions examples/read_buffered.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@ fn main() -> Result<(), quick_xml::Error> {
loop {
match reader.read_event_into(&mut buf) {
Ok(Event::Start(ref e)) => {
let name = e.name();
let name = reader.decoder().decode(name.as_ref())?;
println!("read start event {:?}", name.as_ref());
println!("read start event {:?}", e.name().as_ref());
count += 1;
}
Ok(Event::Eof) => break, // exits the loop when reaching end of file
Expand Down
4 changes: 2 additions & 2 deletions examples/read_texts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ fn main() {
let mut txt = Vec::new();
loop {
match reader.read_event() {
Ok(Event::Start(ref e)) if e.name().as_ref() == b"tag2" => {
Ok(Event::Start(ref e)) if e.name().as_ref() == "tag2" => {
txt.push(
reader
.read_text(QName(b"tag2"))
.read_text_into(QName("tag2"), &mut Vec::new())
.expect("Cannot decode text value"),
);
println!("{:?}", txt);
Expand Down
16 changes: 6 additions & 10 deletions src/de/escape.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
//! Serde `Deserializer` module

use crate::de::deserialize_bool;
use crate::encoding::Decoder;
use crate::errors::serialize::DeError;
use crate::escape::unescape;
use serde::de::{DeserializeSeed, EnumAccess, VariantAccess, Visitor};
Expand All @@ -17,17 +16,15 @@ use std::borrow::Cow;
/// anyway
#[derive(Clone, Debug)]
pub struct EscapedDeserializer<'a> {
decoder: Decoder,
/// Possible escaped value of text/CDATA or attribute value
escaped_value: Cow<'a, [u8]>,
escaped_value: Cow<'a, str>,
/// If `true`, value requires unescaping before using
escaped: bool,
}

impl<'a> EscapedDeserializer<'a> {
pub fn new(escaped_value: Cow<'a, [u8]>, decoder: Decoder, escaped: bool) -> Self {
pub fn new(escaped_value: Cow<'a, str>, escaped: bool) -> Self {
EscapedDeserializer {
decoder,
escaped_value,
escaped,
}
Expand All @@ -40,7 +37,7 @@ macro_rules! deserialize_num {
where
V: Visitor<'de>,
{
let value = self.decoder.decode(self.escaped_value.as_ref())?.parse()?;
let value = self.escaped_value.as_ref().parse()?;

visitor.$visit(value)
}
Expand All @@ -61,14 +58,13 @@ impl<'de, 'a> serde::Deserializer<'de> for EscapedDeserializer<'a> {
where
V: Visitor<'de>,
{
let decoded = self.decoder.decode(&self.escaped_value)?;
if self.escaped {
match unescape(&decoded)? {
match unescape(&self.escaped_value)? {
Cow::Borrowed(s) => visitor.visit_str(s),
Cow::Owned(s) => visitor.visit_string(s),
}
} else {
match decoded {
match self.escaped_value {
Cow::Borrowed(s) => visitor.visit_str(s),
Cow::Owned(s) => visitor.visit_string(s),
}
Expand Down Expand Up @@ -104,7 +100,7 @@ impl<'de, 'a> serde::Deserializer<'de> for EscapedDeserializer<'a> {
where
V: Visitor<'de>,
{
deserialize_bool(self.escaped_value.as_ref(), self.decoder, visitor)
deserialize_bool(self.escaped_value.as_ref(), visitor)
}

fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
Expand Down
52 changes: 24 additions & 28 deletions src/de/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,15 +231,13 @@ where

// FIXME: There error positions counted from the start of tag name - need global position
let slice = &self.start.buf;
let decoder = self.de.reader.decoder();

if let Some(a) = self.iter.next(slice).transpose()? {
// try getting map from attributes (key= "value")
let (key, value) = a.into();
self.source = ValueSource::Attribute(value.unwrap_or_default());
seed.deserialize(EscapedDeserializer::new(
Cow::Borrowed(&slice[key]),
decoder,
Cow::Borrowed(std::str::from_utf8(&slice[key]).expect("fixme dalley")),
false,
))
.map(Some)
Expand Down Expand Up @@ -269,33 +267,32 @@ where
// }
// TODO: This should be handled by #[serde(flatten)]
// See https://github.com/serde-rs/serde/issues/1905
DeEvent::Start(e) if self.has_value_field && not_in(self.fields, e, decoder)? => {
DeEvent::Start(e) if self.has_value_field && not_in(self.fields, e)? => {
self.source = ValueSource::Content;
seed.deserialize(INNER_VALUE.into_deserializer()).map(Some)
}
DeEvent::Start(e) => {
self.source = ValueSource::Nested;
let key = if let Some(p) = self
.unflatten_fields
.iter()
.position(|f| e.name().as_ref() == &f[UNFLATTEN_PREFIX.len()..])
{
// Used to deserialize elements, like:
// <root>
// <xxx>test</xxx>
// </root>
//
// into
//
// struct Root {
// #[serde(rename = "$unflatten=xxx")]
// xxx: String,
// }
seed.deserialize(self.unflatten_fields.remove(p).into_deserializer())
} else {
let name = Cow::Borrowed(e.local_name().into_inner());
seed.deserialize(EscapedDeserializer::new(name, decoder, false))
};
let key =
if let Some(p) = self.unflatten_fields.iter().position(|f| {
e.name().as_ref().as_bytes() == &f[UNFLATTEN_PREFIX.len()..]
}) {
// Used to deserialize elements, like:
// <root>
// <xxx>test</xxx>
// </root>
//
// into
//
// struct Root {
// #[serde(rename = "$unflatten=xxx")]
// xxx: String,
// }
seed.deserialize(self.unflatten_fields.remove(p).into_deserializer())
} else {
let name = Cow::Borrowed(e.local_name().into_inner());
seed.deserialize(EscapedDeserializer::new(name, false))
};
key.map(Some)
}
// Stop iteration after reaching a closing tag
Expand Down Expand Up @@ -616,18 +613,17 @@ where
where
T: DeserializeSeed<'de>,
{
let decoder = self.map.de.reader.decoder();
loop {
break match self.map.de.peek()? {
// If we see a tag that we not interested, skip it
#[cfg(feature = "overlapped-lists")]
DeEvent::Start(e) if !self.filter.is_suitable(&e, decoder)? => {
DeEvent::Start(e) if !self.filter.is_suitable(&e)? => {
self.map.de.skip()?;
continue;
}
// Stop iteration when list elements ends
#[cfg(not(feature = "overlapped-lists"))]
DeEvent::Start(e) if !self.filter.is_suitable(&e, decoder)? => Ok(None),
DeEvent::Start(e) if !self.filter.is_suitable(&e)? => Ok(None),

// Stop iteration after reaching a closing tag
DeEvent::End(e) if e.name() == self.map.start.name() => Ok(None),
Expand Down
39 changes: 10 additions & 29 deletions src/de/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,30 +325,12 @@ where
}
}

fn deserialize_bool<'de, V>(value: &[u8], decoder: Decoder, visitor: V) -> Result<V::Value, DeError>
fn deserialize_bool<'de, V>(value: &str, visitor: V) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
#[cfg(feature = "encoding")]
{
let value = decoder.decode(value)?;
// No need to unescape because valid boolean representations cannot be escaped
str2bool(value.as_ref(), visitor)
}

#[cfg(not(feature = "encoding"))]
{
// No need to unescape because valid boolean representations cannot be escaped
match value {
b"true" | b"1" | b"True" | b"TRUE" | b"t" | b"Yes" | b"YES" | b"yes" | b"y" => {
visitor.visit_bool(true)
}
b"false" | b"0" | b"False" | b"FALSE" | b"f" | b"No" | b"NO" | b"no" | b"n" => {
visitor.visit_bool(false)
}
e => Err(DeError::InvalidBoolean(decoder.decode(e)?.into())),
}
}
// No need to unescape because valid boolean representations cannot be escaped
str2bool(value.as_ref(), visitor)
}

impl<'de, R> Deserializer<'de, R>
Expand Down Expand Up @@ -738,10 +720,9 @@ where
{
// Try to go to the next `<tag ...>...</tag>` or `<tag .../>`
if let Some(e) = self.next_start()? {
let name = e.name().as_ref().to_vec();
let map = map::MapAccess::new(self, e, fields)?;
let map = map::MapAccess::new(self, e.clone(), fields)?;
let value = visitor.visit_map(map)?;
self.read_to_end(QName(&name))?;
self.read_to_end(e.name())?;
Ok(value)
} else {
Err(DeError::ExpectedStart)
Expand Down Expand Up @@ -1182,7 +1163,7 @@ mod tests {
// </skip>
// </root>
assert_eq!(de.next().unwrap(), Start(BytesStart::new("target")));
de.read_to_end(QName(b"target")).unwrap();
de.read_to_end(QName("target")).unwrap();
assert_eq!(de.read, vec![]);
assert_eq!(
de.write,
Expand Down Expand Up @@ -1219,7 +1200,7 @@ mod tests {
assert_eq!(de.write, vec![]);

assert_eq!(de.next().unwrap(), Start(BytesStart::new("skip")));
de.read_to_end(QName(b"skip")).unwrap();
de.read_to_end(QName("skip")).unwrap();

assert_eq!(de.next().unwrap(), End(BytesEnd::new("root")));
assert_eq!(de.next().unwrap(), Eof);
Expand Down Expand Up @@ -1477,7 +1458,7 @@ mod tests {
de.next().unwrap(),
Start(BytesStart::from_content(r#"tag a="1""#, 3))
);
assert_eq!(de.read_to_end(QName(b"tag")).unwrap(), ());
assert_eq!(de.read_to_end(QName("tag")).unwrap(), ());

assert_eq!(
de.next().unwrap(),
Expand All @@ -1487,7 +1468,7 @@ mod tests {
assert_eq!(de.next().unwrap(), End(BytesEnd::new("tag")));

assert_eq!(de.next().unwrap(), Start(BytesStart::new("self-closed")));
assert_eq!(de.read_to_end(QName(b"self-closed")).unwrap(), ());
assert_eq!(de.read_to_end(QName("self-closed")).unwrap(), ());

assert_eq!(de.next().unwrap(), End(BytesEnd::new("root")));
assert_eq!(de.next().unwrap(), Eof);
Expand Down Expand Up @@ -1588,7 +1569,7 @@ mod tests {
reader.next().unwrap(),
DeEvent::Start(BytesStart::from_content("item ", 4))
);
reader.read_to_end(QName(b"item")).unwrap();
reader.read_to_end(QName("item")).unwrap();
assert_eq!(reader.next().unwrap(), DeEvent::Eof);
}

Expand Down
35 changes: 10 additions & 25 deletions src/de/seq.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,12 @@
use crate::de::{DeError, DeEvent, Deserializer, XmlRead};
use crate::encoding::Decoder;
use crate::events::BytesStart;
use serde::de::{DeserializeSeed, SeqAccess};

/// Check if tag `start` is included in the `fields` list. `decoder` is used to
/// get a string representation of a tag.
/// Check if tag `start` is included in the `fields` list.
///
/// Returns `true`, if `start` is not in the `fields` list and `false` otherwise.
pub fn not_in(
fields: &'static [&'static str],
start: &BytesStart,
decoder: Decoder,
) -> Result<bool, DeError> {
let tag = decoder.decode(start.name().into_inner())?;

Ok(fields.iter().all(|&field| field != tag.as_ref()))
pub fn not_in(fields: &'static [&'static str], start: &BytesStart) -> Result<bool, DeError> {
Ok(fields.iter().all(|&field| field != start.name().as_ref()))
}

/// A filter that determines, what tags should form a sequence.
Expand Down Expand Up @@ -59,10 +51,10 @@ pub enum TagFilter<'de> {
}

impl<'de> TagFilter<'de> {
pub fn is_suitable(&self, start: &BytesStart, decoder: Decoder) -> Result<bool, DeError> {
pub fn is_suitable(&self, start: &BytesStart) -> Result<bool, DeError> {
match self {
Self::Include(n) => Ok(n.name() == start.name()),
Self::Exclude(fields) => not_in(fields, start, decoder),
Self::Exclude(fields) => not_in(fields, start),
}
}
}
Expand Down Expand Up @@ -132,18 +124,17 @@ where
where
T: DeserializeSeed<'de>,
{
let decoder = self.de.reader.decoder();
loop {
break match self.de.peek()? {
// If we see a tag that we not interested, skip it
#[cfg(feature = "overlapped-lists")]
DeEvent::Start(e) if !self.filter.is_suitable(e, decoder)? => {
DeEvent::Start(e) if !self.filter.is_suitable(e)? => {
self.de.skip()?;
continue;
}
// Stop iteration when list elements ends
#[cfg(not(feature = "overlapped-lists"))]
DeEvent::Start(e) if !self.filter.is_suitable(e, decoder)? => Ok(None),
DeEvent::Start(e) if !self.filter.is_suitable(e)? => Ok(None),
DeEvent::End(_) => Ok(None),
DeEvent::Eof => Ok(None),

Expand All @@ -158,13 +149,7 @@ where
fn test_not_in() {
let tag = BytesStart::new("tag");

assert_eq!(not_in(&[], &tag, Decoder::utf8()).unwrap(), true);
assert_eq!(
not_in(&["no", "such", "tags"], &tag, Decoder::utf8()).unwrap(),
true
);
assert_eq!(
not_in(&["some", "tag", "included"], &tag, Decoder::utf8()).unwrap(),
false
);
assert_eq!(not_in(&[], &tag).unwrap(), true);
assert_eq!(not_in(&["no", "such", "tags"], &tag).unwrap(), true);
assert_eq!(not_in(&["some", "tag", "included"], &tag).unwrap(), false);
}
Loading

0 comments on commit 553a9ef

Please sign in to comment.