git.delta.rocks / jrsonnet / refs/commits / 94fa86f59bc6

difftreelog

source

crates/jrsonnet-evaluator/src/obj.rs15.3 KiBsourcehistory
1use std::{2	cell::RefCell,3	fmt::Debug,4	hash::{Hash, Hasher},5	ptr::addr_of,6};78use gcmodule::{Cc, Trace, Weak};9use jrsonnet_interner::IStr;10use jrsonnet_parser::{ExprLocation, Visibility};11use rustc_hash::FxHashMap;1213use crate::{14	cc_ptr_eq,15	error::{Error::*, LocError},16	function::CallLocation,17	gc::{GcHashMap, GcHashSet, TraceBox},18	operator::evaluate_add_op,19	throw, weak_ptr_eq, weak_raw, Bindable, LazyBinding, LazyVal, Result, State, Val,20};2122#[cfg(not(feature = "exp-preserve-order"))]23mod ordering {24	#![allow(25		// This module works as stub for preserve-order feature26		clippy::unused_self,27	)]2829	use gcmodule::Trace;3031	#[derive(Clone, Copy, Default, Debug, Trace)]32	pub struct FieldIndex;33	impl FieldIndex {34		pub const fn next(self) -> Self {35			Self36		}37	}3839	#[derive(Clone, Copy, Default, Debug, Trace)]40	pub struct SuperDepth;41	impl SuperDepth {42		pub const fn deeper(self) -> Self {43			Self44		}45	}4647	#[derive(Clone, Copy)]48	pub struct FieldSortKey;49	impl FieldSortKey {50		pub const fn new(_: SuperDepth, _: FieldIndex) -> Self {51			Self52		}53	}54}5556#[cfg(feature = "exp-preserve-order")]57mod ordering {58	use std::cmp::Reverse;5960	use gcmodule::Trace;6162	#[derive(Clone, Copy, Default, Debug, Trace, PartialEq, Eq, PartialOrd, Ord)]63	pub struct FieldIndex(u32);64	impl FieldIndex {65		pub fn next(self) -> Self {66			Self(self.0 + 1)67		}68	}6970	#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Debug)]71	pub struct SuperDepth(u32);72	impl SuperDepth {73		pub fn deeper(self) -> Self {74			Self(self.0 + 1)75		}76	}7778	#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]79	pub struct FieldSortKey(Reverse<SuperDepth>, FieldIndex);80	impl FieldSortKey {81		pub fn new(depth: SuperDepth, index: FieldIndex) -> Self {82			Self(Reverse(depth), index)83		}84		pub fn collide(self, other: Self) -> Self {85			if self.0 .0 > other.0 .0 {86				self87			} else if self.0 .0 < other.0 .0 {88				other89			} else {90				unreachable!("object can't have two fields with same name")91			}92		}93	}94}9596use ordering::*;9798#[allow(clippy::module_name_repetitions)]99#[derive(Debug, Trace)]100pub struct ObjMember {101	pub add: bool,102	pub visibility: Visibility,103	original_index: FieldIndex,104	pub invoke: LazyBinding,105	pub location: Option<ExprLocation>,106}107108pub trait ObjectAssertion: Trace {109	fn run(&self, s: State, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Result<()>;110}111112// Field => This113type CacheKey = (IStr, WeakObjValue);114115#[derive(Trace)]116enum CacheValue {117	Cached(Val),118	NotFound,119	Pending,120	Errored(LocError),121}122123#[allow(clippy::module_name_repetitions)]124#[derive(Trace)]125#[force_tracking]126pub struct ObjValueInternals {127	super_obj: Option<ObjValue>,128	assertions: Cc<Vec<TraceBox<dyn ObjectAssertion>>>,129	assertions_ran: RefCell<GcHashSet<ObjValue>>,130	this_obj: Option<ObjValue>,131	this_entries: Cc<GcHashMap<IStr, ObjMember>>,132	value_cache: RefCell<GcHashMap<CacheKey, CacheValue>>,133}134135#[derive(Clone, Trace)]136pub struct WeakObjValue(#[skip_trace] pub(crate) Weak<ObjValueInternals>);137138impl PartialEq for WeakObjValue {139	fn eq(&self, other: &Self) -> bool {140		weak_ptr_eq(self.0.clone(), other.0.clone())141	}142}143144impl Eq for WeakObjValue {}145impl Hash for WeakObjValue {146	fn hash<H: Hasher>(&self, hasher: &mut H) {147		hasher.write_usize(weak_raw(self.0.clone()) as usize);148	}149}150151#[allow(clippy::module_name_repetitions)]152#[derive(Clone, Trace)]153pub struct ObjValue(pub(crate) Cc<ObjValueInternals>);154impl Debug for ObjValue {155	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {156		if let Some(super_obj) = self.0.super_obj.as_ref() {157			if f.alternate() {158				write!(f, "{:#?}", super_obj)?;159			} else {160				write!(f, "{:?}", super_obj)?;161			}162			write!(f, " + ")?;163		}164		let mut debug = f.debug_struct("ObjValue");165		for (name, member) in self.0.this_entries.iter() {166			debug.field(name, member);167		}168		debug.finish_non_exhaustive()169	}170}171172impl ObjValue {173	pub fn new(174		super_obj: Option<Self>,175		this_entries: Cc<GcHashMap<IStr, ObjMember>>,176		assertions: Cc<Vec<TraceBox<dyn ObjectAssertion>>>,177	) -> Self {178		Self(Cc::new(ObjValueInternals {179			super_obj,180			assertions,181			assertions_ran: RefCell::new(GcHashSet::new()),182			this_obj: None,183			this_entries,184			value_cache: RefCell::new(GcHashMap::new()),185		}))186	}187	pub fn new_empty() -> Self {188		Self::new(None, Cc::new(GcHashMap::new()), Cc::new(Vec::new()))189	}190	#[must_use]191	pub fn extend_from(&self, super_obj: Self) -> Self {192		match &self.0.super_obj {193			None => Self::new(194				Some(super_obj),195				self.0.this_entries.clone(),196				self.0.assertions.clone(),197			),198			Some(v) => Self::new(199				Some(v.extend_from(super_obj)),200				self.0.this_entries.clone(),201				self.0.assertions.clone(),202			),203		}204	}205	pub(crate) fn extend_with_raw_member(self, key: IStr, value: ObjMember) -> Self {206		let mut new = GcHashMap::with_capacity(1);207		new.insert(key, value);208		Self::new(Some(self), Cc::new(new), Cc::new(Vec::new()))209	}210	pub fn extend_field(&mut self, name: IStr) -> ObjMemberBuilder<ExtendBuilder> {211		ObjMemberBuilder::new(ExtendBuilder(self), name, FieldIndex::default())212	}213214	#[must_use]215	pub fn with_this(&self, this_obj: Self) -> Self {216		Self(Cc::new(ObjValueInternals {217			super_obj: self.0.super_obj.clone(),218			assertions: self.0.assertions.clone(),219			assertions_ran: RefCell::new(GcHashSet::new()),220			this_obj: Some(this_obj),221			this_entries: self.0.this_entries.clone(),222			value_cache: RefCell::new(GcHashMap::new()),223		}))224	}225226	pub fn len(&self) -> usize {227		self.fields_visibility()228			.into_iter()229			.filter(|(_, (visible, _))| *visible)230			.count()231	}232233	pub fn is_empty(&self) -> bool {234		if !self.0.this_entries.is_empty() {235			return false;236		}237		self.0.super_obj.as_ref().map_or(true, Self::is_empty)238	}239240	/// Run callback for every field found in object241	pub(crate) fn enum_fields(242		&self,243		depth: SuperDepth,244		handler: &mut impl FnMut(SuperDepth, &IStr, &ObjMember) -> bool,245	) -> bool {246		if let Some(s) = &self.0.super_obj {247			if s.enum_fields(depth.deeper(), handler) {248				return true;249			}250		}251		for (name, member) in self.0.this_entries.iter() {252			if handler(depth, name, member) {253				return true;254			}255		}256		false257	}258259	pub fn fields_visibility(&self) -> FxHashMap<IStr, (bool, FieldSortKey)> {260		let mut out = FxHashMap::default();261		self.enum_fields(SuperDepth::default(), &mut |depth, name, member| {262			let new_sort_key = FieldSortKey::new(depth, member.original_index);263			match member.visibility {264				Visibility::Normal => {265					let entry = out.entry(name.clone());266					let v = entry.or_insert((true, new_sort_key));267					v.1 = new_sort_key;268				}269				Visibility::Hidden => {270					out.insert(name.clone(), (false, new_sort_key));271				}272				Visibility::Unhide => {273					out.insert(name.clone(), (true, new_sort_key));274				}275			};276			false277		});278		out279	}280	pub fn fields_ex(281		&self,282		include_hidden: bool,283		#[cfg(feature = "exp-preserve-order")] preserve_order: bool,284	) -> Vec<IStr> {285		#[cfg(feature = "exp-preserve-order")]286		if preserve_order {287			let (mut fields, mut keys): (Vec<_>, Vec<_>) = self288				.fields_visibility()289				.into_iter()290				.filter(|(_, (visible, _))| include_hidden || *visible)291				.enumerate()292				.map(|(idx, (k, (_, sk)))| (k, (sk, idx)))293				.unzip();294			keys.sort_unstable_by_key(|v| v.0);295			// Reorder in-place by resulting indexes296			for i in 0..fields.len() {297				let x = fields[i].clone();298				let mut j = i;299				loop {300					let k = keys[j].1;301					keys[j].1 = j;302					if k == i {303						break;304					}305					fields[j] = fields[k].clone();306					j = k307				}308				fields[j] = x;309			}310			return fields;311		}312313		let mut fields: Vec<_> = self314			.fields_visibility()315			.into_iter()316			.filter(|(_, (visible, _))| include_hidden || *visible)317			.map(|(k, _)| k)318			.collect();319		fields.sort_unstable();320		fields321	}322	pub fn fields(&self, #[cfg(feature = "exp-preserve-order")] preserve_order: bool) -> Vec<IStr> {323		self.fields_ex(324			false,325			#[cfg(feature = "exp-preserve-order")]326			preserve_order,327		)328	}329330	pub fn field_visibility(&self, name: IStr) -> Option<Visibility> {331		if let Some(m) = self.0.this_entries.get(&name) {332			Some(match &m.visibility {333				Visibility::Normal => self334					.0335					.super_obj336					.as_ref()337					.and_then(|super_obj| super_obj.field_visibility(name))338					.unwrap_or(Visibility::Normal),339				v => *v,340			})341		} else if let Some(super_obj) = &self.0.super_obj {342			super_obj.field_visibility(name)343		} else {344			None345		}346	}347348	fn has_field_include_hidden(&self, name: IStr) -> bool {349		if self.0.this_entries.contains_key(&name) {350			true351		} else if let Some(super_obj) = &self.0.super_obj {352			super_obj.has_field_include_hidden(name)353		} else {354			false355		}356	}357358	pub fn has_field_ex(&self, name: IStr, include_hidden: bool) -> bool {359		if include_hidden {360			self.has_field_include_hidden(name)361		} else {362			self.has_field(name)363		}364	}365	pub fn has_field(&self, name: IStr) -> bool {366		self.field_visibility(name)367			.map_or(false, |v| v.is_visible())368	}369370	pub fn get(&self, s: State, key: IStr) -> Result<Option<Val>> {371		self.run_assertions(s.clone())?;372		self.get_raw(s, key, self.0.this_obj.as_ref())373	}374375	// pub fn extend_with(self, key: )376377	fn get_raw(&self, s: State, key: IStr, real_this: Option<&Self>) -> Result<Option<Val>> {378		let real_this = real_this.unwrap_or(self);379		let cache_key = (key.clone(), WeakObjValue(real_this.0.downgrade()));380381		if let Some(v) = self.0.value_cache.borrow().get(&cache_key) {382			return Ok(match v {383				CacheValue::Cached(v) => Some(v.clone()),384				CacheValue::NotFound => None,385				CacheValue::Pending => throw!(InfiniteRecursionDetected),386				CacheValue::Errored(e) => return Err(e.clone()),387			});388		}389		self.0390			.value_cache391			.borrow_mut()392			.insert(cache_key.clone(), CacheValue::Pending);393		let value = match (self.0.this_entries.get(&key), &self.0.super_obj) {394			(Some(k), None) => Ok(Some(self.evaluate_this(s, k, real_this)?)),395			(Some(k), Some(super_obj)) => {396				let our = self.evaluate_this(s.clone(), k, real_this)?;397				if k.add {398					super_obj399						.get_raw(s.clone(), key, Some(real_this))?400						.map_or(Ok(Some(our.clone())), |v| {401							Ok(Some(evaluate_add_op(s.clone(), &v, &our)?))402						})403				} else {404					Ok(Some(our))405				}406			}407			(None, Some(super_obj)) => super_obj.get_raw(s, key, Some(real_this)),408			(None, None) => Ok(None),409		};410		let value = match value {411			Ok(v) => v,412			Err(e) => {413				self.0414					.value_cache415					.borrow_mut()416					.insert(cache_key, CacheValue::Errored(e.clone()));417				return Err(e);418			}419		};420		self.0.value_cache.borrow_mut().insert(421			cache_key,422			match &value {423				Some(v) => CacheValue::Cached(v.clone()),424				None => CacheValue::NotFound,425			},426		);427		Ok(value)428	}429	fn evaluate_this(&self, s: State, v: &ObjMember, real_this: &Self) -> Result<Val> {430		v.invoke431			.evaluate(s.clone(), Some(real_this.clone()), self.0.super_obj.clone())?432			.evaluate(s)433	}434435	fn run_assertions_raw(&self, s: State, real_this: &Self) -> Result<()> {436		if self.0.assertions_ran.borrow_mut().insert(real_this.clone()) {437			for assertion in self.0.assertions.iter() {438				if let Err(e) =439					assertion.run(s.clone(), Some(real_this.clone()), self.0.super_obj.clone())440				{441					self.0.assertions_ran.borrow_mut().remove(real_this);442					return Err(e);443				}444			}445			if let Some(super_obj) = &self.0.super_obj {446				super_obj.run_assertions_raw(s, real_this)?;447			}448		}449		Ok(())450	}451	pub fn run_assertions(&self, s: State) -> Result<()> {452		self.run_assertions_raw(s, self)453	}454455	pub fn ptr_eq(a: &Self, b: &Self) -> bool {456		cc_ptr_eq(&a.0, &b.0)457	}458}459460impl PartialEq for ObjValue {461	fn eq(&self, other: &Self) -> bool {462		cc_ptr_eq(&self.0, &other.0)463	}464}465466impl Eq for ObjValue {}467impl Hash for ObjValue {468	fn hash<H: Hasher>(&self, hasher: &mut H) {469		hasher.write_usize(addr_of!(*self.0) as usize);470	}471}472473#[allow(clippy::module_name_repetitions)]474pub struct ObjValueBuilder {475	super_obj: Option<ObjValue>,476	map: GcHashMap<IStr, ObjMember>,477	assertions: Vec<TraceBox<dyn ObjectAssertion>>,478	next_field_index: FieldIndex,479}480impl ObjValueBuilder {481	pub fn new() -> Self {482		Self::with_capacity(0)483	}484	pub fn with_capacity(capacity: usize) -> Self {485		Self {486			super_obj: None,487			map: GcHashMap::with_capacity(capacity),488			assertions: Vec::new(),489			next_field_index: FieldIndex::default(),490		}491	}492	pub fn reserve_asserts(&mut self, capacity: usize) -> &mut Self {493		self.assertions.reserve_exact(capacity);494		self495	}496	pub fn with_super(&mut self, super_obj: ObjValue) -> &mut Self {497		self.super_obj = Some(super_obj);498		self499	}500501	pub fn assert(&mut self, assertion: TraceBox<dyn ObjectAssertion>) -> &mut Self {502		self.assertions.push(assertion);503		self504	}505	pub fn member(&mut self, name: IStr) -> ObjMemberBuilder<ValueBuilder> {506		let field_index = self.next_field_index;507		self.next_field_index = self.next_field_index.next();508		ObjMemberBuilder::new(ValueBuilder(self), name, field_index)509	}510511	pub fn build(self) -> ObjValue {512		ObjValue::new(self.super_obj, Cc::new(self.map), Cc::new(self.assertions))513	}514}515impl Default for ObjValueBuilder {516	fn default() -> Self {517		Self::with_capacity(0)518	}519}520521#[allow(clippy::module_name_repetitions)]522#[must_use = "value not added unless binding() was called"]523pub struct ObjMemberBuilder<Kind> {524	kind: Kind,525	name: IStr,526	add: bool,527	visibility: Visibility,528	original_index: FieldIndex,529	location: Option<ExprLocation>,530}531532#[allow(clippy::missing_const_for_fn)]533impl<Kind> ObjMemberBuilder<Kind> {534	pub(crate) fn new(kind: Kind, name: IStr, original_index: FieldIndex) -> Self {535		Self {536			kind,537			name,538			original_index,539			add: false,540			visibility: Visibility::Normal,541			location: None,542		}543	}544545	pub const fn with_add(mut self, add: bool) -> Self {546		self.add = add;547		self548	}549	pub fn add(self) -> Self {550		self.with_add(true)551	}552	pub fn with_visibility(mut self, visibility: Visibility) -> Self {553		self.visibility = visibility;554		self555	}556	pub fn hide(self) -> Self {557		self.with_visibility(Visibility::Hidden)558	}559	pub fn with_location(mut self, location: ExprLocation) -> Self {560		self.location = Some(location);561		self562	}563	fn build_member(self, binding: LazyBinding) -> (Kind, IStr, ObjMember) {564		(565			self.kind,566			self.name,567			ObjMember {568				add: self.add,569				visibility: self.visibility,570				original_index: self.original_index,571				invoke: binding,572				location: self.location,573			},574		)575	}576}577578pub struct ValueBuilder<'v>(&'v mut ObjValueBuilder);579impl<'v> ObjMemberBuilder<ValueBuilder<'v>> {580	pub fn value(self, s: State, value: Val) -> Result<()> {581		self.binding(s, LazyBinding::Bound(LazyVal::new_resolved(value)))582	}583	pub fn bindable(self, s: State, bindable: TraceBox<dyn Bindable>) -> Result<()> {584		self.binding(s, LazyBinding::Bindable(Cc::new(bindable)))585	}586	pub fn binding(self, s: State, binding: LazyBinding) -> Result<()> {587		let (receiver, name, member) = self.build_member(binding);588		let location = member.location.clone();589		let old = receiver.0.map.insert(name.clone(), member);590		if old.is_some() {591			s.push(592				CallLocation(location.as_ref()),593				|| format!("field <{}> initializtion", name.clone()),594				|| throw!(DuplicateFieldName(name.clone())),595			)?;596		}597		Ok(())598	}599}600601pub struct ExtendBuilder<'v>(&'v mut ObjValue);602impl<'v> ObjMemberBuilder<ExtendBuilder<'v>> {603	pub fn value(self, value: Val) {604		self.binding(LazyBinding::Bound(LazyVal::new_resolved(value)));605	}606	pub fn bindable(self, bindable: TraceBox<dyn Bindable>) {607		self.binding(LazyBinding::Bindable(Cc::new(bindable)));608	}609	pub fn binding(self, binding: LazyBinding) {610		let (receiver, name, member) = self.build_member(binding);611		let new = receiver.0.clone();612		*receiver.0 = new.extend_with_raw_member(name, member);613	}614}