diff --git a/rinja_derive/src/config.rs b/rinja_derive/src/config.rs index 91b62911..894de13c 100644 --- a/rinja_derive/src/config.rs +++ b/rinja_derive/src/config.rs @@ -6,15 +6,13 @@ use std::path::{Path, PathBuf}; use std::sync::{Arc, OnceLock}; use std::{env, fs}; -use once_map::sync::OnceMap; use parser::node::Whitespace; use parser::{ParseError, Parsed, Syntax, SyntaxBuilder}; use proc_macro2::Span; -use rustc_hash::FxBuildHasher; #[cfg(feature = "config")] use serde::Deserialize; -use crate::{CRATE, CompileError, FileInfo}; +use crate::{CRATE, CompileError, FileInfo, OnceMap}; #[derive(Debug)] pub(crate) struct Config { @@ -77,23 +75,20 @@ impl Config { template_whitespace: Option<&str>, config_span: Option, ) -> Result<&'static Config, CompileError> { - static CACHE: ManuallyDrop< - OnceLock>, - > = ManuallyDrop::new(OnceLock::new()); - CACHE.get_or_init(OnceMap::default).get_or_try_insert_ref( + static CACHE: ManuallyDrop>> = + ManuallyDrop::new(OnceLock::new()); + CACHE.get_or_init(OnceMap::default).get_or_try_insert( &ConfigKey { source: source.into(), config_path: config_path.map(Cow::Borrowed), template_whitespace: template_whitespace.map(Cow::Borrowed), }, - config_span, - ConfigKey::to_owned, - |config_span, key| { - let config = Config::new_uncached(*key, config_span)?; + |key| { + let config = Config::new_uncached(key.to_owned(), config_span)?; let config = &*Box::leak(Box::new(config)); - Ok((config, config)) + Ok((config._key, config)) }, - |_, _, config| config, + |config| *config, ) } } @@ -234,7 +229,7 @@ impl Config { #[derive(Debug, Default)] pub(crate) struct SyntaxAndCache<'a> { syntax: Syntax<'a>, - cache: OnceMap, FxBuildHasher>, + cache: OnceMap>, } impl<'a> Deref for SyntaxAndCache<'a> { @@ -281,28 +276,27 @@ impl<'a> SyntaxAndCache<'a> { source: Arc, source_path: Option>, ) -> Result, ParseError> { - self.cache.get_or_try_insert_ref( + self.cache.get_or_try_insert( &SyntaxAndCacheKey { source: Cow::Owned(source), source_path: source_path.map(Cow::Owned), }, - &self.syntax, |key| { - OwnedSyntaxAndCacheKey(SyntaxAndCacheKey { + let key = OwnedSyntaxAndCacheKey(SyntaxAndCacheKey { source: Cow::Owned(Arc::clone(key.source.as_ref())), source_path: key .source_path .as_deref() .map(|v| Cow::Owned(Arc::clone(v))), - }) - }, - |syntax, key| { - let source = Arc::clone(key.source.as_ref()); - let source_path = key.source_path.as_deref().map(Arc::clone); - let parsed = Arc::new(Parsed::new(source, source_path, syntax)?); - Ok((Arc::clone(&parsed), parsed)) + }); + let parsed = Parsed::new( + Arc::clone(key.source.as_ref()), + key.source_path.as_deref().map(Arc::clone), + &self.syntax, + )?; + Ok((key, Arc::new(parsed))) }, - |_, _, cached| Arc::clone(cached), + Arc::clone, ) } } diff --git a/rinja_derive/src/input.rs b/rinja_derive/src/input.rs index dbf0e525..497f683f 100644 --- a/rinja_derive/src/input.rs +++ b/rinja_derive/src/input.rs @@ -6,7 +6,6 @@ use std::path::{Path, PathBuf}; use std::sync::{Arc, OnceLock}; use mime::Mime; -use once_map::OnceMap; use parser::{Node, Parsed}; use proc_macro2::Span; use rustc_hash::FxBuildHasher; @@ -14,7 +13,7 @@ use syn::punctuated::Punctuated; use syn::spanned::Spanned; use crate::config::{Config, SyntaxAndCache}; -use crate::{CompileError, FileInfo, MsgValidEscapers}; +use crate::{CompileError, FileInfo, MsgValidEscapers, OnceMap}; pub(crate) struct TemplateInput<'a> { pub(crate) ast: &'a syn::DeriveInput, @@ -766,19 +765,16 @@ pub(crate) fn get_template_source( tpl_path: &Arc, import_from: Option<(&Arc, &str, &str)>, ) -> Result, CompileError> { - static CACHE: OnceLock, Arc, FxBuildHasher>> = OnceLock::new(); + static CACHE: OnceLock, Arc>> = OnceLock::new(); - CACHE.get_or_init(OnceMap::default).get_or_try_insert_ref( + CACHE.get_or_init(OnceMap::default).get_or_try_insert( tpl_path, - (), - Arc::clone, - |(), tpl_path| match read_to_string(tpl_path) { + |tpl_path| match read_to_string(tpl_path) { Ok(mut source) => { if source.ends_with('\n') { let _ = source.pop(); } - let source = Arc::from(source); - Ok((Arc::clone(&source), source)) + Ok((Arc::clone(tpl_path), Arc::from(source))) } Err(err) => Err(CompileError::new( format_args!( @@ -790,7 +786,7 @@ pub(crate) fn get_template_source( }), )), }, - |(), _, cached| Arc::clone(cached), + Arc::clone, ) } diff --git a/rinja_derive/src/lib.rs b/rinja_derive/src/lib.rs index 9eb6d89f..187af0da 100644 --- a/rinja_derive/src/lib.rs +++ b/rinja_derive/src/lib.rs @@ -10,10 +10,12 @@ mod input; #[cfg(test)] mod tests; -use std::borrow::Cow; -use std::collections::HashMap; +use std::borrow::{Borrow, Cow}; +use std::collections::hash_map::{Entry, HashMap}; use std::fmt; +use std::hash::{BuildHasher, Hash}; use std::path::Path; +use std::sync::Mutex; use config::{Config, read_config_file}; use generator::{Generator, MapChain}; @@ -25,6 +27,7 @@ use proc_macro::TokenStream as TokenStream12; #[cfg(feature = "__standalone")] use proc_macro2::TokenStream as TokenStream12; use proc_macro2::{Span, TokenStream}; +use rustc_hash::FxBuildHasher; use syn::parse_quote_spanned; /// The `Template` derive macro and its `template()` attribute. @@ -379,6 +382,42 @@ impl fmt::Display for MsgValidEscapers<'_> { } } +#[derive(Debug)] +struct OnceMap([Mutex>; 8]); + +impl Default for OnceMap { + fn default() -> Self { + Self(Default::default()) + } +} + +impl OnceMap { + // The API of this function was copied, and adapted from the `once_map` crate + // . + fn get_or_try_insert( + &self, + key: &Q, + make_key_value: impl FnOnce(&Q) -> Result<(K, V), E>, + to_value: impl FnOnce(&V) -> T, + ) -> Result + where + K: Borrow, + Q: Hash + Eq, + { + let shard_idx = (FxBuildHasher.hash_one(key) % self.0.len() as u64) as usize; + let mut shard = self.0[shard_idx].lock().unwrap(); + Ok(to_value(if let Some(v) = shard.get(key) { + v + } else { + let (k, v) = make_key_value(key)?; + match shard.entry(k) { + Entry::Vacant(entry) => entry.insert(v), + Entry::Occupied(_) => unreachable!("key in map when it should not have been"), + } + })) + } +} + // This is used by the code generator to decide whether a named filter is part of // Rinja or should refer to a local `filters` module. const BUILT_IN_FILTERS: &[&str] = &[ diff --git a/rinja_derive_standalone/Cargo.toml b/rinja_derive_standalone/Cargo.toml index f503b3d8..f0768a17 100644 --- a/rinja_derive_standalone/Cargo.toml +++ b/rinja_derive_standalone/Cargo.toml @@ -42,7 +42,6 @@ serde = { version = "1.0", optional = true, features = ["derive"] } memchr = "2" mime = "0.3" mime_guess = "2" -once_map = { version = "0.4.18", default-features = false, features = ["std"] } proc-macro2 = "1" quote = "1" rustc-hash = "2.0.0"