difftreelog
perf(evaluator) cache LazyVal/obj fields
in: master
2 files changed
crates/jsonnet-evaluator/src/obj.rsdiffbeforeafterboth--- a/crates/jsonnet-evaluator/src/obj.rs
+++ b/crates/jsonnet-evaluator/src/obj.rs
@@ -1,7 +1,8 @@
use crate::{evaluate_binary_op, Binding, Val};
use jsonnet_parser::{BinaryOpType, Visibility};
use std::{
- collections::{BTreeMap, BTreeSet},
+ cell::RefCell,
+ collections::{BTreeMap, BTreeSet, HashMap},
fmt::Debug,
rc::Rc,
};
@@ -17,6 +18,7 @@
pub struct ObjValueInternals {
super_obj: Option<ObjValue>,
this_entries: Rc<BTreeMap<String, ObjMember>>,
+ value_cache: RefCell<HashMap<String, Val>>,
}
pub struct ObjValue(pub(crate) Rc<ObjValueInternals>);
impl Debug for ObjValue {
@@ -48,6 +50,7 @@
ObjValue(Rc::new(ObjValueInternals {
super_obj,
this_entries,
+ value_cache: RefCell::new(HashMap::new()),
}))
}
pub fn with_super(&self, super_obj: ObjValue) -> ObjValue {
@@ -69,8 +72,14 @@
fields
}
pub fn get(&self, key: &str) -> Option<Val> {
- // TODO: Cache get_raw result
- self.get_raw(key, self)
+ if let Some(v) = self.0.value_cache.borrow().get(key) {
+ return Some(v.clone());
+ }
+ let v = self.get_raw(key, self).map(|v| v.unwrap_if_lazy());
+ if let Some(v) = v.clone() {
+ self.0.value_cache.borrow_mut().insert(key.to_owned(), v);
+ }
+ v
}
fn get_raw(&self, key: &str, real_this: &ObjValue) -> Option<Val> {
match (self.0.this_entries.get(key), &self.0.super_obj) {
crates/jsonnet-evaluator/src/val.rsdiffbeforeafterboth1use crate::{2 lazy_binding, rc_fn_helper, Context, FunctionDefault, FunctionRhs, LazyBinding, ObjValue,3};4use closure::closure;5use jsonnet_parser::{LiteralType, ParamsDesc};6use std::{7 collections::HashMap,8 fmt::{Debug, Display},9};1011rc_fn_helper!(LazyVal, lazy_val, dyn Fn() -> Val);1213#[derive(Debug, PartialEq, Clone)]14pub struct FuncDesc {15 pub ctx: Context,16 pub params: ParamsDesc,17 pub eval_rhs: FunctionRhs,18 pub eval_default: FunctionDefault,19}20impl FuncDesc {21 // TODO: Check for unset variables22 pub fn evaluate(&self, args: Vec<(Option<String>, Val)>) -> Val {23 let mut new_bindings: HashMap<String, LazyBinding> = HashMap::new();24 let future_ctx = Context::new_future();2526 // self.params27 // .with_defaults()28 // .into_iter()29 // .for_each(|Param(name, default)| {30 // let default = Rc::new(*default.unwrap());31 // new_bindings.insert(32 // name,33 // binding!(move |_, _| Val::Lazy(lazy_val!(|| self34 // .eval_default35 // .036 // .default(future_ctx.unwrap(), *default.clone())))),37 // );38 // });39 for (name, val) in args.clone().into_iter().filter(|e| e.0.is_some()) {40 new_bindings.insert(41 name.as_ref().unwrap().clone(),42 lazy_binding!(43 closure!(clone val, |_, _| lazy_val!(closure!(clone val, || val.clone())))44 ),45 );46 }47 for (i, param) in self.params.0.iter().enumerate() {48 if let Some((None, val)) = args.get(i) {49 new_bindings.insert(50 param.0.clone(),51 lazy_binding!(52 closure!(clone val, |_, _| lazy_val!(closure!(clone val, || val.clone())))53 ),54 );55 }56 }57 let ctx = self58 .ctx59 .extend(new_bindings, None, None, None)60 .into_future(future_ctx);61 self.eval_rhs.0(ctx)62 }63}6465#[derive(Debug, PartialEq, Clone)]66pub enum Val {67 Literal(LiteralType),68 Str(String),69 Num(f64),70 Lazy(LazyVal),71 Arr(Vec<Val>),72 Obj(ObjValue),73 Func(FuncDesc),7475 // Library functions implemented in native76 Intristic(String, String),77}78impl Val {79 pub fn unwrap_if_lazy(self) -> Self {80 if let Val::Lazy(v) = self {81 v.0().unwrap_if_lazy()82 } else {83 self84 }85 }86 pub fn type_of(&self) -> &'static str {87 match self {88 Val::Str(..) => "string",89 Val::Num(..) => "number",90 Val::Arr(..) => "array",91 Val::Obj(..) => "object",92 Val::Func(..) => "function",93 _ => panic!("no native type found"),94 }95 }96}97impl Display for Val {98 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {99 match self {100 Val::Literal(v) => write!(f, "{}", v)?,101 Val::Str(str) => write!(f, "\"{}\"", str)?,102 Val::Num(n) => write!(f, "{}", n)?,103 Val::Arr(values) => {104 write!(f, "[")?;105 let mut first = true;106 for value in values {107 if first {108 first = false;109 } else {110 write!(f, ",")?;111 }112 write!(f, "{}", value)?;113 }114 write!(f, "]")?;115 }116 Val::Obj(value) => {117 write!(f, "{{")?;118 let mut first = true;119 for field in value.fields() {120 if first {121 first = false;122 } else {123 write!(f, ",")?;124 }125 write!(f, "\"{}\":", field)?;126 write!(f, "{}", value.get(&field).unwrap())?;127 }128 write!(f, "}}")?;129 }130 Val::Lazy(lazy) => {131 write!(f, "{}", lazy.0())?;132 }133 Val::Func(_) => {134 write!(f, "<<FUNC>>")?;135 }136 v => panic!("no json equivalent for {:?}", v),137 };138 Ok(())139 }140}141142pub fn bool_val(v: bool) -> Val {143 if v {144 Val::Literal(LiteralType::True)145 } else {146 Val::Literal(LiteralType::False)147 }148}1use crate::{lazy_binding, Context, FunctionDefault, FunctionRhs, LazyBinding, ObjValue};2use closure::closure;3use jsonnet_parser::ParamsDesc;4use std::{5 cell::RefCell,6 collections::HashMap,7 fmt::{Debug, Display},8 rc::Rc,9};1011struct LazyValInternals {12 pub f: Box<dyn Fn() -> Val>,13 pub cached: RefCell<Option<Val>>,14}15#[derive(Clone)]16pub struct LazyVal(Rc<LazyValInternals>);17impl LazyVal {18 pub fn new(f: Box<dyn Fn() -> Val>) -> Self {19 LazyVal(Rc::new(LazyValInternals {20 f,21 cached: RefCell::new(None),22 }))23 }24 pub fn evaluate(&self) -> Val {25 {26 let cached = self.0.cached.borrow();27 if cached.is_some() {28 return cached.clone().unwrap();29 }30 }31 let result = (self.0.f)();32 self.0.cached.borrow_mut().replace(result.clone());33 result34 }35}36#[macro_export]37macro_rules! lazy_val {38 ($f: expr) => {39 $crate::LazyVal::new(Box::new($f))40 };41}42impl Debug for LazyVal {43 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {44 write!(f, "Lazy")45 }46}47impl PartialEq for LazyVal {48 fn eq(&self, other: &Self) -> bool {49 Rc::ptr_eq(&self.0, &other.0)50 }51}5253#[derive(Debug, PartialEq, Clone)]54pub struct FuncDesc {55 pub ctx: Context,56 pub params: ParamsDesc,57 pub eval_rhs: FunctionRhs,58 pub eval_default: FunctionDefault,59}60impl FuncDesc {61 // TODO: Check for unset variables62 pub fn evaluate(&self, args: Vec<(Option<String>, Val)>) -> Val {63 let mut new_bindings: HashMap<String, LazyBinding> = HashMap::new();64 let future_ctx = Context::new_future();6566 // self.params67 // .with_defaults()68 // .into_iter()69 // .for_each(|Param(name, default)| {70 // let default = Rc::new(*default.unwrap());71 // new_bindings.insert(72 // name,73 // binding!(move |_, _| Val::Lazy(lazy_val!(|| self74 // .eval_default75 // .076 // .default(future_ctx.unwrap(), *default.clone())))),77 // );78 // });79 for (name, val) in args.clone().into_iter().filter(|e| e.0.is_some()) {80 new_bindings.insert(81 name.as_ref().unwrap().clone(),82 lazy_binding!(83 closure!(clone val, |_, _| lazy_val!(closure!(clone val, || val.clone())))84 ),85 );86 }87 for (i, param) in self.params.0.iter().enumerate() {88 if let Some((None, val)) = args.get(i) {89 new_bindings.insert(90 param.0.clone(),91 lazy_binding!(92 closure!(clone val, |_, _| lazy_val!(closure!(clone val, || val.clone())))93 ),94 );95 }96 }97 let ctx = self98 .ctx99 .extend(new_bindings, None, None, None)100 .into_future(future_ctx);101 self.eval_rhs.0(ctx)102 }103}104105#[derive(Debug, PartialEq, Clone)]106pub enum Val {107 Bool(bool),108 Null,109 Str(String),110 Num(f64),111 Lazy(LazyVal),112 Arr(Vec<Val>),113 Obj(ObjValue),114 Func(FuncDesc),115116 // Library functions implemented in native117 Intristic(String, String),118}119impl Val {120 pub fn unwrap_if_lazy(self) -> Self {121 if let Val::Lazy(v) = self {122 v.evaluate().unwrap_if_lazy()123 } else {124 self125 }126 }127 pub fn type_of(&self) -> &'static str {128 match self {129 Val::Str(..) => "string",130 Val::Num(..) => "number",131 Val::Arr(..) => "array",132 Val::Obj(..) => "object",133 Val::Func(..) => "function",134 _ => panic!("no native type found"),135 }136 }137}138impl Display for Val {139 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {140 match self {141 Val::Str(str) => write!(f, "\"{}\"", str)?,142 Val::Num(n) => write!(f, "{}", n)?,143 Val::Arr(values) => {144 write!(f, "[")?;145 let mut first = true;146 for value in values {147 if first {148 first = false;149 } else {150 write!(f, ",")?;151 }152 write!(f, "{}", value)?;153 }154 write!(f, "]")?;155 }156 Val::Obj(value) => {157 write!(f, "{{")?;158 let mut first = true;159 for field in value.fields() {160 if first {161 first = false;162 } else {163 write!(f, ",")?;164 }165 write!(f, "\"{}\":", field)?;166 write!(f, "{}", value.get(&field).unwrap())?;167 }168 write!(f, "}}")?;169 }170 Val::Lazy(lazy) => {171 write!(f, "{}", lazy.evaluate())?;172 }173 Val::Func(_) => {174 write!(f, "<<FUNC>>")?;175 }176 v => panic!("no json equivalent for {:?}", v),177 };178 Ok(())179 }180}181182pub fn bool_val(v: bool) -> Val {183 Val::Bool(v)184}