git.delta.rocks / jrsonnet / refs/commits / e4a890bf0c31

difftreelog

perf mutate context if operating on only strong ref

Лач2020-07-21parent: #84f648e.patch.diff
in: master

4 files changed

modifiedcrates/jrsonnet-evaluator/src/ctx.rsdiffbeforeafterboth
before · crates/jrsonnet-evaluator/src/ctx.rs
1use 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}
modifiedcrates/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)?))
 						}),
 					));
 
modifiedcrates/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]
modifiedcrates/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>