use criterion::{self, criterion_group, criterion_main, Criterion};
use pretty_assertions::assert_eq;
use quick_xml::escape::{escape, unescape};
use quick_xml::events::Event;
use quick_xml::name::QName;
use quick_xml::reader::{NsReader, Reader};
static SAMPLE: &str = include_str!("../tests/documents/sample_rss.xml");
static PLAYERS: &str = include_str!("../tests/documents/players.xml");
static LOREM_IPSUM_TEXT: &str =
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt
ut labore et dolore magna aliqua. Hac habitasse platea dictumst vestibulum rhoncus est pellentesque.
Risus ultricies tristique nulla aliquet enim tortor at. Fermentum odio eu feugiat pretium nibh ipsum.
Volutpat sed cras ornare arcu dui. Scelerisque fermentum dui faucibus in ornare quam. Arcu cursus
euismod quis viverra nibh cras pulvinar mattis. Sed viverra tellus in hac habitasse platea. Quis
commodo odio aenean sed. Cursus in hac habitasse platea dictumst quisque sagittis purus.
Neque convallis a cras semper auctor. Sit amet mauris commodo quis imperdiet massa. Ac ut consequat
semper viverra nam libero justo laoreet sit. Adipiscing commodo elit at imperdiet dui accumsan.
Enim lobortis scelerisque fermentum dui faucibus in ornare. Natoque penatibus et magnis dis parturient
montes nascetur ridiculus mus. At lectus urna duis convallis convallis tellus id interdum. Libero
volutpat sed cras ornare arcu dui vivamus arcu. Cursus in hac habitasse platea dictumst quisque sagittis
purus. Consequat id porta nibh venenatis cras sed felis.";
fn read_event(c: &mut Criterion) {
let mut group = c.benchmark_group("read_event");
group.bench_function("trim_text = false", |b| {
b.iter(|| {
let mut r = Reader::from_str(SAMPLE);
r.check_end_names(false).check_comments(false);
let mut count = criterion::black_box(0);
loop {
match r.read_event() {
Ok(Event::Start(_)) | Ok(Event::Empty(_)) => count += 1,
Ok(Event::Eof) => break,
_ => (),
}
}
assert_eq!(
count, 1550,
"Overall tag count in ./tests/documents/sample_rss.xml"
);
})
});
group.bench_function("trim_text = true", |b| {
b.iter(|| {
let mut r = Reader::from_str(SAMPLE);
r.check_end_names(false)
.check_comments(false)
.trim_text(true);
let mut count = criterion::black_box(0);
loop {
match r.read_event() {
Ok(Event::Start(_)) | Ok(Event::Empty(_)) => count += 1,
Ok(Event::Eof) => break,
_ => (),
}
}
assert_eq!(
count, 1550,
"Overall tag count in ./tests/documents/sample_rss.xml"
);
});
});
group.finish();
}
fn read_resolved_event_into(c: &mut Criterion) {
let mut group = c.benchmark_group("NsReader::read_resolved_event_into");
group.bench_function("trim_text = false", |b| {
b.iter(|| {
let mut r = NsReader::from_str(SAMPLE);
r.check_end_names(false).check_comments(false);
let mut count = criterion::black_box(0);
loop {
match r.read_resolved_event() {
Ok((_, Event::Start(_))) | Ok((_, Event::Empty(_))) => count += 1,
Ok((_, Event::Eof)) => break,
_ => (),
}
}
assert_eq!(
count, 1550,
"Overall tag count in ./tests/documents/sample_rss.xml"
);
});
});
group.bench_function("trim_text = true", |b| {
b.iter(|| {
let mut r = NsReader::from_str(SAMPLE);
r.check_end_names(false)
.check_comments(false)
.trim_text(true);
let mut count = criterion::black_box(0);
loop {
match r.read_resolved_event() {
Ok((_, Event::Start(_))) | Ok((_, Event::Empty(_))) => count += 1,
Ok((_, Event::Eof)) => break,
_ => (),
}
}
assert_eq!(
count, 1550,
"Overall tag count in ./tests/documents/sample_rss.xml"
);
});
});
group.finish();
}
fn one_event(c: &mut Criterion) {
let mut group = c.benchmark_group("One event");
group.bench_function("Start", |b| {
let src = format!(r#"<hello target="{}">"#, "world".repeat(512 / 5));
b.iter(|| {
let mut r = Reader::from_str(&src);
let mut nbtxt = criterion::black_box(0);
r.check_end_names(false)
.check_comments(false)
.trim_text(true);
match r.read_event() {
Ok(Event::Start(ref e)) => nbtxt += e.len(),
something_else => panic!("Did not expect {:?}", something_else),
};
assert_eq!(nbtxt, 525);
})
});
group.bench_function("Comment", |b| {
let src = format!(r#"<!-- hello "{}" -->"#, "world".repeat(512 / 5));
b.iter(|| {
let mut r = Reader::from_str(&src);
let mut nbtxt = criterion::black_box(0);
r.check_end_names(false)
.check_comments(false)
.trim_text(true);
match r.read_event() {
Ok(Event::Comment(e)) => nbtxt += e.unescape().unwrap().len(),
something_else => panic!("Did not expect {:?}", something_else),
};
assert_eq!(nbtxt, 520);
})
});
group.bench_function("CData", |b| {
let src = format!(r#"<![CDATA[hello "{}"]]>"#, "world".repeat(512 / 5));
b.iter(|| {
let mut r = Reader::from_str(&src);
let mut nbtxt = criterion::black_box(0);
r.check_end_names(false)
.check_comments(false)
.trim_text(true);
match r.read_event() {
Ok(Event::CData(ref e)) => nbtxt += e.len(),
something_else => panic!("Did not expect {:?}", something_else),
};
assert_eq!(nbtxt, 518);
})
});
group.finish();
}
fn attributes(c: &mut Criterion) {
let mut group = c.benchmark_group("attributes");
group.bench_function("with_checks = true", |b| {
b.iter(|| {
let mut r = Reader::from_str(PLAYERS);
r.check_end_names(false).check_comments(false);
let mut count = criterion::black_box(0);
loop {
match r.read_event() {
Ok(Event::Empty(e)) => {
for attr in e.attributes() {
let _attr = attr.unwrap();
count += 1
}
}
Ok(Event::Eof) => break,
_ => (),
}
}
assert_eq!(count, 1041);
})
});
group.bench_function("with_checks = false", |b| {
b.iter(|| {
let mut r = Reader::from_str(PLAYERS);
r.check_end_names(false).check_comments(false);
let mut count = criterion::black_box(0);
loop {
match r.read_event() {
Ok(Event::Empty(e)) => {
for attr in e.attributes().with_checks(false) {
let _attr = attr.unwrap();
count += 1
}
}
Ok(Event::Eof) => break,
_ => (),
}
}
assert_eq!(count, 1041);
})
});
group.bench_function("try_get_attribute", |b| {
b.iter(|| {
let mut r = Reader::from_str(PLAYERS);
r.check_end_names(false).check_comments(false);
let mut count = criterion::black_box(0);
loop {
match r.read_event() {
Ok(Event::Empty(e)) if e.name() == QName(b"player") => {
for name in ["num", "status", "avg"] {
if let Some(_attr) = e.try_get_attribute(name).unwrap() {
count += 1
}
}
assert!(e
.try_get_attribute("attribute-that-doesn't-exist")
.unwrap()
.is_none());
}
Ok(Event::Eof) => break,
_ => (),
}
}
assert_eq!(count, 150);
})
});
group.finish();
}
fn escaping(c: &mut Criterion) {
let mut group = c.benchmark_group("escape_text");
group.bench_function("no_chars_to_escape_long", |b| {
b.iter(|| {
criterion::black_box(escape(LOREM_IPSUM_TEXT));
})
});
group.bench_function("no_chars_to_escape_short", |b| {
b.iter(|| {
criterion::black_box(escape("just bit of text"));
})
});
group.bench_function("escaped_chars_short", |b| {
b.iter(|| {
criterion::black_box(escape("age > 72 && age < 21"));
criterion::black_box(escape("\"what's that?\""));
})
});
group.bench_function("escaped_chars_long", |b| {
let lorem_ipsum_with_escape_chars =
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt
ut labore et dolore magna aliqua. & Hac habitasse platea dictumst vestibulum rhoncus est pellentesque.
Risus ultricies tristique nulla aliquet enim tortor at. Fermentum odio eu feugiat pretium nibh ipsum.
Volutpat sed cras ornare arcu dui. Scelerisque fermentum dui faucibus in ornare quam. Arcu cursus
euismod quis< viverra nibh cras pulvinar mattis. Sed viverra tellus in hac habitasse platea. Quis
commodo odio aenean sed. Cursus in hac habitasse platea dictumst quisque sagittis purus.
Neque convallis >a cras semper auctor. Sit amet mauris commodo quis imperdiet massa. Ac ut consequat
semper viverra nam libero justo laoreet sit. 'Adipiscing' commodo elit at imperdiet dui accumsan.
Enim lobortis scelerisque fermentum dui faucibus in ornare. Natoque penatibus et magnis dis parturient
montes nascetur ridiculus mus. At lectus urna duis convallis convallis tellus id interdum. Libero
volutpat sed cras ornare arcu dui vivamus arcu. Cursus in hac habitasse platea dictumst quisque sagittis
purus. Consequat id porta nibh venenatis cras sed felis.";
b.iter(|| {
criterion::black_box(escape(lorem_ipsum_with_escape_chars));
})
});
group.finish();
}
fn unescaping(c: &mut Criterion) {
let mut group = c.benchmark_group("unescape_text");
group.bench_function("no_chars_to_unescape_long", |b| {
b.iter(|| {
criterion::black_box(unescape(LOREM_IPSUM_TEXT)).unwrap();
})
});
group.bench_function("no_chars_to_unescape_short", |b| {
b.iter(|| {
criterion::black_box(unescape("just a bit of text")).unwrap();
})
});
group.bench_function("char_reference", |b| {
b.iter(|| {
let text = "prefix "some stuff","more stuff"";
criterion::black_box(unescape(text)).unwrap();
let text = "&<";
criterion::black_box(unescape(text)).unwrap();
})
});
group.bench_function("entity_reference", |b| {
b.iter(|| {
let text = "age > 72 && age < 21";
criterion::black_box(unescape(text)).unwrap();
let text = ""what's that?"";
criterion::black_box(unescape(text)).unwrap();
})
});
group.bench_function("mixed", |b| {
let text =
"Lorem ipsum dolor sit amet, &consectetur adipiscing elit, sed do eiusmod tempor incididunt
ut labore et dolore magna aliqua. Hac habitasse platea dictumst vestibulum rhoncus est pellentesque.
Risus ultricies "tristique nulla aliquet enim tortor" at. Fermentum odio eu feugiat pretium
nibh ipsum. Volutpat sed cras ornare arcu dui. Scelerisque fermentum dui faucibus in ornare quam. Arcu
cursus euismod quis <viverra nibh cras pulvinar mattis. Sed viverra tellus in hac habitasse platea.
Quis commodo odio aenean sed. Cursus in hac habitasse platea dictumst quisque sagittis purus.
Neque convallis a cras semper auctor. Sit amet mauris commodo quis imperdiet massa. Ac ut consequat
semper viverra nam libero justo # laoreet sit. Adipiscing commodo elit at imperdiet dui accumsan.
Enim lobortis scelerisque fermentum dui faucibus in ornare. Natoque penatibus et magnis dis parturient
montes nascetur ridiculus mus. At lectus urna !duis convallis convallis tellus id interdum. Libero
volutpat sed cras ornare arcu dui vivamus arcu. Cursus in hac habitasse platea dictumst quisque sagittis
purus. Consequat id porta nibh venenatis cras sed felis.";
b.iter(|| {
criterion::black_box(unescape(text)).unwrap();
})
});
group.finish();
}
criterion_group!(
benches,
read_event,
read_resolved_event_into,
one_event,
attributes,
escaping,
unescaping,
);
criterion_main!(benches);