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

difftreelog

source

crates/jrsonnet-evaluator/src/ctx.rs4.8 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 with_this_super(self, new_this: ObjValue, new_super_obj: Option<ObjValue>) -> Self {89		self.extend(FxHashMap::default(), None, Some(new_this), new_super_obj)90	}9192	pub fn extend(93		self,94		new_bindings: FxHashMap<IStr, LazyVal>,95		new_dollar: Option<ObjValue>,96		new_this: Option<ObjValue>,97		new_super_obj: Option<ObjValue>,98	) -> Self {99		match Rc::try_unwrap(self.0) {100			Ok(mut ctx) => {101				// Extended context aren't used by anything else, we can freely mutate it without cloning102				if let Some(dollar) = new_dollar {103					ctx.dollar = Some(dollar);104				}105				if let Some(this) = new_this {106					ctx.this = Some(this);107				}108				if let Some(super_obj) = new_super_obj {109					ctx.super_obj = Some(super_obj);110				}111				if !new_bindings.is_empty() {112					ctx.bindings = ctx.bindings.extend(new_bindings);113				}114				Self(Rc::new(ctx))115			}116			Err(ctx) => {117				let dollar = new_dollar.or_else(|| ctx.dollar.clone());118				let this = new_this.or_else(|| ctx.this.clone());119				let super_obj = new_super_obj.or_else(|| ctx.super_obj.clone());120				let bindings = if new_bindings.is_empty() {121					ctx.bindings.clone()122				} else {123					ctx.bindings.clone().extend(new_bindings)124				};125				Self(Rc::new(ContextInternals {126					dollar,127					this,128					super_obj,129					bindings,130				}))131			}132		}133	}134	pub fn extend_bound(self, new_bindings: FxHashMap<IStr, LazyVal>) -> Self {135		let new_this = self.0.this.clone();136		let new_super_obj = self.0.super_obj.clone();137		self.extend(new_bindings, None, new_this, new_super_obj)138	}139	pub fn extend_unbound(140		self,141		new_bindings: FxHashMap<IStr, LazyBinding>,142		new_dollar: Option<ObjValue>,143		new_this: Option<ObjValue>,144		new_super_obj: Option<ObjValue>,145	) -> Result<Self> {146		let this = new_this.or_else(|| self.0.this.clone());147		let super_obj = new_super_obj.or_else(|| self.0.super_obj.clone());148		let mut new =149			FxHashMap::with_capacity_and_hasher(new_bindings.len(), BuildHasherDefault::default());150		for (k, v) in new_bindings.into_iter() {151			new.insert(k, v.evaluate(this.clone(), super_obj.clone())?);152		}153		Ok(self.extend(new, new_dollar, this, super_obj))154	}155	#[cfg(feature = "unstable")]156	pub fn into_weak(self) -> WeakContext {157		WeakContext(Rc::downgrade(&self.0))158	}159}160161impl Default for Context {162	fn default() -> Self {163		Self::new()164	}165}166167impl PartialEq for Context {168	fn eq(&self, other: &Self) -> bool {169		Rc::ptr_eq(&self.0, &other.0)170	}171}172173#[cfg(feature = "unstable")]174#[derive(Debug, Clone)]175pub struct WeakContext(std::rc::Weak<ContextInternals>);176#[cfg(feature = "unstable")]177impl WeakContext {178	pub fn upgrade(&self) -> Context {179		Context(self.0.upgrade().expect("context is removed"))180	}181}182#[cfg(feature = "unstable")]183impl PartialEq for WeakContext {184	fn eq(&self, other: &Self) -> bool {185		self.0.ptr_eq(&other.0)186	}187}