Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make derive optional #342

Merged
merged 1 commit into from
Feb 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
- run: |
set -eu
for PKG in \
examples/actix-web-app examples/axum-app examples/poem-app examples/rocket-app examples/salvo-app examples/warp-app fuzzing \
bench-build examples/actix-web-app examples/axum-app examples/poem-app examples/rocket-app examples/salvo-app examples/warp-app fuzzing \
rinja rinja_derive rinja_derive_standalone rinja_parser \
testing testing-alloc testing-no-std testing-renamed
do
Expand Down Expand Up @@ -116,7 +116,7 @@ jobs:
cargo sort --check --check-format --grouped
set -eu
for PKG in \
examples/actix-web-app examples/axum-app examples/poem-app examples/rocket-app examples/salvo-app examples/warp-app fuzzing \
bench-build examples/actix-web-app examples/axum-app examples/poem-app examples/rocket-app examples/salvo-app examples/warp-app fuzzing \
rinja rinja_derive rinja_derive_standalone rinja_parser \
testing testing-alloc testing-no-std testing-renamed
do
Expand Down Expand Up @@ -159,7 +159,7 @@ jobs:
strategy:
matrix:
package: [
examples/actix-web-app, examples/axum-app, examples/poem-app, examples/rocket-app, examples/salvo-app, examples/warp-app, fuzzing,
bench-build, examples/actix-web-app, examples/axum-app, examples/poem-app, examples/rocket-app, examples/salvo-app, examples/warp-app, fuzzing,
rinja, rinja_derive, rinja_derive_standalone, rinja_parser,
testing, testing-alloc, testing-no-std, testing-renamed,
]
Expand Down
1 change: 1 addition & 0 deletions bench-build/.rustfmt.toml
18 changes: 18 additions & 0 deletions bench-build/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "bench-build"
version = "0.3.5"
authors = ["rinja-rs developers"]
edition = "2021"
rust-version = "1.81"
publish = false

[dependencies]
rinja = { path = "../rinja", version = "0.3.5", default-features = false, features = ["std"] }
rinja_derive = { path = "../rinja_derive", version = "0.3.5", features = ["std"] }

[features]
default = []
derive = ["rinja/derive"]

[workspace]
members = ["."]
1 change: 1 addition & 0 deletions bench-build/LICENSE-APACHE
1 change: 1 addition & 0 deletions bench-build/LICENSE-MIT
55 changes: 55 additions & 0 deletions bench-build/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
Run the script `./run.sh` in this directory to compare the compile compile of `rinja`

* uses feature `derive` vs
* it does not use that feature.

The output might look like:

```text
Benchmark 1: cargo run --features=derive
Time (mean ± σ): 3.378 s ± 0.041 s [User: 7.944 s, System: 1.018 s]
Range (min … max): 3.345 s … 3.424 s 3 runs

Benchmark 2: cargo run
Time (mean ± σ): 3.283 s ± 0.130 s [User: 8.400 s, System: 1.091 s]
Range (min … max): 3.141 s … 3.398 s 3 runs

Summary
cargo run ran
1.03 ± 0.04 times faster than cargo run --features=derive

----------

Benchmark 1: cargo run --release --features=derive
Time (mean ± σ): 4.733 s ± 0.050 s [User: 9.026 s, System: 0.749 s]
Range (min … max): 4.689 s … 4.788 s 3 runs

Benchmark 2: cargo run --release
Time (mean ± σ): 4.504 s ± 0.032 s [User: 9.010 s, System: 0.733 s]
Range (min … max): 4.481 s … 4.541 s 3 runs

Summary
cargo run --release ran
1.05 ± 0.01 times faster than cargo run --release --features=derive
```

This shows that – while it is less convenient – for small projects it might be better
to use the following setup.
This might be especially true if you are using `rinja` in a library.
Without the feature, `cargo` will be able to compile more dependencies in parallel.

```toml
# Cargo.toml
[dependencies]
rinja = { version = "0.3.5", default-features = false, features = ["std"] }
rinja_derive = { version = "0.3.5", features = ["std"] }
```

```rust
// lib.rs
use rinja::Template as _;
use rinja_derive::Template;
```

The script uses [hyperfine](https://crates.io/crates/hyperfine).
Install it with `cargo install hyperfine`.
1 change: 1 addition & 0 deletions bench-build/_typos.toml
1 change: 1 addition & 0 deletions bench-build/clippy.toml
1 change: 1 addition & 0 deletions bench-build/deny.toml
20 changes: 20 additions & 0 deletions bench-build/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "${BASH_SOURCE[0]}")"

