git.delta.rocks / jrsonnet / refs/commits / 8e1facac94b0

difftreelog

source

crates/jrsonnet-evaluator/src/ctx.rs4.6 KiBsourcehistory
1use crate::{2	error::Error::*, map::LayeredHashMap, resolved_lazy_val, FutureWrapper, LazyBinding, LazyVal,3	ObjValue, Result, Val,4};5use jrsonnet_interner::IStr;6use rustc_hash::FxHashMap;7use std::hash::BuildHasherDefault;8use std::{fmt::Debug, rc::Rc};910#[derive(Clone)]11pub struct ContextCreator(pub Context, pub FutureWrapper<FxHashMap<IStr, LazyBinding>>);12impl ContextCreator {13	pub fn create(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Result<Context> {14		self.0.clone().extend_unbound(15			self.1.clone().unwrap(),16			self.0.dollar().clone().or_else(|| this.clone()),17			this,18			super_obj,19		)20	}21}2223struct ContextInternals {24	dollar: Option<ObjValue>,25	this: Option<ObjValue>,26	super_obj: Option<ObjValue>,27	bindings: LayeredHashMap<LazyVal>,28}29impl Debug for ContextInternals {30	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {31		f.debug_struct("Context")32			.field("this", &self.this.as_ref().map(|e| Rc::as_ptr(&e.0)))33			.field("bindings", &self.bindings)34			.finish()35	}36}3738#[derive(Debug, Clone)]39pub struct Context(Rc<ContextInternals>);40impl Context {41	pub fn new_future() -> FutureWrapper<Self> {42		FutureWrapper::new()43	}4445	pub fn dollar(&self) -> &Option<ObjValue> {46		&self.0.dollar47	}4849	pub fn this(&self) -> &Option<ObjValue> {50		&self.0.this51	}5253	pub fn super_obj(&self) -> &Option<ObjValue> {54		&self.0.super_obj55	}5657	pub fn new() -> Self {58		Self(Rc::new(ContextInternals {59			dollar: None,60			this: None,61			super_obj: None,62			bindings: LayeredHashMap::default(),63		}))64	}6566	pub fn binding(&self, name: IStr) -> Result<LazyVal> {67		Ok(self68			.069			.bindings70			.get(&name)71			.cloned()72			.ok_or(VariableIsNotDefined(name))?)73	}74	pub fn into_future(self, ctx: FutureWrapper<Self>) -> Self {75		{76			ctx.0.borrow_mut().replace(self);77		}78		ctx.unwrap()79	}8081	pub fn with_var(self, name: IStr, value: Val) -> Self {82		let mut new_bindings =83			FxHashMap::with_capacity_and_hasher(1, BuildHasherDefault::default());84		new_bindings.insert(name, resolved_lazy_val!(value));85		self.extend(new_bindings, None, None, None)86	}8788	pub fn extend(89		self,90		new_bindings: FxHashMap<IStr, LazyVal>,91		new_dollar: Option<ObjValue>,92		new_this: Option<ObjValue>,93		new_super_obj: Option<ObjValue>,94	) -> Self {95		match Rc::try_unwrap(self.0) {96			Ok(mut ctx) => {97				// Extended context aren't used by anything else, we can freely mutate it without cloning98				if let Some(dollar) = new_dollar {99					ctx.dollar = Some(dollar);100				}101				if let Some(this) = new_this {102					ctx.this = Some(this);103				}104				if let Some(super_obj) = new_super_obj {105					ctx.super_obj = Some(super_obj);106				}107				if !new_bindings.is_empty() {108					ctx.bindings = ctx.bindings.extend(new_bindings);109				}110				Self(Rc::new(ctx))111			}112			Err(ctx) => {113				let dollar = new_dollar.or_else(|| ctx.dollar.clone());114				let this = new_this.or_else(|| ctx.this.clone());115				let super_obj = new_super_obj.or_else(|| ctx.super_obj.clone());116				let bindings = if new_bindings.is_empty() {117					ctx.bindings.clone()118				} else {119					ctx.bindings.clone().extend(new_bindings)120				};121				Self(Rc::new(ContextInternals {122					dollar,123					this,124					super_obj,125					bindings,126				}))127			}128		}129	}130	pub fn extend_bound(self, new_bindings: FxHashMap<IStr, LazyVal>) -> Self {131		let new_this = self.0.this.clone();132		let new_super_obj = self.0.super_obj.clone();133		self.extend(new_bindings, None, new_this, new_super_obj)134	}135	pub fn extend_unbound(136		self,137		new_bindings: FxHashMap<IStr, LazyBinding>,138		new_dollar: Option<ObjValue>,139		new_this: Option<ObjValue>,140		new_super_obj: Option<ObjValue>,141	) -> Result<Self> {142		let this = new_this.or_else(|| self.0.this.clone());143		let super_obj = new_super_obj.or_else(|| self.0.super_obj.clone());144		let mut new =145			FxHashMap::with_capacity_and_hasher(new_bindings.len(), BuildHasherDefault::default());146		for (k, v) in new_bindings.into_iter() {147			new.insert(k, v.evaluate(this.clone(), super_obj.clone())?);148		}149		Ok(self.extend(new, new_dollar, this, super_obj))150	}151	#[cfg(feature = "unstable")]152	pub fn into_weak(self) -> WeakContext {153		WeakContext(Rc::downgrade(&self.0))154	}155}156157impl Default for Context {158	fn default() -> Self {159		Self::new()160	}161}162163impl PartialEq for Context {164	fn eq(&self, other: &Self) -> bool {165		Rc::ptr_eq(&self.0, &other.0)166	}167}168169#[cfg(feature = "unstable")]170#[derive(Debug, Clone)]171pub struct WeakContext(std::rc::Weak<ContextInternals>);172#[cfg(feature = "unstable")]173impl WeakContext {174	pub fn upgrade(&self) -> Context {175		Context(self.0.upgrade().expect("context is removed"))176	}177}178#[cfg(feature = "unstable")]179impl PartialEq for WeakContext {180	fn eq(&self, other: &Self) -> bool {181		self.0.ptr_eq(&other.0)182	}183}