From 1719626c88d283c06dcddd651ed156874576d000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Kijewski?= Date: Tue, 18 Jun 2024 18:28:30 +0200 Subject: [PATCH] derive: add benchmark This PR adds the crate "rinja_derive_standalone", which is just like "rinja_derive", though not a "proc_macro". This way we can easily expose it's internals for testing and benchmarking. Right now, the PR is more or less a prove of concept, and it probably needs a handful more useful benchmark use cases to be worth the hassle. --- .github/workflows/rust.yml | 2 +- Cargo.toml | 1 + rinja_derive/src/config.rs | 4 +- rinja_derive/src/heritage.rs | 5 +- rinja_derive/src/input.rs | 2 +- rinja_derive/src/lib.rs | 65 ++++++++++++------- rinja_derive/src/tests.rs | 5 +- rinja_derive_standalone/Cargo.toml | 43 ++++++++++++ rinja_derive_standalone/LICENSE-APACHE | 1 + rinja_derive_standalone/LICENSE-MIT | 1 + rinja_derive_standalone/README.md | 2 + .../benches/derive-template.rs | 25 +++++++ rinja_derive_standalone/src | 1 + rinja_derive_standalone/templates | 1 + 14 files changed, 126 insertions(+), 32 deletions(-) create mode 100644 rinja_derive_standalone/Cargo.toml create mode 120000 rinja_derive_standalone/LICENSE-APACHE create mode 120000 rinja_derive_standalone/LICENSE-MIT create mode 100644 rinja_derive_standalone/README.md create mode 100644 rinja_derive_standalone/benches/derive-template.rs create mode 120000 rinja_derive_standalone/src create mode 120000 rinja_derive_standalone/templates diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index aca24c487..903fa5660 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -32,7 +32,7 @@ jobs: strategy: matrix: package: [ - rinja, rinja_actix, rinja_axum, rinja_derive, rinja_escape, + rinja, rinja_actix, rinja_axum, rinja_derive, rinja_derive_standalone, rinja_escape, rinja_parser, rinja_rocket, rinja_warp, testing, ] runs-on: ubuntu-latest diff --git a/Cargo.toml b/Cargo.toml index 154f58972..4eac66829 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ members = [ "rinja_actix", "rinja_axum", "rinja_derive", + "rinja_derive_standalone", "rinja_escape", "rinja_parser", "rinja_rocket", diff --git a/rinja_derive/src/config.rs b/rinja_derive/src/config.rs index 188ce370a..52e71b8a6 100644 --- a/rinja_derive/src/config.rs +++ b/rinja_derive/src/config.rs @@ -3,12 +3,12 @@ use std::path::{Path, PathBuf}; use std::rc::Rc; use std::{env, fs}; +use parser::node::Whitespace; +use parser::Syntax; #[cfg(feature = "serde")] use serde::Deserialize; use crate::{CompileError, FileInfo, CRATE}; -use parser::node::Whitespace; -use parser::Syntax; #[derive(Debug)] pub(crate) struct Config<'a> { diff --git a/rinja_derive/src/heritage.rs b/rinja_derive/src/heritage.rs index 086eeb1b9..0c60f0d4e 100644 --- a/rinja_derive/src/heritage.rs +++ b/rinja_derive/src/heritage.rs @@ -2,11 +2,12 @@ use std::collections::HashMap; use std::path::Path; use std::rc::Rc; -use crate::config::Config; -use crate::{CompileError, FileInfo}; use parser::node::{BlockDef, Macro}; use parser::{Node, Parsed, WithSpan}; +use crate::config::Config; +use crate::{CompileError, FileInfo}; + pub(crate) struct Heritage<'a> { pub(crate) root: &'a Context<'a>, pub(crate) blocks: BlockAncestry<'a>, diff --git a/rinja_derive/src/input.rs b/rinja_derive/src/input.rs index 34948f415..66e30d663 100644 --- a/rinja_derive/src/input.rs +++ b/rinja_derive/src/input.rs @@ -4,12 +4,12 @@ use std::rc::Rc; use std::str::FromStr; use mime::Mime; +use parser::{Node, Parsed, Syntax}; use quote::ToTokens; use syn::punctuated::Punctuated; use crate::config::{get_template_source, Config}; use crate::CompileError; -use parser::{Node, Parsed, Syntax}; pub(crate) struct TemplateInput<'a> { pub(crate) ast: &'a syn::DeriveInput, diff --git a/rinja_derive/src/lib.rs b/rinja_derive/src/lib.rs index e65cf747c..e3d99204d 100644 --- a/rinja_derive/src/lib.rs +++ b/rinja_derive/src/lib.rs @@ -1,38 +1,57 @@ #![deny(elided_lifetimes_in_paths)] #![deny(unreachable_pub)] +mod config; +mod generator; +mod heritage; +mod input; +#[cfg(test)] +mod tests; + use std::collections::HashMap; use std::fmt; use std::path::Path; -use proc_macro::TokenStream; -use proc_macro2::Span; - -use parser::{generate_error_info, strip_common, ErrorInfo, ParseError}; - -mod config; use config::{read_config_file, Config}; -mod generator; use generator::{Generator, MapChain}; -mod heritage; use heritage::{Context, Heritage}; -mod input; use input::{Print, TemplateArgs, TemplateInput}; -#[cfg(test)] -mod tests; +use parser::{generate_error_info, strip_common, ErrorInfo, ParseError}; +use proc_macro2::{Span, TokenStream}; + +#[cfg(not(feature = "__standalone"))] +macro_rules! pub_if_standalone { + (pub $($tt:tt)*) => { + $($tt)* + } +} + +#[cfg(feature = "__standalone")] +macro_rules! pub_if_standalone { + ($($tt:tt)*) => { + $($tt)* + } +} +#[cfg(not(feature = "__standalone"))] #[proc_macro_derive(Template, attributes(template))] -pub fn derive_template(input: TokenStream) -> TokenStream { - let ast = syn::parse::(input).unwrap(); - match build_template(&ast) { - Ok(source) => source.parse().unwrap(), - Err(e) => { - let mut e = e.into_compile_error(); - if let Ok(source) = build_skeleton(&ast) { - let source: TokenStream = source.parse().unwrap(); - e.extend(source); +pub fn derive_template(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + derive_template2(input.into()).into() +} + +pub_if_standalone! { + pub fn derive_template2(input: TokenStream) -> TokenStream { + let ast = syn::parse2(input).unwrap(); + match build_template(&ast) { + Ok(source) => source.parse().unwrap(), + Err(e) => { + let mut e = e.into_compile_error(); + if let Ok(source) = build_skeleton(&ast) { + let source: TokenStream = source.parse().unwrap(); + e.extend(source); + } + e } - e } } } @@ -138,9 +157,7 @@ impl CompileError { } fn into_compile_error(self) -> TokenStream { - syn::Error::new(self.span, self.msg) - .to_compile_error() - .into() + syn::Error::new(self.span, self.msg).to_compile_error() } } diff --git a/rinja_derive/src/tests.rs b/rinja_derive/src/tests.rs index 7863e1ca6..03f64db5f 100644 --- a/rinja_derive/src/tests.rs +++ b/rinja_derive/src/tests.rs @@ -1,8 +1,9 @@ -// Files containing tests for generated code. +//! Files containing tests for generated code. -use crate::build_template; use std::fmt::Write; +use crate::build_template; + #[test] fn check_if_let() { // This function makes it much easier to compare expected code by adding the wrapping around diff --git a/rinja_derive_standalone/Cargo.toml b/rinja_derive_standalone/Cargo.toml new file mode 100644 index 000000000..82c3b34db --- /dev/null +++ b/rinja_derive_standalone/Cargo.toml @@ -0,0 +1,43 @@ +[package] +name = "rinja_derive_standalone" +version = "0.13.0" +description = "Procedural macro package for Rinja" +homepage = "https://github.com/rinja-rs/rinja" +repository = "https://github.com/rinja-rs/rinja" +license = "MIT/Apache-2.0" +workspace = ".." +readme = "README.md" +edition = "2021" +rust-version = "1.65" +publish = false + +[features] +default = ["__standalone"] +__standalone = [] +config = ["serde", "basic-toml"] +humansize = [] +urlencode = [] +serde-json = [] +num-traits = [] +with-actix-web = [] +with-axum = [] +with-rocket = [] +with-warp = [] + +[dependencies] +parser = { package = "rinja_parser", version = "0.3", path = "../rinja_parser" } +mime = "0.3" +mime_guess = "2" +proc-macro2 = "1" +quote = "1" +serde = { version = "1.0", optional = true, features = ["derive"] } +syn = "2" +basic-toml = { version = "0.1.1", optional = true } + +[dev-dependencies] +criterion = "0.5" + +[[bench]] +name = "derive-template" +harness = false +required-features = ["__standalone"] diff --git a/rinja_derive_standalone/LICENSE-APACHE b/rinja_derive_standalone/LICENSE-APACHE new file mode 120000 index 000000000..965b606f3 --- /dev/null +++ b/rinja_derive_standalone/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/rinja_derive_standalone/LICENSE-MIT b/rinja_derive_standalone/LICENSE-MIT new file mode 120000 index 000000000..76219eb72 --- /dev/null +++ b/rinja_derive_standalone/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/rinja_derive_standalone/README.md b/rinja_derive_standalone/README.md new file mode 100644 index 000000000..a8d89bba4 --- /dev/null +++ b/rinja_derive_standalone/README.md @@ -0,0 +1,2 @@ +This crate embeds the source of `rinja_derive`, but is not a `proc_macro`. +This way we can more easily access the internals of the crate. diff --git a/rinja_derive_standalone/benches/derive-template.rs b/rinja_derive_standalone/benches/derive-template.rs new file mode 100644 index 000000000..faf231ab0 --- /dev/null +++ b/rinja_derive_standalone/benches/derive-template.rs @@ -0,0 +1,25 @@ +use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use quote::quote; + +criterion_main!(benches); +criterion_group!(benches, functions); + +fn functions(c: &mut Criterion) { + c.bench_function("hello_world", hello_world); +} + +fn hello_world(b: &mut criterion::Bencher<'_>) { + let ts = quote! { + #[derive(Template)] + #[template( + source = "

Hello, {{user}}!

", + ext = "html" + )] + struct Hello<'a> { + user: &'a str, + } + }; + b.iter(|| { + rinja_derive_standalone::derive_template2(black_box(&ts).clone()); + }) +} diff --git a/rinja_derive_standalone/src b/rinja_derive_standalone/src new file mode 120000 index 000000000..0e2a1ca24 --- /dev/null +++ b/rinja_derive_standalone/src @@ -0,0 +1 @@ +../rinja_derive/src/ \ No newline at end of file diff --git a/rinja_derive_standalone/templates b/rinja_derive_standalone/templates new file mode 120000 index 000000000..685d5500f --- /dev/null +++ b/rinja_derive_standalone/templates @@ -0,0 +1 @@ +../rinja_derive/templates/ \ No newline at end of file