cargo-binstall/crates/leon/benches/values.rs
Félix Saparelli 2227d363f7
Leon template library (#766)
* leon: first implementation

* Update crates/leon/src/values.rs

Co-authored-by: Jiahao XU <Jiahao_XU@outlook.com>

* Workaround orphan rules to make API more intuitive

* Fmt

* Clippy

* Use CoW

* Use cow for items too

* Test that const construction works

* leon: Initial attempt at O(n) parser

* leon: finish parser (except escapes)

* leon: Improve ergonomics of compile-time templates

* Document helpers

* leon: Docs tweaks

* leon: Use macro to minimise parser tests

* leon: add escapes to parser

* leon: test escapes preceding keys

* leon: add multibyte tests

* leon: test escapes following keys

* Format

* Debug

* leon: Don't actually need to keep track of the key

* leon: Parse to vec first

* leon: there's actually no need for string cows

* leon: reorganise and redo macro now that there's no coww

* Well that was silly

* leon: Adjust text end when pushing

* leon: catch unbalanced keys

* Add error tests

* leon: Catch unfinished escape

* Comment out debugging

* leon: fuzz

* Clippy

* leon: Box parse error

* leon: &dyn instead of impl

* Can't impl FromStr, so rename to parse

* Add Vec<> to values

* leon: Add benches for ways to supply values

* leon: Add bench comparing to std and tt

* Fix fuzz

* Fmt

* Split ParseError and RenderError

* Make miette optional

* Remove RenderError lifetime

* Simplify ParseError type schema

* Write concrete Values types instead of generics

* Add license files

* Reduce criterion deps

* Make default a cow

* Add a CLI leon tool

* Fix tests

* Clippy

* Disable cli by default

* Avoid failing the build when cli is off

* Add to ci

* Update crates/leon/src/main.rs

Co-authored-by: Jiahao XU <Jiahao_XU@outlook.com>

* Update crates/leon/Cargo.toml

Co-authored-by: Jiahao XU <Jiahao_XU@outlook.com>

* Bump version

* Error not transparent

* Diagnostic can do forwarding

* Simplify error type

* Expand doc examples

* Generic Values for Hash and BTree maps

* One more borrowed

* Forward implementations

* More generics

* Add has_keys

* Lock stdout in leon tool

* No more debug comments in parser

* Even more generics

* Macros to reduce bench duplication

* Further simplify error

* Fix leon main

* Stable support

* Clippy

---------

Co-authored-by: Jiahao XU <Jiahao_XU@outlook.com>
2023-03-21 01:36:02 +00:00

298 lines
8.2 KiB
Rust

use std::{borrow::Cow, collections::HashMap};
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use leon::{vals, Template, Values, ValuesFn};
macro_rules! make_values {
($($name:expr => $value:expr),*) => {
(
&[$(($name, $value)),*],
{
let mut map = HashMap::new();
$(
map.insert($name, $value);
)*
map
},
vals(|key| match key {
$(
$name => Some(Cow::Borrowed($value)),
)*
_ => None,
})
)
};
}
fn one_replace(c: &mut Criterion) {
const TEMPLATE: &str = "Hello, {name}!";
let (slice, hashmap, vals) = make_values!(
"name" => "marcus"
);
inner_bench("one replace", c, TEMPLATE, vals, hashmap, slice);
}
fn some_replaces(c: &mut Criterion) {
const TEMPLATE: &str = "hello {name}! i am {age} years old. my goal is to {goal}. i like: {flower}, {music}, {animal}, {color}, {food}. i'm drinking {drink}";
let (slice, hashmap, vals) = make_values!(
"name" => "marcus",
"age" => "42",
"goal" => "primary",
"flower" => "lotus",
"music" => "jazz",
"animal" => "cat",
"color" => "blue",
"food" => "pizza",
"drink" => "coffee"
);
inner_bench("some replaces", c, TEMPLATE, vals, hashmap, slice);
}
fn many_replaces(c: &mut Criterion) {
const TEMPLATE: &str = "
{artichoke}
{aubergine}
{asparagus}
{broccoflower}
{broccoli}
{brussels sprouts}
{cabbage}
{kohlrabi}
{Savoy cabbage}
{red cabbage}
{cauliflower}
{celery}
{endive}
{fiddleheads}
{frisee}
{fennel}
{greens}
{arugula}
{bok choy}
{chard}
{collard greens}
{kale}
{lettuce}
{mustard greens}
{spinach}
{herbs}
{anise}
{basil}
{caraway}
{coriander}
{chamomile}
{daikon}
{dill}
{squash}
{lavender}
{cymbopogon}
{marjoram}
{oregano}
{parsley}
{rosemary}
{thyme}
{legumes}
{alfalfa sprouts}
{azuki beans}
{bean sprouts}
{black beans}
{black-eyed peas}
{borlotti bean}
{broad beans}
{chickpeas, garbanzos, or ceci beans}
{green beans}
{kidney beans}
{lentils}
{lima beans or butter bean}
{mung beans}
{navy beans}
{peanuts}
{pinto beans}
{runner beans}
{split peas}
{soy beans}
{peas}
{mange tout or snap peas}
{mushrooms}
{nettles}
{New Zealand spinach}
{okra}
{onions}
{chives}
{garlic}
{leek}
{onion}
{shallot}
{scallion}
{peppers}
{bell pepper}
{chili pepper}
{jalapeño}
{habanero}
{paprika}
{tabasco pepper}
{cayenne pepper}
{radicchio}
{rhubarb}
{root vegetables}
{beetroot}
{beet}
{mangelwurzel}
{carrot}
{celeriac}
{corms}
{eddoe}
{konjac}
{taro}
{water chestnut}
{ginger}
{parsnip}
{rutabaga}
{radish}
{wasabi}
";
let (slice, hashmap, vals) = make_values!(
"artichoke" => "Abiu",
"aubergine" => "Açaí",
"asparagus" => "Acerola",
"broccoflower" => "Akebi",
"broccoli" => "Ackee",
"brussels sprouts" => "African Cherry Orange",
"cabbage" => "American Mayapple",
"kohlrabi" => "Apple",
"Savoy cabbage" => "Apricot",
"red cabbage" => "Araza",
"cauliflower" => "Avocado",
"celery" => "Banana",
"endive" => "Bilberry",
"fiddleheads" => "Blackberry",
"frisee" => "Blackcurrant",
"fennel" => "Black sapote",
"greens" => "Blueberry",
"arugula" => "Boysenberry",
"bok choy" => "Breadfruit",
"chard" => "Buddha's hand",
"collard greens" => "Cactus pear",
"kale" => "Canistel",
"lettuce" => "Cashew",
"mustard greens" => "Cempedak",
"spinach" => "Cherimoya",
"herbs" => "Cherry",
"anise" => "Chico fruit",
"basil" => "Cloudberry",
"caraway" => "Coco de mer",
"coriander" => "Coconut",
"chamomile" => "Crab apple",
"daikon" => "Cranberry",
"dill" => "Currant",
"squash" => "Damson",
"lavender" => "Date",
"cymbopogon" => "Dragonfruit",
"marjoram" => "Pitaya",
"oregano" => "Durian",
"parsley" => "Elderberry",
"rosemary" => "Feijoa",
"thyme" => "Fig",
"legumes" => "Finger Lime",
"alfalfa sprouts" => "Caviar Lime",
"azuki beans" => "Goji berry",
"bean sprouts" => "Gooseberry",
"black beans" => "Grape",
"black-eyed peas" => "Raisin",
"borlotti bean" => "Grapefruit",
"broad beans" => "Grewia asiatica",
"chickpeas, garbanzos, or ceci beans" => "Guava",
"green beans" => "Hala Fruit",
"kidney beans" => "Honeyberry",
"lentils" => "Huckleberry",
"lima beans or butter bean" => "Jabuticaba",
"mung beans" => "Jackfruit",
"navy beans" => "Jambul",
"peanuts" => "Japanese plum",
"pinto beans" => "Jostaberry",
"runner beans" => "Jujube",
"split peas" => "Juniper berry",
"soy beans" => "Kaffir Lime",
"peas" => "Kiwano",
"mange tout or snap peas" => "Kiwifruit",
"mushrooms" => "Kumquat",
"nettles" => "Lemon",
"New Zealand spinach" => "Lime",
"okra" => "Loganberry",
"onions" => "Longan",
"chives" => "Loquat",
"garlic" => "Lulo",
"leek" => "Lychee",
"onion" => "Magellan Barberry",
"shallot" => "Mamey Apple",
"scallion" => "Mamey Sapote",
"peppers" => "Mango",
"bell pepper" => "Mangosteen",
"chili pepper" => "Marionberry",
"jalapeño" => "Melon",
"habanero" => "Cantaloupe",
"paprika" => "Galia melon",
"tabasco pepper" => "Honeydew",
"cayenne pepper" => "Mouse melon",
"radicchio" => "Musk melon",
"rhubarb" => "Watermelon",
"root vegetables" => "Miracle fruit",
"beetroot" => "Momordica fruit",
"beet" => "Monstera deliciosa",
"mangelwurzel" => "Mulberry",
"carrot" => "Nance",
"celeriac" => "Nectarine",
"corms" => "Orange",
"eddoe" => "Blood orange",
"konjac" => "Clementine",
"taro" => "Mandarine",
"water chestnut" => "Tangerine",
"ginger" => "Papaya",
"parsnip" => "Passionfruit",
"rutabaga" => "Pawpaw",
"radish" => "Peach",
"wasabi" => "Pear"
);
inner_bench("many replaces", c, TEMPLATE, vals, hashmap, slice);
}
fn inner_bench<F>(
name: &str,
c: &mut Criterion,
template_str: &str,
vals: ValuesFn<F>,
hashmap: HashMap<&str, &str>,
slice: &[(&str, &str)],
) where
F: for<'s> Fn(&'s str) -> Option<Cow<'s, str>> + Send + 'static,
{
c.bench_function(&format!("{name}, fn"), |b| {
b.iter(|| {
let template = Template::parse(black_box(template_str)).unwrap();
black_box(template.render(&vals).unwrap());
})
});
c.bench_function(&format!("{name}, hashmap"), |b| {
b.iter(|| {
let template = Template::parse(black_box(template_str)).unwrap();
black_box(template.render(&hashmap).unwrap());
})
});
c.bench_function(&format!("{name}, slice"), |b| {
b.iter(|| {
let template = Template::parse(black_box(template_str)).unwrap();
black_box(template.render(&slice as &dyn Values).unwrap());
})
});
}
criterion_group!(one, one_replace);
criterion_group!(some, some_replaces);
criterion_group!(many, many_replaces);
criterion_main!(one, some, many);