mkdir -p target
hyperfine \
--runs=3 \
--warmup=1 \
--prepare='rm -r target' \
'cargo run --features=derive' \
'cargo run'
echo
echo ----------
echo
hyperfine \
--runs=3 \
--warmup=1 \
--prepare='rm -r target' \
'cargo run --release --features=derive' \
'cargo run --release'
47 changes: 47 additions & 0 deletions bench-build/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use std::str::FromStr;

use rinja::Template as _;
use rinja_derive::Template;

fn main() {
let mut args = std::env::args().fuse().skip(1);
let greeting = args.next();
let user = args.next();

let tmpl = HelloWorld {
greeting: greeting.as_deref().unwrap_or("hi").parse().unwrap(),
user: user.as_deref().unwrap_or("user"),
};
println!("{}", tmpl.render().unwrap());
}

#[derive(Debug, Clone, Copy, Template)]
#[template(path = "hello_world.html")]
struct HelloWorld<'a> {
greeting: Greeting,
user: &'a str,
}

#[derive(Debug, Clone, Copy, Template)]
#[template(path = "greeting.html")]
enum Greeting {
#[template(block = "hello")]
Hello,
#[template(block = "hey")]
Hey,
#[template(block = "hi")]
Hi,
}

impl FromStr for Greeting {
type Err = &'static str;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"hello" => Ok(Self::Hello),
"hey" => Ok(Self::Hey),
"hi" => Ok(Self::Hi),
_ => Err("Valid greetings: <hello | hey | hi>"),
}
}
}
11 changes: 11 additions & 0 deletions bench-build/templates/greeting.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{%- block hello -%}
Hello
{%- endblock -%}

{%- block hey -%}
Hey
{%- endblock -%}

{%- block hi -%}
Hi
{%- endblock -%}
1 change: 1 addition & 0 deletions bench-build/templates/hello_world.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<h1>{{greeting}}, {{user}}!</h1>
1 change: 1 addition & 0 deletions bench-build/tomlfmt.toml
20 changes: 19 additions & 1 deletion book/src/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Without `default-features = false`, i.e with default features enabled,
the following features are automatically selected for you:

```toml
default = ["config", "std", "urlencode"]
default = ["config", "derive", "std", "urlencode"]
```

This should encompass most features an average user of rinja might need.
Expand All @@ -44,6 +44,24 @@ This should encompass most features an average user of rinja might need.
and if you want it to be usable in by other users and in **other projects**,
then you should probably **opt-out of features you do not need**.*

### `"derive"`

<blockquote class="right" style="padding:0.5ex 1ex; margin:0 0 1ex 1ex; font-size:80%">
enabled by <code>"default"</code>
</blockquote>

This feature enables `#[derive(Template)]`. Without it the trait `rinja::Template` will still be
available, but if you want to derive a template, you have to manually depend on `rinja_derive`.
`rinja_derive` should be used with the same features as `rinja`.

Not using this feature might be useful e.g. if you are writing a library with manual filters
for rinja, without any templates. It might also very slightly speed-up the compilation,
because more dependencies can be compiled in parallel, because `rinja` won't transitively depend
on e.g. `syn` or `proc-macro2`. On the author's PC the compilation of a trivial hello-world example
was about 0.2s faster without the feature when compiled in release mode.

*If you are writing a library that uses rinja, consider **not using** this default-feature.*

### `"config"`

<blockquote class="right" style="padding:0.5ex 1ex; margin:0 0 1ex 1ex; font-size:80%">
Expand Down
28 changes: 15 additions & 13 deletions rinja/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ name = "escape"
harness = false

[dependencies]
rinja_derive = { version = "=0.3.5", path = "../rinja_derive" }

itoa = "1.0.11"

# needed by feature "derive"
rinja_derive = { version = "=0.3.5", path = "../rinja_derive", default-features = false, optional = true }

# needed by feature "serde_json"
serde = { version = "1.0", optional = true, default-features = false }
serde_json = { version = "1.0", optional = true, default-features = false }
Expand All @@ -43,24 +44,25 @@ criterion = "0.5"
maintenance = { status = "actively-developed" }

[features]
default = ["config", "std", "urlencode"]
full = ["default", "blocks", "code-in-doc", "serde_json"]
default = ["config", "derive", "std", "urlencode", "rinja_derive?/default"]
full = ["default", "blocks", "code-in-doc", "serde_json", "rinja_derive?/full"]

