difftreelog
perf mutate context if operating on only strong ref
in: master
4 files changed
crates/jrsonnet-evaluator/src/ctx.rsdiffbeforeafterboth1use crate::{2 error::Error::*, future_wrapper, map::LayeredHashMap, rc_fn_helper, resolved_lazy_val,3 LazyBinding, LazyVal, ObjValue, Result, Val,4};5use std::{6 cell::RefCell,7 collections::HashMap,8 fmt::Debug,9 rc::{Rc, Weak},10};1112rc_fn_helper!(13 ContextCreator,14 context_creator,15 dyn Fn(Option<ObjValue>, Option<ObjValue>) -> Result<Context>16);1718future_wrapper!(Context, FutureContext);1920struct ContextInternals {21 dollar: Option<ObjValue>,22 this: Option<ObjValue>,23 super_obj: Option<ObjValue>,24 bindings: LayeredHashMap<Rc<str>, LazyVal>,25}26impl Debug for ContextInternals {27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {28 f.debug_struct("Context")29 .field("this", &self.this.as_ref().map(|e| Rc::as_ptr(&e.0)))30 .field("bindings", &self.bindings)31 .finish()32 }33}3435#[derive(Debug, Clone)]36pub struct Context(Rc<ContextInternals>);37impl Context {38 pub fn new_future() -> FutureContext {39 FutureContext(Rc::new(RefCell::new(None)))40 }4142 pub fn dollar(&self) -> &Option<ObjValue> {43 &self.0.dollar44 }4546 pub fn this(&self) -> &Option<ObjValue> {47 &self.0.this48 }4950 pub fn super_obj(&self) -> &Option<ObjValue> {51 &self.0.super_obj52 }5354 pub fn new() -> Context {55 Context(Rc::new(ContextInternals {56 dollar: None,57 this: None,58 super_obj: None,59 bindings: LayeredHashMap::default(),60 }))61 }6263 pub fn binding(&self, name: Rc<str>) -> Result<LazyVal> {64 Ok(self65 .066 .bindings67 .get(&name)68 .cloned()69 .ok_or_else(|| UnknownVariable(name))?)70 }71 pub fn into_future(self, ctx: FutureContext) -> Context {72 {73 ctx.0.borrow_mut().replace(self);74 }75 ctx.unwrap()76 }7778 pub fn with_var(&self, name: Rc<str>, value: Val) -> Result<Context> {79 let mut new_bindings = HashMap::with_capacity(1);80 new_bindings.insert(name, resolved_lazy_val!(value));81 self.extend(new_bindings, None, None, None)82 }8384 pub fn extend(85 &self,86 new_bindings: HashMap<Rc<str>, LazyVal>,87 new_dollar: Option<ObjValue>,88 new_this: Option<ObjValue>,89 new_super_obj: Option<ObjValue>,90 ) -> Result<Context> {91 let dollar = new_dollar.or_else(|| self.0.dollar.clone());92 let this = new_this.or_else(|| self.0.this.clone());93 let super_obj = new_super_obj.or_else(|| self.0.super_obj.clone());94 let bindings = if new_bindings.is_empty() {95 self.0.bindings.clone()96 } else {97 self.0.bindings.extend(new_bindings)98 };99 Ok(Context(Rc::new(ContextInternals {100 dollar,101 this,102 super_obj,103 bindings,104 })))105 }106 pub fn extend_unbound(107 &self,108 new_bindings: HashMap<Rc<str>, LazyBinding>,109 new_dollar: Option<ObjValue>,110 new_this: Option<ObjValue>,111 new_super_obj: Option<ObjValue>,112 ) -> Result<Context> {113 let this = new_this.or_else(|| self.0.this.clone());114 let super_obj = new_super_obj.or_else(|| self.0.super_obj.clone());115 let mut new = HashMap::with_capacity(new_bindings.len());116 for (k, v) in new_bindings.into_iter() {117 new.insert(k, v.evaluate(this.clone(), super_obj.clone())?);118 }119 self.extend(new, new_dollar, this, super_obj)120 }121 pub fn into_weak(self) -> WeakContext {122 WeakContext(Rc::downgrade(&self.0))123 }124}125126impl Default for Context {127 fn default() -> Self {128 Self::new()129 }130}131132impl PartialEq for Context {133 fn eq(&self, other: &Self) -> bool {134 Rc::ptr_eq(&self.0, &other.0)135 }136}137138#[derive(Debug, Clone)]139pub struct WeakContext(Weak<ContextInternals>);140impl WeakContext {141 pub fn upgrade(&self) -> Context {142 Context(self.0.upgrade().expect("context is removed"))143 }144}145impl PartialEq for WeakContext {146 fn eq(&self, other: &Self) -> bool {147 self.0.ptr_eq(&other.0)148 }149}crates/jrsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/evaluate.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate.rs
@@ -209,7 +209,7 @@
for item in list.iter() {
let item = item.unwrap_if_lazy()?;
out.push(evaluate_comp(
- context.with_var(var.clone(), item.clone())?,
+ context.clone().with_var(var.clone(), item.clone()),
value,
&specs[1..],
)?);
@@ -227,7 +227,7 @@
let future_this = FutureObjValue::new();
let context_creator = context_creator!(
closure!(clone context, clone new_bindings, |this: Option<ObjValue>, super_obj: Option<ObjValue>| {
- Ok(context.extend_unbound(
+ Ok(context.clone().extend_unbound(
new_bindings.clone().unwrap(),
context.dollar().clone().or_else(||this.clone()),
Some(this.unwrap()),
@@ -332,7 +332,7 @@
let new_bindings = FutureNewBindings::new();
let context_creator = context_creator!(
closure!(clone context, clone new_bindings, |this: Option<ObjValue>, super_obj: Option<ObjValue>| {
- Ok(context.extend_unbound(
+ Ok(context.clone().extend_unbound(
new_bindings.clone().unwrap(),
context.dollar().clone().or_else(||this.clone()),
None,
@@ -354,7 +354,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.extend(HashMap::new(), None, this, None)?, &value)?))
+ Ok(LazyVal::new_resolved(evaluate(ctx.clone().extend(HashMap::new(), None, this, None), &value)?))
}),
));
crates/jrsonnet-evaluator/src/function.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/function.rs
+++ b/crates/jrsonnet-evaluator/src/function.rs
@@ -57,7 +57,7 @@
out.insert(p.0.clone(), val);
}
- Ok(body_ctx.unwrap_or(ctx).extend(out, None, None, None)?)
+ Ok(body_ctx.unwrap_or(ctx).extend(out, None, None, None))
}
pub fn parse_function_call_map(
@@ -106,7 +106,7 @@
out.insert(p.0.clone(), val);
}
- Ok(body_ctx.unwrap_or(ctx).extend(out, None, None, None)?)
+ Ok(body_ctx.unwrap_or(ctx).extend(out, None, None, None))
}
pub(crate) fn place_args(
@@ -135,7 +135,7 @@
out.insert(p.0.clone(), resolved_lazy_val!(val));
}
- Ok(body_ctx.unwrap_or(ctx).extend(out, None, None, None)?)
+ Ok(body_ctx.unwrap_or(ctx).extend(out, None, None, None))
}
#[macro_export]
crates/jrsonnet-evaluator/src/map.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/map.rs
+++ b/crates/jrsonnet-evaluator/src/map.rs
@@ -10,12 +10,17 @@
pub struct LayeredHashMap<K: Hash, V>(Rc<LayeredHashMapInternals<K, V>>);
impl<K: Hash + Eq, V> LayeredHashMap<K, V> {
- pub fn extend(&self, new_layer: HashMap<K, V>) -> Self {
- let super_map = self.clone();
- LayeredHashMap(Rc::new(LayeredHashMapInternals {
- parent: Some(super_map),
- current: new_layer,
- }))
+ pub fn extend(self, new_layer: HashMap<K, V>) -> Self {
+ match Rc::try_unwrap(self.0) {
+ Ok(mut map) => {
+ map.current.extend(new_layer);
+ LayeredHashMap(Rc::new(map))
+ }
+ Err(this) => LayeredHashMap(Rc::new(LayeredHashMapInternals {
+ parent: Some(LayeredHashMap(this)),
+ current: new_layer,
+ })),
+ }
}
pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<&V>