use criterion::{black_box, criterion_group, criterion_main, Criterion}; use proc_macro2::TokenStream; use quote::quote; use quote_into::quote_into; fn quote_box_wrap(levels: usize) -> TokenStream { match levels { 0 => quote!(bool), other => { let inner = quote_box_wrap(other - 1); quote!(Box<#inner>) } } } // Faster than the "functional" quote approach, but ugly, and not as fast as `quote_into` fn fragmented_quote_box_wrap(levels: usize) -> TokenStream { let mut t = TokenStream::new(); fn inner(t: &mut TokenStream, levels: usize) { match levels { 0 => t.extend(quote!(bool)), other => { t.extend(quote!(Box<)); inner(t, other - 1); t.extend(quote!(>)); } } } inner(&mut t, levels); t } fn quote_into_box_wrap(levels: usize) -> TokenStream { fn inner(s: &mut TokenStream, levels: usize) { match levels { 0 => quote_into!(s += bool), other => quote_into! {s += Box < #{ inner(s, other - 1) } >}, } } let mut s = TokenStream::new(); inner(&mut s, levels); s } pub fn compare_box_wrap(c: &mut Criterion) { const COUNT: usize = 100; { let a = quote_box_wrap(COUNT).to_string(); let b = fragmented_quote_box_wrap(COUNT).to_string(); let c = quote_into_box_wrap(COUNT).to_string(); assert_eq!(a, b); assert_eq!(b, c); } c.bench_function("quote", |b| b.iter(|| black_box(quote_box_wrap(COUNT)))); c.bench_function("fragmented_quote", |b| { b.iter(|| black_box(fragmented_quote_box_wrap(COUNT))) }); c.bench_function("quote_into", |b| { b.iter(|| black_box(quote_into_box_wrap(COUNT))) }); } criterion_group!(benches, compare_box_wrap); criterion_main!(benches);