--- a/Cargo.lock +++ b/Cargo.lock @@ -172,6 +172,7 @@ "jrsonnet-stdlib", "md5", "pathdiff", + "rustc-hash", "serde", "serde_json", "structdump", @@ -322,6 +323,12 @@ ] [[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] name = "ryu" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" --- a/crates/jrsonnet-evaluator/Cargo.toml +++ b/crates/jrsonnet-evaluator/Cargo.toml @@ -9,7 +9,7 @@ # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] -default = ["serialized-stdlib", "faster", "explaining-traces"] +default = ["serialized-stdlib", "faster", "explaining-traces", "serde-json"] # Serializes standard library AST instead of parsing them every run serialized-stdlib = ["serde", "bincode", "jrsonnet-parser/deserialize"] # Allow to convert Val into serde_json::Value and backwards @@ -35,6 +35,7 @@ md5 = "0.7.0" base64 = "0.12.3" +rustc-hash = "1.1.0" # Serialized stdlib [dependencies.serde] --- a/crates/jrsonnet-evaluator/src/builtin/mod.rs +++ b/crates/jrsonnet-evaluator/src/builtin/mod.rs @@ -158,7 +158,7 @@ ("std", "native") => parse_args!(context, "std.native", args, 1, [ 0, x: [Val::Str]!!Val::Str, vec![ValType::Str]; ], { - Ok(with_state(|s| s.settings().ext_natives.get(&x).cloned()).map(|v| Val::Func(FuncVal::NativeExt(x.clone(), v))).ok_or_else( + Ok(with_state(|s| s.settings().ext_natives.get(&x).cloned()).map(|v| Val::Func(Rc::new(FuncVal::NativeExt(x.clone(), v)))).ok_or_else( || UndefinedExternalFunction(x), )?) })?, @@ -212,7 +212,7 @@ if arr.len() <= 1 { return Ok(Val::Arr(arr)) } - Ok(Val::Arr(sort::sort(context, arr, keyF)?)) + Ok(Val::Arr(sort::sort(context, arr, &keyF)?)) })?, // faster ("std", "format") => parse_args!(context, "std.format", args, 2, [ --- a/crates/jrsonnet-evaluator/src/ctx.rs +++ b/crates/jrsonnet-evaluator/src/ctx.rs @@ -2,6 +2,8 @@ error::Error::*, future_wrapper, map::LayeredHashMap, rc_fn_helper, resolved_lazy_val, LazyBinding, LazyVal, ObjValue, Result, Val, }; +use rustc_hash::FxHashMap; +use std::hash::BuildHasherDefault; use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc}; rc_fn_helper!( @@ -71,14 +73,15 @@ } pub fn with_var(self, name: Rc, value: Val) -> Context { - let mut new_bindings = HashMap::with_capacity(1); + let mut new_bindings = + FxHashMap::with_capacity_and_hasher(1, BuildHasherDefault::default()); new_bindings.insert(name, resolved_lazy_val!(value)); self.extend(new_bindings, None, None, None) } pub fn extend( self, - new_bindings: HashMap, LazyVal>, + new_bindings: FxHashMap, LazyVal>, new_dollar: Option, new_this: Option, new_super_obj: Option, @@ -127,7 +130,8 @@ ) -> Result { let this = new_this.or_else(|| self.0.this.clone()); let super_obj = new_super_obj.or_else(|| self.0.super_obj.clone()); - let mut new = HashMap::with_capacity(new_bindings.len()); + let mut new = + FxHashMap::with_capacity_and_hasher(new_bindings.len(), BuildHasherDefault::default()); for (k, v) in new_bindings.into_iter() { new.insert(k, v.evaluate(this.clone(), super_obj.clone())?); } --- a/crates/jrsonnet-evaluator/src/evaluate.rs +++ b/crates/jrsonnet-evaluator/src/evaluate.rs @@ -9,6 +9,7 @@ ForSpecData, IfSpecData, LiteralType, LocExpr, Member, ObjBody, ParamsDesc, UnaryOpType, Visibility, }; +use rustc_hash::FxHashMap; use std::{collections::HashMap, rc::Rc}; pub fn evaluate_binding(b: &BindSpec, context_creator: ContextCreator) -> (Rc, LazyBinding) { @@ -45,7 +46,7 @@ } pub fn evaluate_method(ctx: Context, name: Rc, params: ParamsDesc, body: LocExpr) -> Val { - Val::Func(FuncVal::Normal(Rc::new(FuncDesc { + Val::Func(Rc::new(FuncVal::Normal(FuncDesc { name, ctx, params, @@ -351,7 +352,7 @@ let key = evaluate(ctx.clone(), &obj.key)?; let value = LazyBinding::Bindable(Rc::new( closure!(clone ctx, clone obj.value, |this, _super_obj| { - Ok(LazyVal::new_resolved(evaluate(ctx.clone().extend(HashMap::new(), None, this, None), &value)?)) + Ok(LazyVal::new_resolved(evaluate(ctx.clone().extend(FxHashMap::default(), None, this, None), &value)?)) }), )); @@ -468,7 +469,7 @@ } else if let Some(Val::Str(n)) = v.get("__intristic_namespace__".into())? { - Ok(Val::Func(FuncVal::Intristic(n, s))) + Ok(Val::Func(Rc::new(FuncVal::Intristic(n, s)))) } else { throw!(NoSuchField(s)) } --- a/crates/jrsonnet-evaluator/src/function.rs +++ b/crates/jrsonnet-evaluator/src/function.rs @@ -1,7 +1,8 @@ use crate::{error::Error::*, evaluate, lazy_val, resolved_lazy_val, throw, Context, Result, Val}; use closure::closure; use jrsonnet_parser::{ArgsDesc, ParamsDesc}; -use std::{collections::HashMap, rc::Rc}; +use rustc_hash::FxHashMap; +use std::{collections::HashMap, hash::BuildHasherDefault, rc::Rc}; const NO_DEFAULT_CONTEXT: &str = "no default context set for call with defined default parameter value"; @@ -20,7 +21,7 @@ args: &ArgsDesc, tailstrict: bool, ) -> Result { - let mut out = HashMap::with_capacity(params.len()); + let mut out = HashMap::with_capacity_and_hasher(params.len(), BuildHasherDefault::default()); let mut positioned_args = vec![None; params.0.len()]; for (id, arg) in args.iter().enumerate() { let idx = if let Some(name) = &arg.0 { @@ -67,7 +68,7 @@ args: &HashMap, Val>, tailstrict: bool, ) -> Result { - let mut out = HashMap::with_capacity(params.len()); + let mut out = FxHashMap::with_capacity_and_hasher(params.len(), BuildHasherDefault::default()); let mut positioned_args = vec![None; params.0.len()]; for (name, val) in args.iter() { let idx = params @@ -115,7 +116,7 @@ params: &ParamsDesc, args: &[Val], ) -> Result { - let mut out = HashMap::with_capacity(params.len()); + let mut out = FxHashMap::with_capacity_and_hasher(params.len(), BuildHasherDefault::default()); let mut positioned_args = vec![None; params.0.len()]; for (id, arg) in args.iter().enumerate() { if id >= params.len() { --- a/crates/jrsonnet-evaluator/src/map.rs +++ b/crates/jrsonnet-evaluator/src/map.rs @@ -1,16 +1,17 @@ -use std::{borrow::Borrow, collections::HashMap, hash::Hash, rc::Rc}; +use rustc_hash::FxHashMap; +use std::{borrow::Borrow, hash::Hash, rc::Rc}; #[derive(Default, Debug)] struct LayeredHashMapInternals { parent: Option>, - current: HashMap, + current: FxHashMap, } #[derive(Debug)] pub struct LayeredHashMap(Rc>); impl LayeredHashMap { - pub fn extend(self, new_layer: HashMap) -> Self { + pub fn extend(self, new_layer: FxHashMap) -> Self { match Rc::try_unwrap(self.0) { Ok(mut map) => { map.current.extend(new_layer); @@ -45,7 +46,7 @@ fn default() -> Self { LayeredHashMap(Rc::new(LayeredHashMapInternals { parent: None, - current: HashMap::new(), + current: FxHashMap::default(), })) } } --- a/crates/jrsonnet-evaluator/src/val.rs +++ b/crates/jrsonnet-evaluator/src/val.rs @@ -71,15 +71,16 @@ pub body: LocExpr, } -#[derive(Debug, Clone)] +#[derive(Debug)] pub enum FuncVal { /// Plain function implemented in jsonnet - Normal(Rc), + Normal(FuncDesc), /// Standard library function Intristic(Rc, Rc), /// Library functions implemented in native NativeExt(Rc, Rc), } + impl PartialEq for FuncVal { fn eq(&self, other: &Self) -> bool { match (self, other) { @@ -212,8 +213,9 @@ Lazy(LazyVal), Arr(Rc>), Obj(ObjValue), - Func(FuncVal), + Func(Rc), } + macro_rules! matches_unwrap { ($e: expr, $p: pat, $r: expr) => { match $e {