alloc = [
"rinja_derive/alloc",
"rinja_derive?/alloc",
"serde?/alloc",
"serde_json?/alloc",
"percent-encoding?/alloc"
"percent-encoding?/alloc",
]
blocks = ["rinja_derive/blocks"]
code-in-doc = ["rinja_derive/code-in-doc"]
config = ["rinja_derive/config"]
serde_json = ["rinja_derive/serde_json", "dep:serde", "dep:serde_json"]
blocks = ["rinja_derive?/blocks"]
code-in-doc = ["rinja_derive?/code-in-doc"]
config = ["rinja_derive?/config"]
derive = ["rinja_derive"]
serde_json = ["rinja_derive?/serde_json", "dep:serde", "dep:serde_json"]
std = [
"alloc",
"rinja_derive/std",
"rinja_derive?/std",
"serde?/std",
"serde_json?/std",
"percent-encoding?/std"
"percent-encoding?/std",
]
urlencode = ["rinja_derive/urlencode", "dep:percent-encoding"]
urlencode = ["rinja_derive?/urlencode", "dep:percent-encoding"]
5 changes: 3 additions & 2 deletions rinja/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@
//! }
//!
//! assert_eq!(
//! Footer { year: 2024, enterprise: "<em>Rinja</em> developers" }.to_string(),
//! "<p>© 2024 &#60;EM&#62;RINJA&#60;/EM&#62; DEVELOPERS</p>",
//! Footer { year: 2025, enterprise: "<em>Rinja</em> developers" }.to_string(),
//! "<p>© 2025 &#60;EM&#62;RINJA&#60;/EM&#62; DEVELOPERS</p>",
//! );
//! // In here you see can Rinja's auto-escaping. You, the developer,
//! // can easily disable the auto-escaping with the `|safe` filter,
Expand Down Expand Up @@ -78,6 +78,7 @@ use core::fmt;
#[cfg(feature = "std")]
use std::io;

#[cfg(feature = "derive")]
pub use rinja_derive::Template;

#[doc(hidden)]
Expand Down
7 changes: 6 additions & 1 deletion rinja_derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,19 @@ prettyplease = "0.2.20"
similar = "2.6.0"
syn = { version = "2.0.3", features = ["full"] }

# must be the same feature list as for rinja
[features]
default = ["config", "derive", "std", "urlencode"]
full = ["default", "blocks", "code-in-doc", "serde_json"]

alloc = []
blocks = ["syn/full"]
code-in-doc = ["dep:pulldown-cmark"]
config = ["dep:basic-toml", "dep:serde", "dep:serde_derive", "parser/config"]
urlencode = []
derive = []
serde_json = []
std = ["alloc"]
urlencode = []

[lints.rust]
# Used in `rinja_derive_standalone` which uses the same source folder, but is not a proc-macro.
Expand Down
5 changes: 4 additions & 1 deletion rinja_derive_standalone/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,14 @@ syn = { version = "2.0.3", features = ["full"] }
default = ["__standalone"]
__standalone = []

alloc = []
blocks = ["syn/full"]
code-in-doc = ["dep:pulldown-cmark"]
config = ["dep:basic-toml", "dep:serde", "dep:serde_derive", "parser/config"]
urlencode = []
derive = []
serde_json = []
std = ["alloc"]
urlencode = []

[lints.rust]
# Used in `rinja_derive` which uses the same source folder, but is a proc-macro.
Expand Down
2 changes: 1 addition & 1 deletion testing-alloc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ rust-version = "1.81"
publish = false

[dev-dependencies]
rinja = { path = "../rinja", version = "0.3.5", default-features = false, features = ["alloc"] }
rinja = { path = "../rinja", version = "0.3.5", default-features = false, features = ["alloc", "derive"] }

assert_matches = "1.5.0"
2 changes: 1 addition & 1 deletion testing-no-std/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ rust-version = "1.81"
publish = false

[dev-dependencies]
rinja = { path = "../rinja", version = "0.3.5", default-features = false }
rinja = { path = "../rinja", version = "0.3.5", default-features = false, features = ["derive"] }

assert_matches = "1.5.0"
2 changes: 1 addition & 1 deletion testing-renamed/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ rust-version = "1.81"
publish = false

[dev-dependencies]
some_name = { package = "rinja", path = "../rinja", version = "0.3.5", default-features = false }
some_name = { package = "rinja", path = "../rinja", version = "0.3.5", default-features = false, features = ["derive"] }

assert_matches = "1.5.0"
Loading