Merge commit 'b5d0354' into stable
This commit is contained in:
commit
5187e57ad3
|
@ -14,6 +14,10 @@ matrix:
|
||||||
- os: linux
|
- os: linux
|
||||||
rust: nightly
|
rust: nightly
|
||||||
|
|
||||||
|
# minimum supported version
|
||||||
|
- os: linux
|
||||||
|
rust: 1.42.0
|
||||||
|
|
||||||
- os: osx
|
- os: osx
|
||||||
rust: stable
|
rust: stable
|
||||||
|
|
||||||
|
|
|
@ -429,16 +429,6 @@ dependencies = [
|
||||||
"syn 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "examples"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"actix-rt 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"actix-web 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"sailfish 0.1.0",
|
|
||||||
"sailfish-macros 0.1.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "failure"
|
name = "failure"
|
||||||
version = "0.1.8"
|
version = "0.1.8"
|
||||||
|
@ -671,11 +661,11 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "integration-tests"
|
name = "integration-tests"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"sailfish 0.1.0",
|
"sailfish 0.1.1",
|
||||||
"sailfish-macros 0.1.0",
|
"sailfish-macros 0.1.1",
|
||||||
"trybuild 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)",
|
"trybuild 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1050,14 +1040,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sailfish"
|
name = "sailfish"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sailfish-compiler"
|
name = "sailfish-compiler"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1067,12 +1058,22 @@ dependencies = [
|
||||||
"yaml-rust 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"yaml-rust 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sailfish-examples"
|
||||||
|
version = "0.1.1"
|
||||||
|
dependencies = [
|
||||||
|
"actix-rt 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"actix-web 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"sailfish 0.1.1",
|
||||||
|
"sailfish-macros 0.1.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sailfish-macros"
|
name = "sailfish-macros"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"sailfish-compiler 0.1.0",
|
"sailfish-compiler 0.1.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1347,6 +1348,11 @@ dependencies = [
|
||||||
"percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.9.0+wasi-snapshot-preview1"
|
version = "0.9.0+wasi-snapshot-preview1"
|
||||||
|
@ -1561,6 +1567,7 @@ dependencies = [
|
||||||
"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
|
"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
|
||||||
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
||||||
"checksum url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb"
|
"checksum url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb"
|
||||||
|
"checksum version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
|
||||||
"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||||
"checksum widestring 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "effc0e4ff8085673ea7b9b2e3c73f6bd4d118810c9009ed8f1e16bd96c331db6"
|
"checksum widestring 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "effc0e4ff8085673ea7b9b2e3c73f6bd4d118810c9009ed8f1e16bd96c331db6"
|
||||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||||
|
|
|
@ -22,6 +22,7 @@ Simple, small, and extremely fast template engine for Rust
|
||||||
- Template rendering is always type-safe because templates are statically compiled.
|
- Template rendering is always type-safe because templates are statically compiled.
|
||||||
- Syntax highlighting support ([vscode](./syntax/vscode), [vim](./syntax/vim))
|
- Syntax highlighting support ([vscode](./syntax/vscode), [vim](./syntax/vim))
|
||||||
- Automatically re-compile sources when template file is updated.
|
- Automatically re-compile sources when template file is updated.
|
||||||
|
- Works on Rust 1.42 or later
|
||||||
|
|
||||||
## 🐟 Example
|
## 🐟 Example
|
||||||
|
|
||||||
|
@ -29,8 +30,8 @@ Dependencies:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
sailfish = "0.1.0"
|
sailfish = "0.1.1"
|
||||||
sailfish-macros = "0.1.0"
|
sailfish-macros = "0.1.1"
|
||||||
```
|
```
|
||||||
|
|
||||||
Template file (templates/hello.stpl):
|
Template file (templates/hello.stpl):
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2,18 +2,31 @@
|
||||||
name = "benches"
|
name = "benches"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Dirkjan Ochtman <dirkjan@ochtman.nl>", "Ryohei Machida <orcinus4627@gmail.com>"]
|
authors = ["Dirkjan Ochtman <dirkjan@ochtman.nl>", "Ryohei Machida <orcinus4627@gmail.com>"]
|
||||||
|
build = "src/build.rs"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
horrorshow = "0.8.3"
|
askama = { git = "https://github.com/djc/askama" }
|
||||||
markup = "0.4.1"
|
criterion = "0.3"
|
||||||
askama = "0.9.0"
|
fomat-macros = { git = "https://github.com/krdln/fomat-macros" }
|
||||||
criterion = "0.3.2"
|
handlebars = { git = "https://github.com/sunng87/handlebars-rust" }
|
||||||
yarte = { version = "0.9.8", features = ["fixed"] }
|
horrorshow = { git = "https://github.com/Stebalien/horrorshow-rs" }
|
||||||
|
liquid = "0.19.0"
|
||||||
|
markup = { git = "https://github.com/utkarshkukreti/markup.rs" }
|
||||||
|
maud = "0.21.0"
|
||||||
|
ramhorns = { git = "https://github.com/maciejhirsz/ramhorns" }
|
||||||
sailfish = { path = "../sailfish" }
|
sailfish = { path = "../sailfish" }
|
||||||
sailfish-macros = { path = "../sailfish-macros" }
|
sailfish-macros = { path = "../sailfish-macros" }
|
||||||
fomat-macros = "0.3.1"
|
serde = "1"
|
||||||
|
serde_derive = "1"
|
||||||
|
serde_json = "1"
|
||||||
|
serde_yaml = "0.8"
|
||||||
|
tera = { git = "https://github.com/Keats/tera" }
|
||||||
|
yarte = { git = "https://github.com/botika/yarte", features = ["bytes_buff"] }
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
ructe = { git = "https://github.com/kaj/ructe" }
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "all"
|
name = "all"
|
||||||
|
|
|
@ -6,9 +6,15 @@ Performance comparison of template engines for Rust based on [criterion](https:/
|
||||||
|
|
||||||
- [askama](https://github.com/djc/askama): Type-safe, compiled Jinja-like templates for Rust
|
- [askama](https://github.com/djc/askama): Type-safe, compiled Jinja-like templates for Rust
|
||||||
- [fomat](https://github.com/krdln/fomat-macros): Alternative syntax for printing macros in Rust
|
- [fomat](https://github.com/krdln/fomat-macros): Alternative syntax for printing macros in Rust
|
||||||
|
- [handlebars](https://github.com/sunng87/handlebars-rust): Handlebars templating language implemented in Rust and for Rust.
|
||||||
- [horrorshow](https://github.com/Stebalien/horrorshow-rs): A macro-based html builder for rust
|
- [horrorshow](https://github.com/Stebalien/horrorshow-rs): A macro-based html builder for rust
|
||||||
|
- [liquid](https://github.com/cobalt-org/liquid-rust): the liquid templating language for Rust
|
||||||
- [markup](https://github.com/utkarshkukreti/markup.rs): A blazing fast, type-safe template engine for Rust.
|
- [markup](https://github.com/utkarshkukreti/markup.rs): A blazing fast, type-safe template engine for Rust.
|
||||||
|
- [maud](https://github.com/lambda-fairy/maud): Compile-time HTML templates for Rust
|
||||||
|
- [ramhorns](https://github.com/maciejhirsz/ramhorns): Fast Mustache template engine implementation in pure Rust
|
||||||
|
- [ructe](https://github.com/kaj/ructe): Rust Compiled Templates with static-file handling
|
||||||
- [std::write!](https://doc.rust-lang.org/std/macro.write.html): the std library `write!` macro
|
- [std::write!](https://doc.rust-lang.org/std/macro.write.html): the std library `write!` macro
|
||||||
|
- [tera](https://github.com/Keats/tera): A template engine for Rust based on Jinja2/Django
|
||||||
- [yarte](https://github.com/botika/yarte): Yet Another Rust Template Engine, is the fastest template engine
|
- [yarte](https://github.com/botika/yarte): Yet Another Rust Template Engine, is the fastest template engine
|
||||||
- [sailfish](https://github.com/Kogia-sima/sailfish): Simple, small, and extremely fast template engine for Rust
|
- [sailfish](https://github.com/Kogia-sima/sailfish): Simple, small, and extremely fast template engine for Rust
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,26 @@
|
||||||
use criterion::{criterion_group, criterion_main, Criterion};
|
|
||||||
use benches::{
|
use benches::{
|
||||||
askama_bench, fomat, horrorshow_bench, markup_bench, sailfish, std_write, yarte_bench, yarte_fixed
|
askama_bench, fomat, handlebars, horrorshow_bench, liquid, markup_bench, maud_bench,
|
||||||
|
ramhorns, ructe, sailfish, std_write, tera, yarte_bench, yarte_bytes, yarte_fixed,
|
||||||
};
|
};
|
||||||
|
use criterion::{criterion_group, criterion_main, Criterion};
|
||||||
|
|
||||||
fn big_table(c: &mut Criterion) {
|
fn big_table(c: &mut Criterion) {
|
||||||
let mut g = c.benchmark_group("Big table");
|
let mut g = c.benchmark_group("Big table");
|
||||||
g.bench_function("Askama", |b| askama_bench::big_table(b, &100));
|
g.bench_function("Askama", |b| askama_bench::big_table(b, &100));
|
||||||
g.bench_function("fomat", |b| fomat::big_table(b, &100));
|
g.bench_function("fomat", |b| fomat::big_table(b, &100));
|
||||||
|
g.bench_function("Handlebars", |b| handlebars::big_table(b, &100));
|
||||||
g.bench_function("Horrorshow", |b| horrorshow_bench::big_table(b, &100));
|
g.bench_function("Horrorshow", |b| horrorshow_bench::big_table(b, &100));
|
||||||
|
g.bench_function("Liquid", |b| liquid::big_table(b, &100));
|
||||||
g.bench_function("Markup", |b| markup_bench::big_table(b, &100));
|
g.bench_function("Markup", |b| markup_bench::big_table(b, &100));
|
||||||
|
g.bench_function("Maud", |b| maud_bench::big_table(b, &100));
|
||||||
|
g.bench_function("Ramhorns", |b| ramhorns::big_table(b, &100));
|
||||||
|
g.bench_function("Ructe", |b| ructe::big_table(b, &100));
|
||||||
|
g.bench_function("Sailfish", |b| sailfish::big_table(b, &100));
|
||||||
|
g.bench_function("Tera", |b| tera::big_table(b, &100));
|
||||||
g.bench_function("Yarte", |b| yarte_bench::big_table(b, &100));
|
g.bench_function("Yarte", |b| yarte_bench::big_table(b, &100));
|
||||||
g.bench_function("Yarte Fixed", |b| yarte_fixed::big_table(b, &100));
|
g.bench_function("Yarte Send", |b| yarte_bytes::big_table(b, &100));
|
||||||
|
g.bench_function("Yarte ?Send", |b| yarte_fixed::big_table(b, &100));
|
||||||
g.bench_function("write", |b| std_write::big_table(b, &100));
|
g.bench_function("write", |b| std_write::big_table(b, &100));
|
||||||
g.bench_function("sailfish", |b| sailfish::big_table(b, &100));
|
|
||||||
g.finish();
|
g.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,12 +28,19 @@ fn teams(c: &mut Criterion) {
|
||||||
let mut g = c.benchmark_group("Teams");
|
let mut g = c.benchmark_group("Teams");
|
||||||
g.bench_function("Askama", |b| askama_bench::teams(b, &0));
|
g.bench_function("Askama", |b| askama_bench::teams(b, &0));
|
||||||
g.bench_function("fomat", |b| fomat::teams(b, &0));
|
g.bench_function("fomat", |b| fomat::teams(b, &0));
|
||||||
|
g.bench_function("Handlebars", |b| handlebars::teams(b, &0));
|
||||||
g.bench_function("Horrorshow", |b| horrorshow_bench::teams(b, &0));
|
g.bench_function("Horrorshow", |b| horrorshow_bench::teams(b, &0));
|
||||||
|
g.bench_function("Liquid", |b| liquid::teams(b, &0));
|
||||||
g.bench_function("Markup", |b| markup_bench::teams(b, &0));
|
g.bench_function("Markup", |b| markup_bench::teams(b, &0));
|
||||||
|
g.bench_function("Maud", |b| maud_bench::teams(b, &0));
|
||||||
|
g.bench_function("Ramhorns", |b| ramhorns::teams(b));
|
||||||
|
g.bench_function("Ructe", |b| ructe::teams(b, &0));
|
||||||
|
g.bench_function("Sailfish", |b| sailfish::teams(b));
|
||||||
|
g.bench_function("Tera", |b| tera::teams(b, &0));
|
||||||
g.bench_function("Yarte", |b| yarte_bench::teams(b));
|
g.bench_function("Yarte", |b| yarte_bench::teams(b));
|
||||||
g.bench_function("Yarte Fixed", |b| yarte_fixed::teams(b));
|
g.bench_function("Yarte Send", |b| yarte_bytes::teams(b));
|
||||||
|
g.bench_function("Yarte ?Send", |b| yarte_fixed::teams(b));
|
||||||
g.bench_function("write", |b| std_write::teams(b, &0));
|
g.bench_function("write", |b| std_write::teams(b, &0));
|
||||||
g.bench_function("sailfish", |b| sailfish::teams(b));
|
|
||||||
g.finish();
|
g.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 45 KiB |
|
@ -0,0 +1,89 @@
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
use ::handlebars::{to_json, Handlebars};
|
||||||
|
use criterion;
|
||||||
|
use serde::Serialize;
|
||||||
|
use serde_json;
|
||||||
|
use serde_json::value::Value as Json;
|
||||||
|
|
||||||
|
pub fn big_table(b: &mut criterion::Bencher<'_>, size: &usize) {
|
||||||
|
let mut table = Vec::with_capacity(*size);
|
||||||
|
for _ in 0..*size {
|
||||||
|
let mut inner = Vec::with_capacity(*size);
|
||||||
|
for i in 0..*size {
|
||||||
|
inner.push(i);
|
||||||
|
}
|
||||||
|
table.push(inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
let ctx = BigTable { table };
|
||||||
|
let mut handlebars = Handlebars::new();
|
||||||
|
handlebars
|
||||||
|
.register_template_string("big-table.html", SOURCE)
|
||||||
|
.unwrap();
|
||||||
|
b.iter(|| handlebars.render("big-table.html", &ctx).ok().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct BigTable {
|
||||||
|
table: Vec<Vec<usize>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
static SOURCE: &'static str = "<html>
|
||||||
|
{{#each table as |n|}}
|
||||||
|
<tr>{{#each n as |v|}}<td>{{v}}</td>{{/each}}</tr>
|
||||||
|
{{/each}}
|
||||||
|
</html>";
|
||||||
|
|
||||||
|
pub fn teams(b: &mut criterion::Bencher<'_>, _: &usize) {
|
||||||
|
let mut handlebars = Handlebars::new();
|
||||||
|
handlebars
|
||||||
|
.register_template_string("table", TEAMS_TEMPLATE)
|
||||||
|
.ok()
|
||||||
|
.expect("Invalid template format");
|
||||||
|
|
||||||
|
let data = teams_data();
|
||||||
|
b.iter(|| handlebars.render("table", &data).ok().unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn teams_data() -> BTreeMap<String, Json> {
|
||||||
|
let mut data = BTreeMap::new();
|
||||||
|
|
||||||
|
data.insert("year".to_string(), to_json(&"2015".to_owned()));
|
||||||
|
|
||||||
|
let mut teams = Vec::new();
|
||||||
|
|
||||||
|
for v in vec![
|
||||||
|
("Jiangsu", 43u16),
|
||||||
|
("Beijing", 27u16),
|
||||||
|
("Guangzhou", 22u16),
|
||||||
|
("Shandong", 12u16),
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
{
|
||||||
|
let (name, score) = *v;
|
||||||
|
let mut t = BTreeMap::new();
|
||||||
|
t.insert("name".to_string(), to_json(&name));
|
||||||
|
t.insert("score".to_string(), to_json(&score));
|
||||||
|
teams.push(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
data.insert("teams".to_string(), to_json(&teams));
|
||||||
|
data
|
||||||
|
}
|
||||||
|
|
||||||
|
static TEAMS_TEMPLATE: &'static str = "<html>
|
||||||
|
<head>
|
||||||
|
<title>{{year}}</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>CSL {{year}}</h1>
|
||||||
|
<ul>
|
||||||
|
{{#each teams}}
|
||||||
|
<li class=\"{{#if @first}}champion{{/if}}\">
|
||||||
|
<b>{{name}}</b>: {{score}}
|
||||||
|
</li>
|
||||||
|
{{/each}}
|
||||||
|
</ul>
|
||||||
|
</body>
|
||||||
|
</html>";
|
|
@ -1,8 +1,19 @@
|
||||||
|
#![feature(proc_macro_hygiene)]
|
||||||
|
|
||||||
pub mod askama_bench;
|
pub mod askama_bench;
|
||||||
pub mod fomat;
|
pub mod fomat;
|
||||||
|
pub mod handlebars;
|
||||||
pub mod horrorshow_bench;
|
pub mod horrorshow_bench;
|
||||||
|
pub mod liquid;
|
||||||
pub mod markup_bench;
|
pub mod markup_bench;
|
||||||
|
pub mod maud_bench;
|
||||||
|
pub mod ramhorns;
|
||||||
|
pub mod ructe;
|
||||||
pub mod sailfish;
|
pub mod sailfish;
|
||||||
pub mod std_write;
|
pub mod std_write;
|
||||||
|
pub mod tera;
|
||||||
pub mod yarte_bench;
|
pub mod yarte_bench;
|
||||||
|
pub mod yarte_bytes;
|
||||||
pub mod yarte_fixed;
|
pub mod yarte_fixed;
|
||||||
|
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/templates.rs"));
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
use ::liquid::{
|
||||||
|
value::{Object, Value},
|
||||||
|
ParserBuilder,
|
||||||
|
};
|
||||||
|
use criterion;
|
||||||
|
use serde_yaml;
|
||||||
|
|
||||||
|
pub fn big_table(b: &mut criterion::Bencher<'_>, size: &usize) {
|
||||||
|
let mut table = Vec::with_capacity(*size);
|
||||||
|
for _ in 0..*size {
|
||||||
|
let mut inner = Vec::with_capacity(*size);
|
||||||
|
for i in 0..*size {
|
||||||
|
inner.push(Value::Scalar((i as i32).into()));
|
||||||
|
}
|
||||||
|
table.push(Value::Array(inner));
|
||||||
|
}
|
||||||
|
|
||||||
|
let template = ParserBuilder::with_liquid()
|
||||||
|
.build()
|
||||||
|
.unwrap()
|
||||||
|
.parse(
|
||||||
|
"<table>
|
||||||
|
{% for row in table %}
|
||||||
|
<tr>{% for col in row %}<td>{{ col|escape }}</td>{% endfor %}</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut globals = Object::new();
|
||||||
|
globals.insert("table".into(), Value::Array(table));
|
||||||
|
|
||||||
|
b.iter(|| template.render(&globals));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn teams(b: &mut criterion::Bencher<'_>, _: &usize) {
|
||||||
|
let parser = ParserBuilder::with_liquid()
|
||||||
|
.extra_filters()
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
let template = parser.parse(TEAMS_TEMPLATE).unwrap();
|
||||||
|
|
||||||
|
let data: Object = self::serde_yaml::from_str(TEAMS_DATA).unwrap();
|
||||||
|
|
||||||
|
b.iter(|| template.render(&data));
|
||||||
|
}
|
||||||
|
|
||||||
|
static TEAMS_TEMPLATE: &'static str = "<html>
|
||||||
|
<head>
|
||||||
|
<title>{{year}}</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>CSL {{year}}</h1>
|
||||||
|
<ul>
|
||||||
|
{% for team in teams %}
|
||||||
|
<li class=\"{% if forloop.first %}champion{% endif %}\">
|
||||||
|
<b>{{team.name}}</b>: {{team.score}}
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</body>
|
||||||
|
</html>";
|
||||||
|
|
||||||
|
static TEAMS_DATA: &'static str = "
|
||||||
|
year: 2015
|
||||||
|
teams:
|
||||||
|
- name: Jiangsu
|
||||||
|
score: 43
|
||||||
|
- name: Beijing
|
||||||
|
score: 27
|
||||||
|
- name: Guangzhou
|
||||||
|
score: 22
|
||||||
|
- name: Shandong
|
||||||
|
score: 12
|
||||||
|
";
|
|
@ -0,0 +1,92 @@
|
||||||
|
use criterion;
|
||||||
|
|
||||||
|
use maud::html;
|
||||||
|
|
||||||
|
pub fn big_table(b: &mut criterion::Bencher, size: &usize) {
|
||||||
|
let mut table = Vec::with_capacity(*size);
|
||||||
|
for _ in 0..*size {
|
||||||
|
let mut inner = Vec::with_capacity(*size);
|
||||||
|
for i in 0..*size {
|
||||||
|
inner.push(i);
|
||||||
|
}
|
||||||
|
table.push(inner);
|
||||||
|
}
|
||||||
|
b.iter(|| big_table_render(&table));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn big_table_render(table: &Vec<Vec<usize>>) -> String {
|
||||||
|
let page = html! {
|
||||||
|
table {
|
||||||
|
@for row in table {
|
||||||
|
tr {
|
||||||
|
@for col in row {
|
||||||
|
td { (col) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
page.into_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn teams(b: &mut criterion::Bencher, _: &usize) {
|
||||||
|
let teams = Teams {
|
||||||
|
year: 2015,
|
||||||
|
teams: vec![
|
||||||
|
Team {
|
||||||
|
name: "Jiangsu".into(),
|
||||||
|
score: 43,
|
||||||
|
},
|
||||||
|
Team {
|
||||||
|
name: "Beijing".into(),
|
||||||
|
score: 27,
|
||||||
|
},
|
||||||
|
Team {
|
||||||
|
name: "Guangzhou".into(),
|
||||||
|
score: 22,
|
||||||
|
},
|
||||||
|
Team {
|
||||||
|
name: "Shandong".into(),
|
||||||
|
score: 12,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
b.iter(|| teams_render(&teams));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn teams_render(teams: &Teams) -> String {
|
||||||
|
let page = html! {
|
||||||
|
html {
|
||||||
|
head {
|
||||||
|
title { (teams.year) }
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
h1 {
|
||||||
|
"CSL "
|
||||||
|
(teams.year)
|
||||||
|
}
|
||||||
|
ul {
|
||||||
|
@for (idx, team) in teams.teams.iter().enumerate() {
|
||||||
|
li.champion[idx == 0] {
|
||||||
|
b { (&team.name) }
|
||||||
|
": "
|
||||||
|
(team.score)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
page.into_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Teams {
|
||||||
|
year: u16,
|
||||||
|
teams: Vec<Team>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Team {
|
||||||
|
name: String,
|
||||||
|
score: u8,
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
use ramhorns::{Template, Content};
|
||||||
|
|
||||||
|
pub fn big_table(b: &mut criterion::Bencher<'_>, size: &usize) {
|
||||||
|
let mut table = Vec::with_capacity(*size);
|
||||||
|
for _ in 0..*size {
|
||||||
|
let mut inner = Vec::with_capacity(*size);
|
||||||
|
for i in 0..*size {
|
||||||
|
inner.push(i);
|
||||||
|
}
|
||||||
|
table.push(inner);
|
||||||
|
}
|
||||||
|
let tpl = Template::new(SOURCE).unwrap();
|
||||||
|
let ctx = BigTable { table };
|
||||||
|
b.iter(|| {
|
||||||
|
tpl.render(&ctx)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Content)]
|
||||||
|
struct BigTable {
|
||||||
|
table: Vec<Vec<usize>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
static SOURCE: &'static str = "<html>
|
||||||
|
{{#table}}
|
||||||
|
<tr>{{#.}}<td>{{.}}</td>{{/.}}</tr>
|
||||||
|
{{/table}}
|
||||||
|
</html>";
|
||||||
|
|
||||||
|
pub fn teams(b: &mut criterion::Bencher<'_>) {
|
||||||
|
let tpl = Template::new(TEAMS_TEMPLATE).unwrap();
|
||||||
|
let teams = Teams {
|
||||||
|
year: 2015,
|
||||||
|
teams: vec![
|
||||||
|
Team {
|
||||||
|
name: "Jiangsu".into(),
|
||||||
|
class: "champion".into(),
|
||||||
|
score: 43,
|
||||||
|
},
|
||||||
|
Team {
|
||||||
|
name: "Beijing".into(),
|
||||||
|
class: String::new(),
|
||||||
|
score: 27,
|
||||||
|
},
|
||||||
|
Team {
|
||||||
|
name: "Guangzhou".into(),
|
||||||
|
class: String::new(),
|
||||||
|
score: 22,
|
||||||
|
},
|
||||||
|
Team {
|
||||||
|
name: "Shandong".into(),
|
||||||
|
class: String::new(),
|
||||||
|
score: 12,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
b.iter(|| {
|
||||||
|
tpl.render(&teams)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Content)]
|
||||||
|
struct Teams {
|
||||||
|
year: u16,
|
||||||
|
teams: Vec<Team>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Content)]
|
||||||
|
struct Team {
|
||||||
|
name: String,
|
||||||
|
class: String,
|
||||||
|
score: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
static TEAMS_TEMPLATE: &'static str = "<html>
|
||||||
|
<head>
|
||||||
|
<title>{{year}}</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>CSL {{year}}</h1>
|
||||||
|
<ul>
|
||||||
|
{{#teams}}
|
||||||
|
<li class=\"{{class}}\">
|
||||||
|
<b>{{name}}</b>: {{score}}
|
||||||
|
</li>
|
||||||
|
{{/teams}}
|
||||||
|
</ul>
|
||||||
|
</body>
|
||||||
|
</html>";
|
|
@ -0,0 +1,48 @@
|
||||||
|
use crate::templates;
|
||||||
|
use criterion;
|
||||||
|
|
||||||
|
pub fn big_table(b: &mut criterion::Bencher<'_>, size: &usize) {
|
||||||
|
let mut table = Vec::with_capacity(*size);
|
||||||
|
for _ in 0..*size {
|
||||||
|
let mut inner = Vec::with_capacity(*size);
|
||||||
|
for i in 0..*size {
|
||||||
|
inner.push(i);
|
||||||
|
}
|
||||||
|
table.push(inner);
|
||||||
|
}
|
||||||
|
b.iter(|| {
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
templates::big_table(&mut buf, &table).unwrap();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn teams(b: &mut criterion::Bencher<'_>, _: &usize) {
|
||||||
|
let year = 2015;
|
||||||
|
let teams = vec![
|
||||||
|
Team {
|
||||||
|
name: "Jiangsu".into(),
|
||||||
|
score: 43,
|
||||||
|
},
|
||||||
|
Team {
|
||||||
|
name: "Beijing".into(),
|
||||||
|
score: 27,
|
||||||
|
},
|
||||||
|
Team {
|
||||||
|
name: "Guangzhou".into(),
|
||||||
|
score: 22,
|
||||||
|
},
|
||||||
|
Team {
|
||||||
|
name: "Shandong".into(),
|
||||||
|
score: 12,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
b.iter(|| {
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
templates::teams(&mut buf, year, &teams).unwrap();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Team {
|
||||||
|
pub name: String,
|
||||||
|
pub score: u8,
|
||||||
|
}
|
|
@ -42,7 +42,7 @@ pub fn teams(b: &mut criterion::Bencher<'_>) {
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let teams = TeamsTemplate {
|
let teams = TeamsTemplate {
|
||||||
year: teams.year,
|
year: teams.year,
|
||||||
teams: &teams.teams
|
teams: &teams.teams,
|
||||||
};
|
};
|
||||||
teams.render_once().unwrap()
|
teams.render_once().unwrap()
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
use ::tera::{Context, Tera};
|
||||||
|
use criterion;
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
pub fn big_table(b: &mut criterion::Bencher<'_>, size: &usize) {
|
||||||
|
let mut table = Vec::with_capacity(*size);
|
||||||
|
for _ in 0..*size {
|
||||||
|
let mut inner = Vec::with_capacity(*size);
|
||||||
|
for i in 0..*size {
|
||||||
|
inner.push(i);
|
||||||
|
}
|
||||||
|
table.push(inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut tera = Tera::default();
|
||||||
|
tera.add_raw_templates(vec![("big-table.html", BIG_TABLE_TEMPLATE)])
|
||||||
|
.unwrap();
|
||||||
|
let mut ctx = Context::new();
|
||||||
|
ctx.insert("table", &table);
|
||||||
|
|
||||||
|
let _ = tera.render("big-table.html", &ctx).unwrap();
|
||||||
|
b.iter(|| tera.render("big-table.html", &ctx));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct Team {
|
||||||
|
name: String,
|
||||||
|
score: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tera doesn't allow `escape` on number values
|
||||||
|
static BIG_TABLE_TEMPLATE: &'static str = "<table>
|
||||||
|
{% for row in table %}
|
||||||
|
<tr>{% for col in row %}<td>{{ col }}</td>{% endfor %}</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>";
|
||||||
|
|
||||||
|
pub fn teams(b: &mut criterion::Bencher<'_>, _: &usize) {
|
||||||
|
let mut tera = Tera::default();
|
||||||
|
tera.add_raw_templates(vec![("teams.html", TEAMS_TEMPLATE)])
|
||||||
|
.unwrap();
|
||||||
|
let mut ctx = Context::new();
|
||||||
|
ctx.insert("year", &2015);
|
||||||
|
ctx.insert(
|
||||||
|
"teams",
|
||||||
|
&vec![
|
||||||
|
Team {
|
||||||
|
name: "Jiangsu".into(),
|
||||||
|
score: 43,
|
||||||
|
},
|
||||||
|
Team {
|
||||||
|
name: "Beijing".into(),
|
||||||
|
score: 27,
|
||||||
|
},
|
||||||
|
Team {
|
||||||
|
name: "Guangzhou".into(),
|
||||||
|
score: 22,
|
||||||
|
},
|
||||||
|
Team {
|
||||||
|
name: "Shandong".into(),
|
||||||
|
score: 12,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
let _ = tera.render("teams.html", &ctx).unwrap();
|
||||||
|
b.iter(|| tera.render("teams.html", &ctx));
|
||||||
|
}
|
||||||
|
|
||||||
|
static TEAMS_TEMPLATE: &'static str = "<html>
|
||||||
|
<head>
|
||||||
|
<title>{{ year }}</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>CSL {{ year }}</h1>
|
||||||
|
<ul>
|
||||||
|
{% for team in teams %}
|
||||||
|
<li class=\"{% if loop.first %}champion{% endif %}\">
|
||||||
|
<b>{{team.name}}</b>: {{team.score}}
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</body>
|
||||||
|
</html>";
|
|
@ -0,0 +1,58 @@
|
||||||
|
use yarte::TemplateBytes;
|
||||||
|
|
||||||
|
pub fn big_table(b: &mut criterion::Bencher<'_>, size: &usize) {
|
||||||
|
let mut table = Vec::with_capacity(*size);
|
||||||
|
for _ in 0..*size {
|
||||||
|
let mut inner = Vec::with_capacity(*size);
|
||||||
|
for i in 0..*size {
|
||||||
|
inner.push(i);
|
||||||
|
}
|
||||||
|
table.push(inner);
|
||||||
|
}
|
||||||
|
let t = BigTable { table };
|
||||||
|
b.iter(|| t.call(109915).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(TemplateBytes)]
|
||||||
|
#[template(path = "big-table")]
|
||||||
|
struct BigTable {
|
||||||
|
table: Vec<Vec<usize>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn teams(b: &mut criterion::Bencher<'_>) {
|
||||||
|
let t = Teams {
|
||||||
|
year: 2015,
|
||||||
|
teams: vec![
|
||||||
|
Team {
|
||||||
|
name: "Jiangsu".into(),
|
||||||
|
|
||||||
|
score: 43,
|
||||||
|
},
|
||||||
|
Team {
|
||||||
|
name: "Beijing".into(),
|
||||||
|
score: 27,
|
||||||
|
},
|
||||||
|
Team {
|
||||||
|
name: "Guangzhou".into(),
|
||||||
|
score: 22,
|
||||||
|
},
|
||||||
|
Team {
|
||||||
|
name: "Shandong".into(),
|
||||||
|
score: 12,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
b.iter(|| t.call(239).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(TemplateBytes)]
|
||||||
|
#[template(path = "teams")]
|
||||||
|
struct Teams {
|
||||||
|
year: u16,
|
||||||
|
teams: Vec<Team>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Team {
|
||||||
|
name: String,
|
||||||
|
score: u8,
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
use criterion::black_box;
|
||||||
|
use std::mem::MaybeUninit;
|
||||||
use yarte::TemplateFixed;
|
use yarte::TemplateFixed;
|
||||||
|
|
||||||
pub fn big_table(b: &mut criterion::Bencher<'_>, size: &usize) {
|
pub fn big_table(b: &mut criterion::Bencher<'_>, size: &usize) {
|
||||||
|
@ -9,26 +11,20 @@ pub fn big_table(b: &mut criterion::Bencher<'_>, size: &usize) {
|
||||||
}
|
}
|
||||||
table.push(inner);
|
table.push(inner);
|
||||||
}
|
}
|
||||||
let ctx = BigTable { table };
|
let t = BigTable { table };
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut buf = String::with_capacity(109915);
|
black_box(unsafe { t.call(&mut [MaybeUninit::uninit(); 109915]) }.unwrap());
|
||||||
unsafe {
|
|
||||||
buf.as_mut_vec().set_len(109915);
|
|
||||||
let b = ctx.call(buf.as_bytes_mut()).unwrap();
|
|
||||||
buf.as_mut_vec().set_len(b);
|
|
||||||
}
|
|
||||||
buf
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(TemplateFixed)]
|
#[derive(TemplateFixed)]
|
||||||
#[template(path = "big-table.hbs")]
|
#[template(path = "big-table")]
|
||||||
struct BigTable {
|
struct BigTable {
|
||||||
table: Vec<Vec<usize>>,
|
table: Vec<Vec<usize>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn teams(b: &mut criterion::Bencher<'_>) {
|
pub fn teams(b: &mut criterion::Bencher<'_>) {
|
||||||
let teams = Teams {
|
let t = Teams {
|
||||||
year: 2015,
|
year: 2015,
|
||||||
teams: vec![
|
teams: vec![
|
||||||
Team {
|
Team {
|
||||||
|
@ -51,18 +47,12 @@ pub fn teams(b: &mut criterion::Bencher<'_>) {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut buf = String::with_capacity(239);
|
black_box(unsafe { t.call(&mut [MaybeUninit::uninit(); 239]) }.unwrap());
|
||||||
unsafe {
|
|
||||||
buf.as_mut_vec().set_len(239);
|
|
||||||
let b = teams.call(buf.as_bytes_mut()).unwrap();
|
|
||||||
buf.as_mut_vec().set_len(b);
|
|
||||||
}
|
|
||||||
buf
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(TemplateFixed)]
|
#[derive(TemplateFixed)]
|
||||||
#[template(path = "teams.hbs")]
|
#[template(path = "teams")]
|
||||||
struct Teams {
|
struct Teams {
|
||||||
year: u16,
|
year: u16,
|
||||||
teams: Vec<Team>,
|
teams: Vec<Team>,
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 55 KiB |
|
@ -1 +1 @@
|
||||||
<table>{{#each table}}<tr>{{#each this}}<td>{{ this }}</td>{{/each}}</tr>{{/each}}</table>
|
<table>{{#each table}}<tr>{{#each this}}<td>{{ this }}</td>{{/each }}</tr>{{/each }}</table>
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
<html><head><title>{{ year }}</title></head><body><h1>CSL {{ year }}</h1><ul>{{#each teams }}<li class="{{#if index0 == 0 }}champion{{/if}}"><b>{{ name }}</b>: {{ score }}</li>{{/each}}</ul></body></html>
|
<html><head><title>{{ year }}</title></head><body><h1>CSL {{ year }}</h1><ul>{{#each teams }}<li class="{{#if first }}champion{{/if }}"><b>{{ name }}</b>: {{ score }}</li>{{/each }}</ul></body></html>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<body>
|
<body>
|
||||||
<h1>CSL <%= year %></h1>
|
<h1>CSL <%= year %></h1>
|
||||||
<ul>
|
<ul>
|
||||||
<% for (i, team) in teams.iter().enumerate() { %><li class="<% if i == 0 { %>champion<% } %>"><b><%- team.name %></b>: <%= team.score %></li><% } %>
|
<% for (i, team) in teams.iter().enumerate() { %><li class="<% if i == 0 { %>champion<% } %>"><b><%= team.name %></b>: <%= team.score %></li><% } %>
|
||||||
</ul>
|
</ul>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
@(table: &Vec<Vec<usize>>)
|
||||||
|
|
||||||
|
<table>
|
||||||
|
@for row in table{
|
||||||
|
<tr>
|
||||||
|
@for col in row {
|
||||||
|
<td>@col</td>
|
||||||
|
}
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</table>
|
|
@ -0,0 +1,18 @@
|
||||||
|
@use crate::ructe::Team;
|
||||||
|
@(year: u16, teams: &Vec<Team>)
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>@year</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>CSL @year</h1>
|
||||||
|
<ul>
|
||||||
|
@for (i, team) in teams.iter().enumerate(){
|
||||||
|
<li @if i==0 {class="champion"} else {}>
|
||||||
|
<b>@team.name</b>: @team.score
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -4,8 +4,8 @@ In order to use sailfish templates, you have add two dependencies in your `Cargo
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
sailfish = "0.1.0"
|
sailfish = "0.1.1"
|
||||||
sailfish-macros = "0.1.0"
|
sailfish-macros = "0.1.1"
|
||||||
```
|
```
|
||||||
|
|
||||||
`sailfish` crate contains runtime for rendering contents, and `sailfish-macros` serves you derive macros to compile and import the template files.
|
`sailfish` crate contains runtime for rendering contents, and `sailfish-macros` serves you derive macros to compile and import the template files.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "examples"
|
name = "sailfish-examples"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
authors = ["Ryohei Machida <orcinus4627@gmail.com>"]
|
authors = ["Ryohei Machida <orcinus4627@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
publish = false
|
publish = false
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "integration-tests"
|
name = "integration-tests"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
authors = ["Kogia-sima <orcinus4627@gmail.com>"]
|
authors = ["Kogia-sima <orcinus4627@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
publish = false
|
publish = false
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 5.0 KiB |
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "sailfish-compiler"
|
name = "sailfish-compiler"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
authors = ["Ryohei Machida <orcinus4627@gmail.com>"]
|
authors = ["Ryohei Machida <orcinus4627@gmail.com>"]
|
||||||
description = "Really fast, intuitive template engine for Rust"
|
description = "Really fast, intuitive template engine for Rust"
|
||||||
homepage = "https://github.com/Kogia-sima/sailfish"
|
homepage = "https://github.com/Kogia-sima/sailfish"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "sailfish-macros"
|
name = "sailfish-macros"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
authors = ["Ryohei Machida <orcinus4627@gmail.com>"]
|
authors = ["Ryohei Machida <orcinus4627@gmail.com>"]
|
||||||
description = "Really fast, intuitive template engine for Rust"
|
description = "Really fast, intuitive template engine for Rust"
|
||||||
homepage = "https://github.com/Kogia-sima/sailfish"
|
homepage = "https://github.com/Kogia-sima/sailfish"
|
||||||
|
@ -25,10 +25,10 @@ default = ["config"]
|
||||||
config = ["sailfish-compiler/config"]
|
config = ["sailfish-compiler/config"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
proc-macro2 = "1.0.17"
|
proc-macro2 = "1.0.11"
|
||||||
|
|
||||||
[dependencies.sailfish-compiler]
|
[dependencies.sailfish-compiler]
|
||||||
path = "../sailfish-compiler"
|
path = "../sailfish-compiler"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["procmacro"]
|
features = ["procmacro"]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "sailfish"
|
name = "sailfish"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
authors = ["Ryohei Machida <orcinus4627@gmail.com>"]
|
authors = ["Ryohei Machida <orcinus4627@gmail.com>"]
|
||||||
description = "Really fast, intuitive template engine for Rust"
|
description = "Really fast, intuitive template engine for Rust"
|
||||||
homepage = "https://github.com/Kogia-sima/sailfish"
|
homepage = "https://github.com/Kogia-sima/sailfish"
|
||||||
|
@ -12,5 +12,12 @@ license = "MIT"
|
||||||
workspace = ".."
|
workspace = ".."
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["perf-inline"]
|
||||||
|
perf-inline = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ryu = "1.0.4"
|
ryu = "1.0.4"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
version_check = "0.9.2"
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
fn main() {
|
||||||
|
if version_check::is_feature_flaggable() == Some(true) {
|
||||||
|
println!("cargo:rustc-cfg=sailfish_nightly");
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,6 +34,7 @@
|
||||||
#![doc(
|
#![doc(
|
||||||
html_logo_url = "https://raw.githubusercontent.com/Kogia-sima/sailfish/master/resources/icon.png"
|
html_logo_url = "https://raw.githubusercontent.com/Kogia-sima/sailfish/master/resources/icon.png"
|
||||||
)]
|
)]
|
||||||
|
#![cfg_attr(sailfish_nightly, feature(core_intrinsics))]
|
||||||
|
|
||||||
pub mod runtime;
|
pub mod runtime;
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,20 @@ use std::mem::{align_of, ManuallyDrop};
|
||||||
use std::ops::{Add, AddAssign};
|
use std::ops::{Add, AddAssign};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
|
#[cfg(sailfish_nightly)]
|
||||||
|
macro_rules! unlikely {
|
||||||
|
($val:expr) => {
|
||||||
|
std::intrinsics::unlikely($val)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(sailfish_nightly))]
|
||||||
|
macro_rules! unlikely {
|
||||||
|
($val:expr) => {
|
||||||
|
$val
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// Buffer for rendered contents
|
/// Buffer for rendered contents
|
||||||
///
|
///
|
||||||
/// This struct is quite simular to `String`, but some methods are
|
/// This struct is quite simular to `String`, but some methods are
|
||||||
|
@ -24,7 +38,7 @@ impl Buffer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[cfg_attr(feature = "perf-inline", inline)]
|
||||||
pub fn with_capacity(n: usize) -> Buffer {
|
pub fn with_capacity(n: usize) -> Buffer {
|
||||||
unsafe {
|
unsafe {
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
|
@ -84,14 +98,10 @@ impl Buffer {
|
||||||
self.len == 0
|
self.len == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(never)]
|
#[inline]
|
||||||
pub fn reserve(&mut self, size: usize) {
|
pub fn reserve(&mut self, size: usize) {
|
||||||
if size > self.capacity - self.len {
|
if unlikely!(self.len + size > self.capacity) {
|
||||||
unsafe {
|
self.reserve_internal(size);
|
||||||
let new_capacity = std::cmp::max(self.capacity * 2, self.len + size);
|
|
||||||
self.realloc(new_capacity);
|
|
||||||
self.capacity = new_capacity;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,9 +119,7 @@ impl Buffer {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn push_str(&mut self, data: &str) {
|
pub fn push_str(&mut self, data: &str) {
|
||||||
let size = data.len();
|
let size = data.len();
|
||||||
if size > self.capacity - self.len {
|
self.reserve(size);
|
||||||
self.reserve(size);
|
|
||||||
}
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let p = self.data.add(self.len);
|
let p = self.data.add(self.len);
|
||||||
std::ptr::copy_nonoverlapping(data.as_ptr(), p, size);
|
std::ptr::copy_nonoverlapping(data.as_ptr(), p, size);
|
||||||
|
@ -125,18 +133,31 @@ impl Buffer {
|
||||||
self.push_str(data.encode_utf8(&mut buf));
|
self.push_str(data.encode_utf8(&mut buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn realloc(&mut self, cap: usize) {
|
#[cfg_attr(feature = "perf-inline", inline)]
|
||||||
if self.capacity == 0 {
|
fn reserve_internal(&mut self, size: usize) {
|
||||||
let new_layout = Layout::from_size_align_unchecked(cap, 1);
|
unsafe {
|
||||||
self.data = alloc(new_layout);
|
let new_capacity = std::cmp::max(self.capacity * 2, self.len + size);
|
||||||
} else {
|
self.data = self.realloc(new_capacity);
|
||||||
let old_layout = Layout::from_size_align_unchecked(self.capacity, 1);
|
self.capacity = new_capacity;
|
||||||
self.data = realloc(self.data, old_layout, cap);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if self.data.is_null() {
|
#[cfg_attr(feature = "perf-inline", inline)]
|
||||||
|
unsafe fn realloc(&self, cap: usize) -> *mut u8 {
|
||||||
|
let data = if unlikely!(self.capacity == 0) {
|
||||||
|
let new_layout = Layout::from_size_align_unchecked(cap, 1);
|
||||||
|
alloc(new_layout)
|
||||||
|
} else {
|
||||||
|
debug_assert!(cap <= std::usize::MAX / 2, "capacity is too large");
|
||||||
|
let old_layout = Layout::from_size_align_unchecked(self.capacity, 1);
|
||||||
|
realloc(self.data, old_layout, cap)
|
||||||
|
};
|
||||||
|
|
||||||
|
if data.is_null() {
|
||||||
handle_alloc_error(Layout::from_size_align_unchecked(cap, 1));
|
handle_alloc_error(Layout::from_size_align_unchecked(cap, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,20 +14,20 @@ const VECTOR_BYTES: usize = std::mem::size_of::<__m256i>();
|
||||||
const VECTOR_ALIGN: usize = VECTOR_BYTES - 1;
|
const VECTOR_ALIGN: usize = VECTOR_BYTES - 1;
|
||||||
|
|
||||||
#[target_feature(enable = "avx2")]
|
#[target_feature(enable = "avx2")]
|
||||||
pub unsafe fn escape(buffer: &mut Buffer, bytes: &[u8]) {
|
pub unsafe fn escape(feed: &str, buffer: &mut Buffer) {
|
||||||
let len = bytes.len();
|
let len = feed.len();
|
||||||
|
|
||||||
if len < 8 {
|
if len < 8 {
|
||||||
let start_ptr = bytes.as_ptr();
|
let start_ptr = feed.as_ptr();
|
||||||
let end_ptr = start_ptr.add(len);
|
let end_ptr = start_ptr.add(len);
|
||||||
naive::escape(buffer, start_ptr, start_ptr, end_ptr);
|
naive::escape(buffer, start_ptr, start_ptr, end_ptr);
|
||||||
return;
|
return;
|
||||||
} else if len < VECTOR_BYTES {
|
} else if len < VECTOR_BYTES {
|
||||||
sse2::escape(buffer, bytes);
|
sse2::escape(feed, buffer);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut start_ptr = bytes.as_ptr();
|
let mut start_ptr = feed.as_ptr();
|
||||||
let end_ptr = start_ptr.add(len);
|
let end_ptr = start_ptr.add(len);
|
||||||
|
|
||||||
let v_independent1 = _mm256_set1_epi8(5);
|
let v_independent1 = _mm256_set1_epi8(5);
|
||||||
|
|
|
@ -39,12 +39,12 @@ fn contains_key(x: usize) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn escape(buffer: &mut Buffer, bytes: &[u8]) {
|
pub unsafe fn escape(feed: &str, buffer: &mut Buffer) {
|
||||||
let len = bytes.len();
|
let len = feed.len();
|
||||||
let mut start_ptr = bytes.as_ptr();
|
let mut start_ptr = feed.as_ptr();
|
||||||
let end_ptr = start_ptr.add(len);
|
let end_ptr = start_ptr.add(len);
|
||||||
|
|
||||||
if bytes.len() < USIZE_BYTES {
|
if feed.len() < USIZE_BYTES {
|
||||||
naive::escape(buffer, start_ptr, start_ptr, end_ptr);
|
naive::escape(buffer, start_ptr, start_ptr, end_ptr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,19 @@
|
||||||
//! HTML escaping
|
//! HTML escaping
|
||||||
//!
|
//!
|
||||||
//! By default sailfish replaces the characters `&"<>` with the equivalent html.
|
//! By default sailfish replaces the characters `&"'<>` with the equivalent html.
|
||||||
|
|
||||||
mod avx2;
|
mod avx2;
|
||||||
mod fallback;
|
mod fallback;
|
||||||
mod naive;
|
mod naive;
|
||||||
mod sse2;
|
mod sse2;
|
||||||
|
|
||||||
|
use std::mem;
|
||||||
|
use std::sync::atomic::{AtomicPtr, Ordering};
|
||||||
|
|
||||||
use super::buffer::Buffer;
|
use super::buffer::Buffer;
|
||||||
|
|
||||||
|
type FnRaw = *mut ();
|
||||||
|
|
||||||
static ESCAPE_LUT: [u8; 256] = [
|
static ESCAPE_LUT: [u8; 256] = [
|
||||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||||
9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 1, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 1, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||||
|
@ -25,38 +30,37 @@ static ESCAPE_LUT: [u8; 256] = [
|
||||||
const ESCAPED: [&str; 5] = [""", "&", "'", "<", ">"];
|
const ESCAPED: [&str; 5] = [""", "&", "'", "<", ">"];
|
||||||
const ESCAPED_LEN: usize = 5;
|
const ESCAPED_LEN: usize = 5;
|
||||||
|
|
||||||
|
static FN: AtomicPtr<()> = AtomicPtr::new(escape as FnRaw);
|
||||||
|
|
||||||
#[cfg(target_feature = "avx2")]
|
#[cfg(target_feature = "avx2")]
|
||||||
pub(crate) fn escape_to_buf(feed: &str, buf: &mut Buffer) {
|
pub fn escape(feed: &str, buf: &mut Buffer) {
|
||||||
unsafe { avx2::escape(buf, feed.as_bytes()) }
|
unsafe { avx2::escape(buf, feed.as_bytes()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// default escape function
|
||||||
#[cfg(not(target_feature = "avx2"))]
|
#[cfg(not(target_feature = "avx2"))]
|
||||||
|
pub fn escape(feed: &str, buf: &mut Buffer) {
|
||||||
|
let fun = if is_x86_feature_detected!("avx2") {
|
||||||
|
avx2::escape
|
||||||
|
} else if is_x86_feature_detected!("sse2") {
|
||||||
|
sse2::escape
|
||||||
|
} else {
|
||||||
|
fallback::escape
|
||||||
|
};
|
||||||
|
|
||||||
|
FN.store(fun as FnRaw, Ordering::Relaxed);
|
||||||
|
unsafe { fun(feed, buf) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register_escape_fn(fun: fn(&str, &mut Buffer)) {
|
||||||
|
FN.store(fun as FnRaw, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub(crate) fn escape_to_buf(feed: &str, buf: &mut Buffer) {
|
pub(crate) fn escape_to_buf(feed: &str, buf: &mut Buffer) {
|
||||||
use std::mem;
|
|
||||||
use std::sync::atomic::{AtomicPtr, Ordering};
|
|
||||||
|
|
||||||
type FnRaw = *mut ();
|
|
||||||
|
|
||||||
static FN: AtomicPtr<()> = AtomicPtr::new(detect as FnRaw);
|
|
||||||
|
|
||||||
fn detect(buffer: &mut Buffer, bytes: &[u8]) {
|
|
||||||
let fun = if is_x86_feature_detected!("avx2") {
|
|
||||||
avx2::escape as FnRaw
|
|
||||||
} else if is_x86_feature_detected!("sse2") {
|
|
||||||
sse2::escape as FnRaw
|
|
||||||
} else {
|
|
||||||
fallback::escape as FnRaw
|
|
||||||
};
|
|
||||||
|
|
||||||
FN.store(fun as FnRaw, Ordering::Relaxed);
|
|
||||||
unsafe {
|
|
||||||
mem::transmute::<FnRaw, fn(&mut Buffer, &[u8])>(fun)(buffer, bytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let fun = FN.load(Ordering::Relaxed);
|
let fun = FN.load(Ordering::Relaxed);
|
||||||
mem::transmute::<FnRaw, fn(&mut Buffer, &[u8])>(fun)(buf, feed.as_bytes());
|
mem::transmute::<FnRaw, fn(&str, &mut Buffer)>(fun)(feed, buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,8 +161,8 @@ mod tests {
|
||||||
buf3.clear();
|
buf3.clear();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
escape_to_buf(&*s, &mut buf1);
|
escape_to_buf(s, &mut buf1);
|
||||||
fallback::escape(&mut buf2, s.as_bytes());
|
fallback::escape(s, &mut buf2);
|
||||||
naive::escape(&mut buf3, s.as_ptr(), s.as_ptr(), s.as_ptr().add(s.len()));
|
naive::escape(&mut buf3, s.as_ptr(), s.as_ptr(), s.as_ptr().add(s.len()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,16 +15,16 @@ const VECTOR_ALIGN: usize = VECTOR_BYTES - 1;
|
||||||
|
|
||||||
#[target_feature(enable = "sse2")]
|
#[target_feature(enable = "sse2")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn escape(buffer: &mut Buffer, bytes: &[u8]) {
|
pub unsafe fn escape(feed: &str, buffer: &mut Buffer) {
|
||||||
let len = bytes.len();
|
let len = feed.len();
|
||||||
if len < VECTOR_BYTES {
|
if len < VECTOR_BYTES {
|
||||||
let start_ptr = bytes.as_ptr();
|
let start_ptr = feed.as_ptr();
|
||||||
let end_ptr = start_ptr.add(len);
|
let end_ptr = start_ptr.add(len);
|
||||||
naive::escape(buffer, start_ptr, start_ptr, end_ptr);
|
naive::escape(buffer, start_ptr, start_ptr, end_ptr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut start_ptr = bytes.as_ptr();
|
let mut start_ptr = feed.as_ptr();
|
||||||
let end_ptr = start_ptr.add(len);
|
let end_ptr = start_ptr.add(len);
|
||||||
|
|
||||||
let v_independent1 = _mm_set1_epi8(5);
|
let v_independent1 = _mm_set1_epi8(5);
|
||||||
|
@ -72,7 +72,7 @@ pub unsafe fn escape(buffer: &mut Buffer, bytes: &[u8]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[target_feature(enable = "sse2")]
|
#[target_feature(enable = "sse2")]
|
||||||
#[inline]
|
#[cfg_attr(feature = "perf-inline", inline)]
|
||||||
pub unsafe fn escape_aligned(
|
pub unsafe fn escape_aligned(
|
||||||
buffer: &mut Buffer,
|
buffer: &mut Buffer,
|
||||||
mut start_ptr: *const u8,
|
mut start_ptr: *const u8,
|
||||||
|
|
|
@ -245,7 +245,7 @@ mod tests {
|
||||||
use super::Integer;
|
use super::Integer;
|
||||||
let mut buf = Vec::with_capacity(i8::MAX_LEN);
|
let mut buf = Vec::with_capacity(i8::MAX_LEN);
|
||||||
|
|
||||||
for n in i8::MIN..=i8::MAX {
|
for n in std::i8::MIN..=std::i8::MAX {
|
||||||
unsafe {
|
unsafe {
|
||||||
let l = n.write_to(buf.as_mut_ptr());
|
let l = n.write_to(buf.as_mut_ptr());
|
||||||
buf.set_len(l);
|
buf.set_len(l);
|
||||||
|
@ -350,8 +350,8 @@ mod tests {
|
||||||
18446744073709551615
|
18446744073709551615
|
||||||
);
|
);
|
||||||
|
|
||||||
make_test!(test_i8, i8, i8::MIN, i8::MAX);
|
make_test!(test_i8, i8, std::i8::MIN, std::i8::MAX);
|
||||||
make_test!(test_i16, i16, i16::MIN, i16::MAX);
|
make_test!(test_i16, i16, std::i16::MIN, std::i16::MAX);
|
||||||
make_test!(test_i32, i32, i32::MIN, i32::MAX);
|
make_test!(test_i32, i32, std::i32::MIN, std::i32::MAX);
|
||||||
make_test!(test_i64, i64, i64::MIN, i64::MAX);
|
make_test!(test_i64, i64, std::i64::MIN, std::i64::MAX);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
macro_rules! render {
|
macro_rules! render {
|
||||||
($ctx:ident, $value:expr) => {
|
($ctx:ident, $value:expr) => {
|
||||||
(&($value))._sailfish_render_internal(&mut $ctx.buf)?
|
(&($value))._sf_r_internal(&mut $ctx.buf)?
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ macro_rules! render {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
macro_rules! render_escaped {
|
macro_rules! render_escaped {
|
||||||
($ctx:ident, $value:expr) => {
|
($ctx:ident, $value:expr) => {
|
||||||
(&($value))._sailfish_render_escaped_internal(&mut $ctx.buf)?
|
(&($value))._sf_re_internal(&mut $ctx.buf)?
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,3 +55,20 @@ impl Context {
|
||||||
Ok(self.buf.into_string())
|
Ok(self.buf.into_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #[inline(never)]
|
||||||
|
// pub fn _instantiate(table: Vec<Vec<usize>>) -> String {
|
||||||
|
// let mut buffer = Buffer::with_capacity(130000);
|
||||||
|
// buffer.push_str("<table>");
|
||||||
|
// for r1 in table {
|
||||||
|
// buffer.push_str("<tr><td>");
|
||||||
|
// for r2 in r1 {
|
||||||
|
// let _ = (&r2).render(&mut buffer);
|
||||||
|
// buffer.push_str("</td><td>");
|
||||||
|
// }
|
||||||
|
// unsafe { buffer.set_len(buffer.len() - 4) }
|
||||||
|
// buffer.push_str("</tr>");
|
||||||
|
// }
|
||||||
|
// buffer.push_str("</table>");
|
||||||
|
// buffer.into_string()
|
||||||
|
// }
|
||||||
|
|
|
@ -134,9 +134,7 @@ macro_rules! render_int {
|
||||||
fn render(&self, b: &mut Buffer) -> Result<(), RenderError> {
|
fn render(&self, b: &mut Buffer) -> Result<(), RenderError> {
|
||||||
use super::integer::Integer;
|
use super::integer::Integer;
|
||||||
|
|
||||||
if Self::MAX_LEN > b.capacity() - b.len() {
|
b.reserve(Self::MAX_LEN);
|
||||||
b.reserve(Self::MAX_LEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = b.as_mut_ptr().add(b.len());
|
let ptr = b.as_mut_ptr().add(b.len());
|
||||||
|
@ -158,51 +156,77 @@ macro_rules! render_int {
|
||||||
|
|
||||||
render_int!(u8, u16, u32, u64, i8, i16, i32, i64, usize, isize);
|
render_int!(u8, u16, u32, u64, i8, i16, i32, i64, usize, isize);
|
||||||
|
|
||||||
macro_rules! render_float {
|
impl Render for f32 {
|
||||||
($($float:ty),*) => {
|
#[inline]
|
||||||
$(
|
fn render(&self, b: &mut Buffer) -> Result<(), RenderError> {
|
||||||
impl Render for $float {
|
if self.is_finite() {
|
||||||
#[inline]
|
unsafe {
|
||||||
fn render(&self, b: &mut Buffer) -> Result<(), RenderError> {
|
b.reserve(16);
|
||||||
let mut buffer = ryu::Buffer::new();
|
let ptr = b.as_mut_ptr().add(b.len());
|
||||||
let s = buffer.format(*self);
|
let l = ryu::raw::format32(*self, ptr);
|
||||||
b.push_str(s);
|
b.set_len(b.len() + l);
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn render_escaped(&self, b: &mut Buffer) -> Result<(), RenderError> {
|
|
||||||
// escape string
|
|
||||||
self.render(b)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)*
|
} else if self.is_nan() {
|
||||||
|
b.push_str("NaN");
|
||||||
|
} else if *self > 0.0 {
|
||||||
|
b.push_str("inf");
|
||||||
|
} else {
|
||||||
|
b.push_str("-inf");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn render_escaped(&self, b: &mut Buffer) -> Result<(), RenderError> {
|
||||||
|
// escape string
|
||||||
|
self.render(b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render_float!(f32, f64);
|
impl Render for f64 {
|
||||||
|
#[inline]
|
||||||
|
fn render(&self, b: &mut Buffer) -> Result<(), RenderError> {
|
||||||
|
if self.is_finite() {
|
||||||
|
unsafe {
|
||||||
|
b.reserve(24);
|
||||||
|
let ptr = b.as_mut_ptr().add(b.len());
|
||||||
|
let l = ryu::raw::format64(*self, ptr);
|
||||||
|
b.set_len(b.len() + l);
|
||||||
|
}
|
||||||
|
} else if self.is_nan() {
|
||||||
|
b.push_str("NaN");
|
||||||
|
} else if *self > 0.0 {
|
||||||
|
b.push_str("inf");
|
||||||
|
} else {
|
||||||
|
b.push_str("-inf");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn render_escaped(&self, b: &mut Buffer) -> Result<(), RenderError> {
|
||||||
|
// escape string
|
||||||
|
self.render(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// private trait for avoiding method name collision in render* macros
|
// private trait for avoiding method name collision in render* macros
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub trait RenderInternal {
|
pub trait RenderInternal {
|
||||||
fn _sailfish_render_internal(&self, b: &mut Buffer) -> Result<(), RenderError>;
|
fn _sf_r_internal(&self, b: &mut Buffer) -> Result<(), RenderError>;
|
||||||
fn _sailfish_render_escaped_internal(
|
fn _sf_re_internal(&self, b: &mut Buffer) -> Result<(), RenderError>;
|
||||||
&self,
|
|
||||||
b: &mut Buffer,
|
|
||||||
) -> Result<(), RenderError>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Render + ?Sized> RenderInternal for T {
|
impl<T: Render + ?Sized> RenderInternal for T {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn _sailfish_render_internal(&self, b: &mut Buffer) -> Result<(), RenderError> {
|
fn _sf_r_internal(&self, b: &mut Buffer) -> Result<(), RenderError> {
|
||||||
self.render(b)
|
self.render(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn _sailfish_render_escaped_internal(
|
fn _sf_re_internal(&self, b: &mut Buffer) -> Result<(), RenderError> {
|
||||||
&self,
|
|
||||||
b: &mut Buffer,
|
|
||||||
) -> Result<(), RenderError> {
|
|
||||||
self.render_escaped(b)
|
self.render_escaped(b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -214,34 +238,34 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn receiver_coercion() {
|
fn receiver_coercion() {
|
||||||
let mut b = Buffer::new();
|
let mut b = Buffer::new();
|
||||||
(&1)._sailfish_render_internal(&mut b).unwrap();
|
(&1)._sf_r_internal(&mut b).unwrap();
|
||||||
(&&1)._sailfish_render_internal(&mut b).unwrap();
|
(&&1)._sf_r_internal(&mut b).unwrap();
|
||||||
(&&&1)._sailfish_render_internal(&mut b).unwrap();
|
(&&&1)._sf_r_internal(&mut b).unwrap();
|
||||||
(&&&&1)._sailfish_render_internal(&mut b).unwrap();
|
(&&&&1)._sf_r_internal(&mut b).unwrap();
|
||||||
assert_eq!(b.as_str(), "1111");
|
assert_eq!(b.as_str(), "1111");
|
||||||
b.clear();
|
b.clear();
|
||||||
|
|
||||||
let v = 2.0;
|
let v = 2.0;
|
||||||
(&v)._sailfish_render_internal(&mut b).unwrap();
|
(&v)._sf_r_internal(&mut b).unwrap();
|
||||||
(&&v)._sailfish_render_internal(&mut b).unwrap();
|
(&&v)._sf_r_internal(&mut b).unwrap();
|
||||||
(&&&v)._sailfish_render_internal(&mut b).unwrap();
|
(&&&v)._sf_r_internal(&mut b).unwrap();
|
||||||
(&&&&v)._sailfish_render_internal(&mut b).unwrap();
|
(&&&&v)._sf_r_internal(&mut b).unwrap();
|
||||||
assert_eq!(b.as_str(), "2.02.02.02.0");
|
assert_eq!(b.as_str(), "2.02.02.02.0");
|
||||||
b.clear();
|
b.clear();
|
||||||
|
|
||||||
let s = "apple";
|
let s = "apple";
|
||||||
(&*s)._sailfish_render_escaped_internal(&mut b).unwrap();
|
(&*s)._sf_re_internal(&mut b).unwrap();
|
||||||
(&s)._sailfish_render_escaped_internal(&mut b).unwrap();
|
(&s)._sf_re_internal(&mut b).unwrap();
|
||||||
(&&s)._sailfish_render_escaped_internal(&mut b).unwrap();
|
(&&s)._sf_re_internal(&mut b).unwrap();
|
||||||
(&&&s)._sailfish_render_escaped_internal(&mut b).unwrap();
|
(&&&s)._sf_re_internal(&mut b).unwrap();
|
||||||
(&&&&s)._sailfish_render_escaped_internal(&mut b).unwrap();
|
(&&&&s)._sf_re_internal(&mut b).unwrap();
|
||||||
assert_eq!(b.as_str(), "appleappleappleappleapple");
|
assert_eq!(b.as_str(), "appleappleappleappleapple");
|
||||||
b.clear();
|
b.clear();
|
||||||
|
|
||||||
(&'c')._sailfish_render_escaped_internal(&mut b).unwrap();
|
(&'c')._sf_re_internal(&mut b).unwrap();
|
||||||
(&&'<')._sailfish_render_escaped_internal(&mut b).unwrap();
|
(&&'<')._sf_re_internal(&mut b).unwrap();
|
||||||
(&&&'&')._sailfish_render_escaped_internal(&mut b).unwrap();
|
(&&&'&')._sf_re_internal(&mut b).unwrap();
|
||||||
(&&&&' ')._sailfish_render_escaped_internal(&mut b).unwrap();
|
(&&&&' ')._sf_re_internal(&mut b).unwrap();
|
||||||
assert_eq!(b.as_str(), "c<& ");
|
assert_eq!(b.as_str(), "c<& ");
|
||||||
b.clear();
|
b.clear();
|
||||||
}
|
}
|
||||||
|
@ -252,18 +276,10 @@ mod tests {
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
let mut b = Buffer::new();
|
let mut b = Buffer::new();
|
||||||
(&String::from("a"))
|
(&String::from("a"))._sf_r_internal(&mut b).unwrap();
|
||||||
._sailfish_render_internal(&mut b)
|
(&&PathBuf::from("b"))._sf_r_internal(&mut b).unwrap();
|
||||||
.unwrap();
|
(&Rc::new(4u32))._sf_re_internal(&mut b).unwrap();
|
||||||
(&&PathBuf::from("b"))
|
(&Rc::new(2.3f32))._sf_re_internal(&mut b).unwrap();
|
||||||
._sailfish_render_internal(&mut b)
|
|
||||||
.unwrap();
|
|
||||||
(&Rc::new(4u32))
|
|
||||||
._sailfish_render_escaped_internal(&mut b)
|
|
||||||
.unwrap();
|
|
||||||
(&Rc::new(2.3f32))
|
|
||||||
._sailfish_render_escaped_internal(&mut b)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(b.as_str(), "ab42.3");
|
assert_eq!(b.as_str(), "ab42.3");
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,10 @@ if [ "$TRAVIS_RUST_VERSION" = "nightly" ] && [ -z "$TRAVIS_TAG" ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cargo build $CARGO_OPTIONS
|
cargo build $CARGO_OPTIONS
|
||||||
cargo test $CARGO_OPTIONS
|
|
||||||
|
if [ "$TRAVIS_RUST_VERSION" != "1.42.0" ]; then
|
||||||
|
cargo test $CARGO_OPTIONS
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "$TRAVIS_RUST_VERSION" = "nightly" ] && [ -z "$TRAVIS_TAG" ]; then
|
if [ "$TRAVIS_RUST_VERSION" = "nightly" ] && [ -z "$TRAVIS_TAG" ]; then
|
||||||
zip -0 ccov.zip `find . \( -name "sailfish*.gc*" -o -name "test-*.gc*" \) -print`
|
zip -0 ccov.zip `find . \( -name "sailfish*.gc*" -o -name "test-*.gc*" \) -print`
|
||||||
|
|
Loading…
Reference in New Issue