git.delta.rocks / jrsonnet / refs/commits / 3154bc9d5381

difftreelog

source

crates/jrsonnet-evaluator/src/ctx.rs4.2 KiBsourcehistory
1use crate::{2	error::Error::*, map::LayeredHashMap, rc_fn_helper, resolved_lazy_val, FutureWrapper,3	LazyBinding, LazyVal, ObjValue, Result, Val,4};5use jrsonnet_interner::IStr;6use rustc_hash::FxHashMap;7use std::hash::BuildHasherDefault;8use std::{collections::HashMap, fmt::Debug, rc::Rc};910rc_fn_helper!(11	ContextCreator,12	context_creator,13	dyn Fn(Option<ObjValue>, Option<ObjValue>) -> Result<Context>14);1516struct ContextInternals {17	dollar: Option<ObjValue>,18	this: Option<ObjValue>,19	super_obj: Option<ObjValue>,20	bindings: LayeredHashMap<LazyVal>,21}22impl Debug for ContextInternals {23	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {24		f.debug_struct("Context")25			.field("this", &self.this.as_ref().map(|e| Rc::as_ptr(&e.0)))26			.field("bindings", &self.bindings)27			.finish()28	}29}3031#[derive(Debug, Clone)]32pub struct Context(Rc<ContextInternals>);33impl Context {34	pub fn new_future() -> FutureWrapper<Context> {35		FutureWrapper::new()36	}3738	pub fn dollar(&self) -> &Option<ObjValue> {39		&self.0.dollar40	}4142	pub fn this(&self) -> &Option<ObjValue> {43		&self.0.this44	}4546	pub fn super_obj(&self) -> &Option<ObjValue> {47		&self.0.super_obj48	}4950	pub fn new() -> Self {51		Self(Rc::new(ContextInternals {52			dollar: None,53			this: None,54			super_obj: None,55			bindings: LayeredHashMap::default(),56		}))57	}5859	pub fn binding(&self, name: IStr) -> Result<LazyVal> {60		Ok(self61			.062			.bindings63			.get(&name)64			.cloned()65			.ok_or(VariableIsNotDefined(name))?)66	}67	pub fn into_future(self, ctx: FutureWrapper<Context>) -> Self {68		{69			ctx.0.borrow_mut().replace(self);70		}71		ctx.unwrap()72	}7374	pub fn with_var(self, name: IStr, value: Val) -> Self {75		let mut new_bindings =76			FxHashMap::with_capacity_and_hasher(1, BuildHasherDefault::default());77		new_bindings.insert(name, resolved_lazy_val!(value));78		self.extend(new_bindings, None, None, None)79	}8081	pub fn extend(82		self,83		new_bindings: FxHashMap<IStr, LazyVal>,84		new_dollar: Option<ObjValue>,85		new_this: Option<ObjValue>,86		new_super_obj: Option<ObjValue>,87	) -> Self {88		match Rc::try_unwrap(self.0) {89			Ok(mut ctx) => {90				// Extended context aren't used by anything else, we can freely mutate it without cloning91				if let Some(dollar) = new_dollar {92					ctx.dollar = Some(dollar);93				}94				if let Some(this) = new_this {95					ctx.this = Some(this);96				}97				if let Some(super_obj) = new_super_obj {98					ctx.super_obj = Some(super_obj);99				}100				if !new_bindings.is_empty() {101					ctx.bindings = ctx.bindings.extend(new_bindings);102				}103				Self(Rc::new(ctx))104			}105			Err(ctx) => {106				let dollar = new_dollar.or_else(|| ctx.dollar.clone());107				let this = new_this.or_else(|| ctx.this.clone());108				let super_obj = new_super_obj.or_else(|| ctx.super_obj.clone());109				let bindings = if new_bindings.is_empty() {110					ctx.bindings.clone()111				} else {112					ctx.bindings.clone().extend(new_bindings)113				};114				Self(Rc::new(ContextInternals {115					dollar,116					this,117					super_obj,118					bindings,119				}))120			}121		}122	}123	pub fn extend_unbound(124		self,125		new_bindings: HashMap<IStr, LazyBinding>,126		new_dollar: Option<ObjValue>,127		new_this: Option<ObjValue>,128		new_super_obj: Option<ObjValue>,129	) -> Result<Self> {130		let this = new_this.or_else(|| self.0.this.clone());131		let super_obj = new_super_obj.or_else(|| self.0.super_obj.clone());132		let mut new =133			FxHashMap::with_capacity_and_hasher(new_bindings.len(), BuildHasherDefault::default());134		for (k, v) in new_bindings.into_iter() {135			new.insert(k, v.evaluate(this.clone(), super_obj.clone())?);136		}137		Ok(self.extend(new, new_dollar, this, super_obj))138	}139	#[cfg(feature = "unstable")]140	pub fn into_weak(self) -> WeakContext {141		WeakContext(Rc::downgrade(&self.0))142	}143}144145impl Default for Context {146	fn default() -> Self {147		Self::new()148	}149}150151impl PartialEq for Context {152	fn eq(&self, other: &Self) -> bool {153		Rc::ptr_eq(&self.0, &other.0)154	}155}156157#[cfg(feature = "unstable")]158#[derive(Debug, Clone)]159pub struct WeakContext(std::rc::Weak<ContextInternals>);160#[cfg(feature = "unstable")]161impl WeakContext {162	pub fn upgrade(&self) -> Context {163		Context(self.0.upgrade().expect("context is removed"))164	}165}166#[cfg(feature = "unstable")]167impl PartialEq for WeakContext {168	fn eq(&self, other: &Self) -> bool {169		self.0.ptr_eq(&other.0)170	}171}