parser/derive: use only one hasher throughout the proc_macro

This commit is contained in:
René Kijewski 2025-08-03 05:53:00 +02:00
parent 3a677870d9
commit 267a115672
11 changed files with 41 additions and 44 deletions

View File

@ -1,5 +1,5 @@
use std::borrow::{Borrow, Cow}; use std::borrow::{Borrow, Cow};
use std::collections::btree_map::{BTreeMap, Entry}; use std::collections::hash_map::Entry;
use std::mem::ManuallyDrop; use std::mem::ManuallyDrop;
use std::ops::Deref; use std::ops::Deref;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@ -12,12 +12,12 @@ use proc_macro2::Span;
#[cfg(feature = "config")] #[cfg(feature = "config")]
use serde_derive::Deserialize; use serde_derive::Deserialize;
use crate::{CompileError, FileInfo, OnceMap}; use crate::{CompileError, FileInfo, HashMap, OnceMap};
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct Config { pub(crate) struct Config {
pub(crate) dirs: Vec<PathBuf>, pub(crate) dirs: Vec<PathBuf>,
pub(crate) syntaxes: BTreeMap<String, SyntaxAndCache<'static>>, pub(crate) syntaxes: HashMap<String, SyntaxAndCache<'static>>,
pub(crate) default_syntax: &'static str, pub(crate) default_syntax: &'static str,
pub(crate) escapers: Vec<(Vec<Cow<'static, str>>, Cow<'static, str>)>, pub(crate) escapers: Vec<(Vec<Cow<'static, str>>, Cow<'static, str>)>,
pub(crate) whitespace: Whitespace, pub(crate) whitespace: Whitespace,
@ -107,7 +107,7 @@ impl Config {
let default_dirs = vec![root.join("templates")]; let default_dirs = vec![root.join("templates")];
let mut syntaxes = BTreeMap::new(); let mut syntaxes = HashMap::default();
syntaxes.insert(DEFAULT_SYNTAX_NAME.to_string(), SyntaxAndCache::default()); syntaxes.insert(DEFAULT_SYNTAX_NAME.to_string(), SyntaxAndCache::default());
let raw = if s.is_empty() { let raw = if s.is_empty() {

View File

@ -4,7 +4,6 @@ mod helpers;
mod node; mod node;
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::hash_map::HashMap;
use std::env::current_dir; use std::env::current_dir;
use std::ops::Deref; use std::ops::Deref;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@ -15,7 +14,6 @@ use parser::node::{Call, Macro, Whitespace};
use parser::{CharLit, Expr, FloatKind, IntKind, Num, StrLit, WithSpan}; use parser::{CharLit, Expr, FloatKind, IntKind, Num, StrLit, WithSpan};
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::{ToTokens, quote_spanned}; use quote::{ToTokens, quote_spanned};
use rustc_hash::FxBuildHasher;
use syn::Token; use syn::Token;
use crate::generator::helpers::{clean_path, diff_paths}; use crate::generator::helpers::{clean_path, diff_paths};
@ -23,12 +21,12 @@ use crate::heritage::{Context, Heritage};
use crate::html::write_escaped_str; use crate::html::write_escaped_str;
use crate::input::{Source, TemplateInput}; use crate::input::{Source, TemplateInput};
use crate::integration::{Buffer, impl_everything, write_header}; use crate::integration::{Buffer, impl_everything, write_header};
use crate::{CompileError, FileInfo, field_new, quote_into}; use crate::{CompileError, FileInfo, HashMap, field_new, quote_into};
pub(crate) fn template_to_string( pub(crate) fn template_to_string(
buf: &mut Buffer, buf: &mut Buffer,
input: &TemplateInput<'_>, input: &TemplateInput<'_>,
contexts: &HashMap<&Arc<Path>, Context<'_>, FxBuildHasher>, contexts: &HashMap<&Arc<Path>, Context<'_>>,
heritage: Option<&Heritage<'_, '_>>, heritage: Option<&Heritage<'_, '_>>,
tmpl_kind: TmplKind<'_>, tmpl_kind: TmplKind<'_>,
) -> Result<usize, CompileError> { ) -> Result<usize, CompileError> {
@ -69,7 +67,7 @@ struct Generator<'a, 'h> {
/// The template input state: original struct AST and attributes /// The template input state: original struct AST and attributes
input: &'a TemplateInput<'a>, input: &'a TemplateInput<'a>,
/// All contexts, keyed by the package-relative template path /// All contexts, keyed by the package-relative template path
contexts: &'a HashMap<&'a Arc<Path>, Context<'a>, FxBuildHasher>, contexts: &'a HashMap<&'a Arc<Path>, Context<'a>>,
/// The heritage contains references to blocks and their ancestry /// The heritage contains references to blocks and their ancestry
heritage: Option<&'h Heritage<'a, 'h>>, heritage: Option<&'h Heritage<'a, 'h>>,
/// Variables accessible directly from the current scope (not redirected to context) /// Variables accessible directly from the current scope (not redirected to context)
@ -102,7 +100,7 @@ enum CallerDir {
impl<'a, 'h> Generator<'a, 'h> { impl<'a, 'h> Generator<'a, 'h> {
fn new( fn new(
input: &'a TemplateInput<'a>, input: &'a TemplateInput<'a>,
contexts: &'a HashMap<&'a Arc<Path>, Context<'a>, FxBuildHasher>, contexts: &'a HashMap<&'a Arc<Path>, Context<'a>>,
heritage: Option<&'h Heritage<'a, 'h>>, heritage: Option<&'h Heritage<'a, 'h>>,
locals: MapChain<'a>, locals: MapChain<'a>,
buf_writable_discard: bool, buf_writable_discard: bool,
@ -619,7 +617,7 @@ impl<'a> LocalMeta<'a> {
} }
struct MapChain<'a> { struct MapChain<'a> {
scopes: Vec<HashMap<Cow<'a, str>, LocalMeta<'a>, FxBuildHasher>>, scopes: Vec<HashMap<Cow<'a, str>, LocalMeta<'a>>>,
} }
impl<'a> MapChain<'a> { impl<'a> MapChain<'a> {

View File

@ -1,19 +1,17 @@
use core::fmt; use core::fmt;
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::HashMap;
use std::fmt::Write; use std::fmt::Write;
use std::mem; use std::mem;
use parser::node::{Call, Macro, Ws}; use parser::node::{Call, Macro, Ws};
use parser::{Expr, Span, WithSpan}; use parser::{Expr, Span, WithSpan};
use quote::quote_spanned; use quote::quote_spanned;
use rustc_hash::FxBuildHasher;
use crate::generator::node::AstLevel; use crate::generator::node::AstLevel;
use crate::generator::{Generator, LocalMeta, is_copyable}; use crate::generator::{Generator, LocalMeta, is_copyable};
use crate::heritage::Context; use crate::heritage::Context;
use crate::integration::Buffer; use crate::integration::Buffer;
use crate::{CompileError, field_new, quote_into}; use crate::{CompileError, HashMap, field_new, quote_into};
/// Helper to generate the code for macro invocations /// Helper to generate the code for macro invocations
pub(crate) struct MacroInvocation<'a, 'b> { pub(crate) struct MacroInvocation<'a, 'b> {
@ -97,14 +95,14 @@ impl<'a, 'b> MacroInvocation<'a, 'b> {
buf: &'b mut Buffer, buf: &'b mut Buffer,
generator: &mut Generator<'a, 'h>, generator: &mut Generator<'a, 'h>,
) -> Result<(), CompileError> { ) -> Result<(), CompileError> {
let mut named_arguments: HashMap<&str, _, FxBuildHasher> = HashMap::default(); let mut named_arguments = HashMap::default();
if let Some(Expr::NamedArgument(_, _)) = self.call_args.last().map(|expr| &***expr) { if let Some(Expr::NamedArgument(_, _)) = self.call_args.last().map(|expr| &***expr) {
// First we check that all named arguments actually exist in the called item. // First we check that all named arguments actually exist in the called item.
for (index, arg) in self.call_args.iter().enumerate().rev() { for (index, arg) in self.call_args.iter().enumerate().rev() {
let Expr::NamedArgument(arg_name, _) = &***arg else { let &Expr::NamedArgument(arg_name, _) = &***arg else {
break; break;
}; };
if !self.macro_def.args.iter().any(|(arg, _)| arg == arg_name) { if !self.macro_def.args.iter().any(|&(arg, _)| arg == arg_name) {
return Err(self.callsite_ctx.generate_error( return Err(self.callsite_ctx.generate_error(
format_args!( format_args!(
"no argument named `{arg_name}` in macro {}", "no argument named `{arg_name}` in macro {}",

View File

@ -1,5 +1,5 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::hash_map::{Entry, HashMap}; use std::collections::hash_map::Entry;
use std::fmt::Debug; use std::fmt::Debug;
use std::mem; use std::mem;
use std::ops::ControlFlow; use std::ops::ControlFlow;
@ -12,13 +12,14 @@ use parser::node::{
use parser::{Expr, Node, Span, Target, WithSpan}; use parser::{Expr, Node, Span, Target, WithSpan};
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::quote_spanned; use quote::quote_spanned;
use rustc_hash::FxBuildHasher;
use syn::Token; use syn::Token;
use super::{DisplayWrap, Generator, LocalMeta, MapChain, compile_time_escape, is_copyable}; use super::{DisplayWrap, Generator, LocalMeta, MapChain, compile_time_escape, is_copyable};
use crate::generator::{LocalCallerMeta, Writable, helpers, logic_op}; use crate::generator::{LocalCallerMeta, Writable, helpers, logic_op};
use crate::heritage::{Context, Heritage}; use crate::heritage::{Context, Heritage};
use crate::integration::{Buffer, string_escape}; use crate::integration::{Buffer, string_escape};
use crate::{CompileError, FileInfo, field_new, fmt_left, fmt_right, quote_into}; use crate::{CompileError, FileInfo, HashMap, field_new, fmt_left, fmt_right, quote_into};
impl<'a> Generator<'a, '_> { impl<'a> Generator<'a, '_> {
pub(super) fn impl_template_inner( pub(super) fn impl_template_inner(
@ -1270,7 +1271,8 @@ impl<'a> Generator<'a, '_> {
let mut targets = Buffer::new(); let mut targets = Buffer::new();
let mut lines = Buffer::new(); let mut lines = Buffer::new();
let mut expr_cache = HashMap::with_capacity(self.buf_writable.len()); let mut expr_cache =
HashMap::with_capacity_and_hasher(self.buf_writable.len(), FxBuildHasher);
// the `last_line` contains any sequence of trailing simple `writer.write_str()` calls // the `last_line` contains any sequence of trailing simple `writer.write_str()` calls
let mut trailing_simple_lines = Vec::new(); let mut trailing_simple_lines = Vec::new();

View File

@ -1,15 +1,13 @@
use core::fmt; use core::fmt;
use std::collections::HashMap;
use std::path::Path; use std::path::Path;
use std::sync::Arc; use std::sync::Arc;
use parser::node::{BlockDef, Macro}; use parser::node::{BlockDef, Macro};
use parser::{Node, Parsed, Span}; use parser::{Node, Parsed, Span};
use rustc_hash::FxBuildHasher;
use crate::config::Config; use crate::config::Config;
use crate::input::LiteralOrSpan; use crate::input::LiteralOrSpan;
use crate::{CompileError, FileInfo}; use crate::{CompileError, FileInfo, HashMap};
pub(crate) struct Heritage<'a, 'h> { pub(crate) struct Heritage<'a, 'h> {
pub(crate) root: &'h Context<'a>, pub(crate) root: &'h Context<'a>,
@ -19,7 +17,7 @@ pub(crate) struct Heritage<'a, 'h> {
impl<'a, 'h> Heritage<'a, 'h> { impl<'a, 'h> Heritage<'a, 'h> {
pub(crate) fn new( pub(crate) fn new(
mut root: &'h Context<'a>, mut root: &'h Context<'a>,
contexts: &'a HashMap<&'a Arc<Path>, Context<'a>, FxBuildHasher>, contexts: &'a HashMap<&'a Arc<Path>, Context<'a>>,
) -> Self { ) -> Self {
let mut blocks: BlockAncestry<'a, 'h> = root let mut blocks: BlockAncestry<'a, 'h> = root
.blocks .blocks
@ -38,16 +36,15 @@ impl<'a, 'h> Heritage<'a, 'h> {
} }
} }
type BlockAncestry<'a, 'h> = type BlockAncestry<'a, 'h> = HashMap<&'a str, Vec<(&'h Context<'a>, &'a BlockDef<'a>)>>;
HashMap<&'a str, Vec<(&'h Context<'a>, &'a BlockDef<'a>)>, FxBuildHasher>;
#[derive(Clone)] #[derive(Clone)]
pub(crate) struct Context<'a> { pub(crate) struct Context<'a> {
pub(crate) nodes: &'a [Box<Node<'a>>], pub(crate) nodes: &'a [Box<Node<'a>>],
pub(crate) extends: Option<Arc<Path>>, pub(crate) extends: Option<Arc<Path>>,
pub(crate) blocks: HashMap<&'a str, &'a BlockDef<'a>, FxBuildHasher>, pub(crate) blocks: HashMap<&'a str, &'a BlockDef<'a>>,
pub(crate) macros: HashMap<&'a str, &'a Macro<'a>, FxBuildHasher>, pub(crate) macros: HashMap<&'a str, &'a Macro<'a>>,
pub(crate) imports: HashMap<&'a str, Arc<Path>, FxBuildHasher>, pub(crate) imports: HashMap<&'a str, Arc<Path>>,
pub(crate) path: Option<&'a Path>, pub(crate) path: Option<&'a Path>,
pub(crate) parsed: &'a Parsed, pub(crate) parsed: &'a Parsed,
pub(crate) literal: Option<LiteralOrSpan>, pub(crate) literal: Option<LiteralOrSpan>,

View File

@ -1,5 +1,4 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::HashMap;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::str::FromStr; use std::str::FromStr;
use std::sync::Arc; use std::sync::Arc;
@ -7,13 +6,12 @@ use std::sync::Arc;
use parser::node::Whitespace; use parser::node::Whitespace;
use parser::{Node, Parsed}; use parser::{Node, Parsed};
use proc_macro2::Span; use proc_macro2::Span;
use rustc_hash::FxBuildHasher;
use syn::punctuated::Punctuated; use syn::punctuated::Punctuated;
use syn::spanned::Spanned; use syn::spanned::Spanned;
use syn::{Attribute, Expr, ExprLit, ExprPath, Ident, Lit, LitBool, LitStr, Meta, Token}; use syn::{Attribute, Expr, ExprLit, ExprPath, Ident, Lit, LitBool, LitStr, Meta, Token};
use crate::config::{Config, SyntaxAndCache}; use crate::config::{Config, SyntaxAndCache};
use crate::{CompileError, FileInfo, MsgValidEscapers}; use crate::{CompileError, FileInfo, HashMap, MsgValidEscapers};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub(crate) enum LiteralOrSpan { pub(crate) enum LiteralOrSpan {
@ -178,7 +176,7 @@ impl TemplateInput<'_> {
pub(crate) fn find_used_templates( pub(crate) fn find_used_templates(
&self, &self,
map: &mut HashMap<Arc<Path>, Arc<Parsed>, FxBuildHasher>, map: &mut HashMap<Arc<Path>, Arc<Parsed>>,
) -> Result<(), CompileError> { ) -> Result<(), CompileError> {
let (source, source_path) = match &self.source { let (source, source_path) = match &self.source {
Source::Source(s) => (s.clone(), None), Source::Source(s) => (s.clone(), None),

View File

@ -23,7 +23,7 @@ pub mod __macro_support {
} }
use std::borrow::{Borrow, Cow}; use std::borrow::{Borrow, Cow};
use std::collections::hash_map::{Entry, HashMap}; use std::collections::hash_map::Entry;
use std::fmt; use std::fmt;
use std::hash::{BuildHasher, Hash}; use std::hash::{BuildHasher, Hash};
use std::path::Path; use std::path::Path;
@ -623,7 +623,7 @@ fn var_expr_n(n: usize, span: proc_macro2::Span) -> Ident {
} }
#[derive(Debug)] #[derive(Debug)]
struct OnceMap<K, V>([Mutex<HashMap<K, V, FxBuildHasher>>; 8]); struct OnceMap<K, V>([Mutex<HashMap<K, V>>; 8]);
impl<K, V> Default for OnceMap<K, V> { impl<K, V> Default for OnceMap<K, V> {
fn default() -> Self { fn default() -> Self {
@ -718,3 +718,5 @@ macro_rules! quote_into {
} }
pub(crate) use {fmt_left, fmt_right, quote_into}; pub(crate) use {fmt_left, fmt_right, quote_into};
type HashMap<K, V> = std::collections::hash_map::HashMap<K, V, FxBuildHasher>;

View File

@ -21,6 +21,7 @@ name = "from_str"
harness = false harness = false
[dependencies] [dependencies]
rustc-hash = "2.0.0"
serde = { version = "1.0", optional = true } serde = { version = "1.0", optional = true }
serde_derive = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true }
unicode-ident = "1.0.12" unicode-ident = "1.0.12"

View File

@ -1,4 +1,3 @@
use std::collections::HashSet;
use std::str; use std::str;
use winnow::Parser; use winnow::Parser;
@ -11,9 +10,9 @@ use winnow::token::{one_of, take_until};
use crate::node::CondTest; use crate::node::CondTest;
use crate::{ use crate::{
CharLit, ErrorContext, Level, Num, ParseResult, PathOrIdentifier, StrLit, StrPrefix, WithSpan, CharLit, ErrorContext, HashSet, Level, Num, ParseResult, PathOrIdentifier, StrLit, StrPrefix,
can_be_variable_name, char_lit, cut_error, filter, identifier, keyword, not_suffix_with_hash, WithSpan, can_be_variable_name, char_lit, cut_error, filter, identifier, keyword,
num_lit, path_or_identifier, skip_ws0, skip_ws1, str_lit, ws, not_suffix_with_hash, num_lit, path_or_identifier, skip_ws0, skip_ws1, str_lit, ws,
}; };
macro_rules! expr_prec_layer { macro_rules! expr_prec_layer {
@ -253,7 +252,7 @@ impl<'a> Expr<'a> {
level: Level<'_>, level: Level<'_>,
) -> ParseResult<'a, Vec<WithSpan<'a, Box<Self>>>> { ) -> ParseResult<'a, Vec<WithSpan<'a, Box<Self>>>> {
let _level_guard = level.nest(i)?; let _level_guard = level.nest(i)?;
let mut named_arguments = HashSet::new(); let mut named_arguments = HashSet::default();
let start = *i; let start = *i;
preceded( preceded(

View File

@ -18,6 +18,7 @@ use std::path::Path;
use std::sync::Arc; use std::sync::Arc;
use std::{fmt, str}; use std::{fmt, str};
use rustc_hash::FxBuildHasher;
use winnow::ascii::take_escaped; use winnow::ascii::take_escaped;
use winnow::combinator::{ use winnow::combinator::{
alt, cut_err, delimited, empty, fail, not, opt, peek, preceded, repeat, terminated, alt, cut_err, delimited, empty, fail, not, opt, peek, preceded, repeat, terminated,
@ -1463,6 +1464,8 @@ fn cut_context_err<'a, T>(gen_err: impl FnOnce() -> ErrorContext<'a>) -> ParseRe
Err(ErrMode::Cut(gen_err())) Err(ErrMode::Cut(gen_err()))
} }
type HashSet<T> = std::collections::hash_set::HashSet<T, FxBuildHasher>;
#[cfg(not(windows))] #[cfg(not(windows))]
#[cfg(test)] #[cfg(test)]
mod test { mod test {

View File

@ -1,4 +1,3 @@
use std::collections::HashSet;
use std::str::{self, FromStr}; use std::str::{self, FromStr};
use winnow::combinator::{ use winnow::combinator::{
@ -11,8 +10,8 @@ use winnow::token::{any, rest, take_until};
use winnow::{ModalParser, Parser}; use winnow::{ModalParser, Parser};
use crate::{ use crate::{
ErrorContext, Expr, Filter, ParseResult, Span, State, Target, WithSpan, cut_error, filter, ErrorContext, Expr, Filter, HashSet, ParseResult, Span, State, Target, WithSpan, cut_error,
identifier, is_rust_keyword, keyword, skip_ws0, str_lit_without_prefix, ws, filter, identifier, is_rust_keyword, keyword, skip_ws0, str_lit_without_prefix, ws,
}; };
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@ -685,7 +684,7 @@ impl<'a> Macro<'a> {
} }
if let Some(ref params) = params { if let Some(ref params) = params {
let mut names = HashSet::new(); let mut names = HashSet::default();
let mut iter = params.iter(); let mut iter = params.iter();
while let Some((arg_name, default_value)) = iter.next() { while let Some((arg_name, default_value)) = iter.next() {