difftreelog
refactor dyn ObjValue
in: master
5 files changed
Cargo.lockdiffbeforeafterboth--- a/Cargo.lock
+++ b/Cargo.lock
@@ -219,6 +219,17 @@
]
[[package]]
+name = "derivative"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -346,6 +357,7 @@
"anyhow",
"async-trait",
"bincode",
+ "derivative",
"hashbrown 0.13.2",
"jrsonnet-gcmodule",
"jrsonnet-interner",
crates/jrsonnet-evaluator/Cargo.tomldiffbeforeafterboth--- a/crates/jrsonnet-evaluator/Cargo.toml
+++ b/crates/jrsonnet-evaluator/Cargo.toml
@@ -58,3 +58,4 @@
async-trait = { version = "0.1.60", optional = true }
# Bigint
num-bigint = { version = "0.4.3", features = ["serde"], optional = true }
+derivative = "2.2.0"
crates/jrsonnet-evaluator/src/gc.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/gc.rs
+++ b/crates/jrsonnet-evaluator/src/gc.rs
@@ -116,7 +116,10 @@
}
}
-pub struct GcHashMap<K, V>(pub HashMap<K, V, BuildHasherDefault<FxHasher>>);
+#[derive(Debug)]
+pub struct GcHashMap<K, V>(
+ pub HashMap<K, V, BuildHasherDefault<FxHasher>>
+);
impl<K, V> GcHashMap<K, V> {
pub fn new() -> Self {
Self(HashMap::default())
crates/jrsonnet-evaluator/src/obj.rsdiffbeforeafterboth1use std::{1use std::{2 any::Any,2 cell::RefCell,3 cell::RefCell,3 fmt::Debug,4 fmt::Debug,4 hash::{Hash, Hasher},5 hash::{Hash, Hasher},949595use ordering::*;96use ordering::*;969798// 0 - add99// 12 - visibility100#[derive(Clone, Copy)]101pub struct ObjFieldFlags(u8);102impl ObjFieldFlags {103 fn new(add: bool, visibility: Visibility) -> Self {104 let mut v = 0;105 if add {106 v |= 1;107 }108 v |= match visibility {109 Visibility::Normal => 0b000,110 Visibility::Hidden => 0b010,111 Visibility::Unhide => 0b100,112 };113 Self(v)114 }115 pub fn add(&self) -> bool {116 self.0 & 1 != 0117 }118 pub fn visibility(&self) -> Visibility {119 match (self.0 & 0b110) >> 1 {120 0b00 => Visibility::Normal,121 0b01 => Visibility::Hidden,122 0b10 => Visibility::Unhide,123 _ => unreachable!(),124 }125 }126}127impl Debug for ObjFieldFlags {128 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {129 f.debug_struct("ObjFieldFlags")130 .field("add", &self.add())131 .field("visibility", &self.visibility())132 .finish()133 }134}13597#[allow(clippy::module_name_repetitions)]136#[allow(clippy::module_name_repetitions)]98#[derive(Debug, Trace)]137#[derive(Debug, Trace)]99pub struct ObjMember {138pub struct ObjMember {100 pub add: bool,139 #[trace(skip)]101 pub visibility: Visibility,140 flags: ObjFieldFlags,102 original_index: FieldIndex,141 original_index: FieldIndex,103 pub invoke: MaybeUnbound,142 pub invoke: MaybeUnbound,104 pub location: Option<ExprLocation>,143 pub location: Option<ExprLocation>,121#[allow(clippy::module_name_repetitions)]160#[allow(clippy::module_name_repetitions)]122#[derive(Trace)]161#[derive(Trace)]123#[trace(tracking(force))]162#[trace(tracking(force))]124pub struct ObjValueInternals {163pub struct OopObject {125 sup: Option<ObjValue>,164 sup: Option<ObjValue>,126 this: Option<ObjValue>,165 // this: Option<ObjValue>,127128 assertions: Cc<Vec<TraceBox<dyn ObjectAssertion>>>,166 assertions: Cc<Vec<TraceBox<dyn ObjectAssertion>>>,129 assertions_ran: RefCell<GcHashSet<ObjValue>>,167 assertions_ran: RefCell<GcHashSet<ObjValue>>,130 this_entries: Cc<GcHashMap<IStr, ObjMember>>,168 this_entries: Cc<GcHashMap<IStr, ObjMember>>,131 value_cache: RefCell<GcHashMap<(IStr, Option<WeakObjValue>), CacheValue>>,169 value_cache: RefCell<GcHashMap<(IStr, Option<WeakObjValue>), CacheValue>>,132}170}171impl Debug for OopObject {172 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {173 f.debug_struct("OopObject")174 .field("sup", &self.sup)175 // .field("assertions", &self.assertions)176 // .field("assertions_ran", &self.assertions_ran)177 .field("this_entries", &self.this_entries)178 // .field("value_cache", &self.value_cache)179 .finish()180 }181}133182183type EnumFieldsHandler<'a> = dyn FnMut(SuperDepth, FieldIndex, IStr, Visibility) -> bool + 'a;184185pub trait ObjectLike: Trace + Any + Debug {186 fn extend_from(&self, sup: ObjValue) -> ObjValue;187 /// When using standalone super in object, `this.super_obj.with_this(this)` is executed188 fn with_this(&self, me: ObjValue, this: ObjValue) -> ObjValue {189 ObjValue::new(ThisOverride { inner: me, this })190 }191 fn this(&self) -> Option<ObjValue> {192 None193 }194 fn len(&self) -> usize;195 fn is_empty(&self) -> bool;196 // If callback returns false, iteration stops197 fn enum_fields(&self, depth: SuperDepth, handler: &mut EnumFieldsHandler<'_>) -> bool;198199 fn has_field_include_hidden(&self, name: IStr) -> bool;200 fn has_field(&self, name: IStr) -> bool;201202 fn get_for(&self, key: IStr, this: ObjValue) -> Result<Option<Val>>;203 fn get_for_uncached(&self, key: IStr, this: ObjValue) -> Result<Option<Val>>;204 fn field_visibility(&self, field: IStr) -> Option<Visibility>;205206 fn run_assertions_raw(&self, this: ObjValue) -> Result<()>;207}208134#[derive(Clone, Trace)]209#[derive(Clone, Trace)]135pub struct WeakObjValue(#[trace(skip)] pub(crate) Weak<ObjValueInternals>);210pub struct WeakObjValue(#[trace(skip)] pub(crate) Weak<TraceBox<dyn ObjectLike>>);136211137impl PartialEq for WeakObjValue {212impl PartialEq for WeakObjValue {138 fn eq(&self, other: &Self) -> bool {213 fn eq(&self, other: &Self) -> bool {150}225}151226152#[allow(clippy::module_name_repetitions)]227#[allow(clippy::module_name_repetitions)]153#[derive(Clone, Trace)]228#[derive(Clone, Trace, Debug)]154pub struct ObjValue(pub(crate) Cc<ObjValueInternals>);229pub struct ObjValue(pub(crate) Cc<TraceBox<dyn ObjectLike>>);230231#[derive(Debug, Trace)]232struct EmptyObject;155impl Debug for ObjValue {233impl ObjectLike for EmptyObject {156 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {234 fn extend_from(&self, sup: ObjValue) -> ObjValue {157 if let Some(super_obj) = self.0.sup.as_ref() {235 // obj + {} == obj158 if f.alternate() {159 write!(f, "{super_obj:#?}")?;160 } else {161 write!(f, "{super_obj:?}")?;162 }163 write!(f, " + ")?;164 }165 let mut debug = f.debug_struct("ObjValue");166 for (name, member) in self.0.this_entries.iter() {236 sup167 debug.field(name, member);168 }169 debug.finish_non_exhaustive()170 }237 }238239 fn this(&self) -> Option<ObjValue> {240 None241 }242243 fn len(&self) -> usize {244 0245 }246247 fn is_empty(&self) -> bool {248 true249 }250251 fn enum_fields(&self, _depth: SuperDepth, _handler: &mut EnumFieldsHandler<'_>) -> bool {252 false253 }254255 fn has_field_include_hidden(&self, _name: IStr) -> bool {256 false257 }258259 fn has_field(&self, _name: IStr) -> bool {260 false261 }262263 fn get_for(&self, _key: IStr, _this: ObjValue) -> Result<Option<Val>> {264 Ok(None)265 }266 fn get_for_uncached(&self, _key: IStr, _this: ObjValue) -> Result<Option<Val>> {267 Ok(None)268 }269270 fn run_assertions_raw(&self, _this: ObjValue) -> Result<()> {271 Ok(())272 }273274 fn field_visibility(&self, _field: IStr) -> Option<Visibility> {275 None276 }171}277}172278279#[derive(Trace, Debug)]280struct ThisOverride {281 inner: ObjValue,282 this: ObjValue,283}284impl ObjectLike for ThisOverride {285 fn with_this(&self, _me: ObjValue, this: ObjValue) -> ObjValue {286 ObjValue::new(ThisOverride {287 inner: self.inner.clone(),288 this,289 })290 }291292 fn extend_from(&self, sup: ObjValue) -> ObjValue {293 self.inner.extend_from(sup).with_this(self.this.clone())294 }295296 fn this(&self) -> Option<ObjValue> {297 Some(self.this.clone())298 }299300 fn len(&self) -> usize {301 self.inner.len()302 }303304 fn is_empty(&self) -> bool {305 self.inner.is_empty()306 }307308 fn enum_fields(&self, depth: SuperDepth, handler: &mut EnumFieldsHandler<'_>) -> bool {309 self.inner.enum_fields(depth, handler)310 }311312 fn has_field_include_hidden(&self, name: IStr) -> bool {313 self.inner.has_field_include_hidden(name)314 }315316 fn has_field(&self, name: IStr) -> bool {317 self.inner.has_field(name)318 }319320 fn get_for(&self, key: IStr, this: ObjValue) -> Result<Option<Val>> {321 self.inner.get_for(key, this)322 }323324 fn get_for_uncached(&self, key: IStr, this: ObjValue) -> Result<Option<Val>> {325 self.inner.get_raw(key, this)326 }327328 fn field_visibility(&self, field: IStr) -> Option<Visibility> {329 self.inner.field_visibility(field)330 }331332 fn run_assertions_raw(&self, this: ObjValue) -> Result<()> {333 self.inner.run_assertions_raw(this)334 }335}336173impl ObjValue {337impl ObjValue {174 pub fn new(338 pub fn new(v: impl ObjectLike) -> Self {175 sup: Option<Self>,176 this_entries: Cc<GcHashMap<IStr, ObjMember>>,177 assertions: Cc<Vec<TraceBox<dyn ObjectAssertion>>>,178 ) -> Self {179 Self(Cc::new(ObjValueInternals {339 Self(Cc::new(tb!(v)))180 sup,181 this: None,182 assertions,183 assertions_ran: RefCell::new(GcHashSet::new()),184 this_entries,185 value_cache: RefCell::new(GcHashMap::new()),186 }))187 }340 }188 pub fn new_empty() -> Self {341 pub fn new_empty() -> Self {189 Self::new(None, Cc::new(GcHashMap::new()), Cc::new(Vec::new()))342 Self::new(EmptyObject)190 }343 }191 pub fn builder() -> ObjValueBuilder {344 pub fn builder() -> ObjValueBuilder {192 ObjValueBuilder::new()345 ObjValueBuilder::new()193 }346 }194 pub fn builder_with_capacity(capacity: usize) -> ObjValueBuilder {347 pub fn builder_with_capacity(capacity: usize) -> ObjValueBuilder {195 ObjValueBuilder::with_capacity(capacity)348 ObjValueBuilder::with_capacity(capacity)196 }349 }197 #[must_use]198 pub fn extend_from(&self, sup: Self) -> Self {199 match &self.0.sup {200 None => Self::new(201 Some(sup),202 self.0.this_entries.clone(),203 self.0.assertions.clone(),204 ),205 Some(v) => Self::new(206 Some(v.extend_from(sup)),207 self.0.this_entries.clone(),208 self.0.assertions.clone(),209 ),210 }211 }212 pub(crate) fn extend_with_raw_member(self, key: IStr, value: ObjMember) -> Self {350 pub(crate) fn extend_with_raw_member(self, key: IStr, value: ObjMember) -> Self {213 let mut new = GcHashMap::with_capacity(1);351 // let mut new = GcHashMap::with_capacity(1);214 new.insert(key, value);352 // new.insert(key, value);215 Self::new(Some(self), Cc::new(new), Cc::new(Vec::new()))353 // Self::new(Some(self), Cc::new(new), Cc::new(Vec::new()))354 todo!()216 }355 }217 pub fn extend_field(&mut self, name: IStr) -> ObjMemberBuilder<ExtendBuilder<'_>> {356 pub fn extend_field(&mut self, name: IStr) -> ObjMemberBuilder<ExtendBuilder<'_>> {218 ObjMemberBuilder::new(ExtendBuilder(self), name, FieldIndex::default())357 ObjMemberBuilder::new(ExtendBuilder(self), name, FieldIndex::default())219 }358 }220359221 #[must_use]360 #[must_use]361 pub fn extend_from(&self, sup: Self) -> Self {362 self.0.extend_from(sup)363 }364 #[must_use]222 pub fn with_this(&self, this: Self) -> Self {365 pub fn with_this(&self, this: Self) -> Self {223 Self(Cc::new(ObjValueInternals {366 self.0.with_this(self.clone(), this)224 sup: self.0.sup.clone(),225 assertions: self.0.assertions.clone(),226 assertions_ran: RefCell::new(GcHashSet::new()),227 this: Some(this),228 this_entries: self.0.this_entries.clone(),229 value_cache: RefCell::new(GcHashMap::new()),230 }))231 }367 }232233 pub fn len(&self) -> usize {368 pub fn len(&self) -> usize {234 self.fields_visibility()369 self.0.len()235 .into_iter()236 .filter(|(_, (visible, _))| *visible)237 .count()238 }370 }371 pub fn is_empty(&self) -> bool {372 self.0.is_empty()373 }374 pub fn enum_fields(&self, depth: SuperDepth, handler: &mut EnumFieldsHandler<'_>) -> bool {375 self.0.enum_fields(depth, handler)376 }239377240 pub fn is_empty(&self) -> bool {378 pub fn has_field_include_hidden(&self, name: IStr) -> bool {241 if !self.0.this_entries.is_empty() {379 self.0.has_field_include_hidden(name)380 }381 pub fn has_field(&self, name: IStr) -> bool {382 self.0.has_field(name)383 }384 pub fn has_field_ex(&self, name: IStr, include_hidden: bool) -> bool {385 if include_hidden {386 self.has_field_include_hidden(name)387 } else {242 return false;388 self.has_field(name)243 }389 }244 self.0.sup.as_ref().map_or(true, Self::is_empty)245 }390 }246391247 /// Run callback for every field found in object392 pub fn get(&self, key: IStr) -> Result<Option<Val>> {393 self.run_assertions()?;394 self.get_for(key, self.0.this().unwrap_or(self.clone()))395 }396397 pub fn get_for(&self, key: IStr, this: ObjValue) -> Result<Option<Val>> {398 self.0.get_for(key, this)399 }400401 fn get_raw(&self, key: IStr, this: ObjValue) -> Result<Option<Val>> {402 self.0.get_for_uncached(key, this)403 }404405 fn field_visibility(&self, field: IStr) -> Option<Visibility> {248 ///406 self.0.field_visibility(field)249 /// Returns true if ended prematurely407 }408409 pub fn run_assertions(&self) -> Result<()> {410 // FIXME: Should it use `self.0.this()` in case of standalone super?250 pub(crate) fn enum_fields(411 self.run_assertions_raw(self.clone())412 }413 fn run_assertions_raw(&self, this: ObjValue) -> Result<()> {414 self.0.run_assertions_raw(this)415 }416417 pub fn iter(251 &self,418 &self,252 depth: SuperDepth,419 #[cfg(feature = "exp-preserve-order")] preserve_order: bool,253 handler: &mut impl FnMut(SuperDepth, &IStr, &ObjMember) -> bool,420 ) -> impl Iterator<Item = (IStr, Result<Val>)> + '_ {254 ) -> bool {255 if let Some(s) = &self.0.sup {421 let fields = self.fields(422 #[cfg(feature = "exp-preserve-order")]423 preserve_order,424 );425 fields.into_iter().map(|field| {256 if s.enum_fields(depth.deeper(), handler) {426 (427 field.clone(),428 self.get(field)429 .map(|opt| opt.expect("iterating over keys, field exists")),430 )431 })432 }433 pub fn get_lazy(&self, key: IStr) -> Option<Thunk<Val>> {257 return true;434 #[derive(Trace)]435 struct ThunkGet {258 }436 obj: ObjValue,437 key: IStr,259 }438 }260 for (name, member) in self.0.this_entries.iter() {439 impl ThunkValue for ThunkGet {440 type Output = Val;441261 if handler(depth, name, member) {442 fn get(self: Box<Self>) -> Result<Self::Output> {262 return true;443 Ok(self.obj.get(self.key)?.expect("field exists"))263 }444 }264 }445 }446447 if !self.has_field_ex(key.clone(), true) {448 return None;449 }450 Some(Thunk::new(ThunkGet {451 obj: self.clone(),452 key,265 false453 }))266 }454 }267455 pub fn ptr_eq(a: &Self, b: &Self) -> bool {268 pub fn fields_visibility(&self) -> FxHashMap<IStr, (bool, FieldSortKey)> {456 Cc::ptr_eq(&a.0, &b.0)457 }458 pub fn downgrade(self) -> WeakObjValue {459 WeakObjValue(self.0.downgrade())460 }461 fn fields_visibility(&self) -> FxHashMap<IStr, (bool, FieldSortKey)> {269 let mut out = FxHashMap::default();462 let mut out = FxHashMap::default();270 self.enum_fields(SuperDepth::default(), &mut |depth, name, member| {463 self.enum_fields(464 SuperDepth::default(),465 &mut |depth, index, name, visibility| {271 let new_sort_key = FieldSortKey::new(depth, member.original_index);466 let new_sort_key = FieldSortKey::new(depth, index);272 let entry = out.entry(name.clone());467 let entry = out.entry(name.clone());273 let (visible, _) = entry.or_insert((true, new_sort_key));468 let (visible, _) = entry.or_insert((true, new_sort_key));274 match member.visibility {469 match visibility {275 Visibility::Normal => {}470 Visibility::Normal => {}276 Visibility::Hidden => {471 Visibility::Hidden => {277 *visible = false;472 *visible = false;278 }473 }279 Visibility::Unhide => {474 Visibility::Unhide => {280 *visible = true;475 *visible = true;281 }476 }282 };477 };283 false478 false284 });479 },480 );285 out481 out286 }482 }287 pub fn fields_ex(483 pub fn fields_ex(333 preserve_order,529 preserve_order,334 )530 )335 }531 }532}336533534impl OopObject {337 pub fn field_visibility(&self, name: IStr) -> Option<Visibility> {535 pub fn new(536 sup: Option<ObjValue>,338 if let Some(m) = self.0.this_entries.get(&name) {537 this_entries: Cc<GcHashMap<IStr, ObjMember>>,339 Some(match &m.visibility {538 assertions: Cc<Vec<TraceBox<dyn ObjectAssertion>>>,340 Visibility::Normal => self539 ) -> Self {341 .0540 Self {342 .sup541 sup,343 .as_ref()542 // this: None,344 .and_then(|super_obj| super_obj.field_visibility(name))543 assertions,345 .unwrap_or(Visibility::Normal),544 assertions_ran: RefCell::new(GcHashSet::new()),346 v => *v,545 this_entries,347 })546 value_cache: RefCell::new(GcHashMap::new()),348 } else if let Some(super_obj) = &self.0.sup {349 super_obj.field_visibility(name)350 } else {351 None352 }547 }353 }548 }354549355 fn has_field_include_hidden(&self, name: IStr) -> bool {550 fn evaluate_this(&self, v: &ObjMember, real_this: ObjValue) -> Result<Val> {356 if self.0.this_entries.contains_key(&name) {551 v.invoke.evaluate(self.sup.clone(), Some(real_this))357 true358 } else if let Some(super_obj) = &self.0.sup {359 super_obj.has_field_include_hidden(name)360 } else {361 false362 }363 }552 }364553365 pub fn has_field_ex(&self, name: IStr, include_hidden: bool) -> bool {554 // FIXME: Duplication between ObjValue and OopObject555 fn fields_visibility(&self) -> FxHashMap<IStr, (bool, FieldSortKey)> {366 if include_hidden {556 let mut out = FxHashMap::default();367 self.has_field_include_hidden(name)557 self.enum_fields(558 SuperDepth::default(),368 } else {559 &mut |depth, index, name, visibility| {369 self.has_field(name)560 let new_sort_key = FieldSortKey::new(depth, index);561 let entry = out.entry(name.clone());370 }562 let (visible, _) = entry.or_insert((true, new_sort_key));563 match visibility {564 Visibility::Normal => {}565 Visibility::Hidden => {566 *visible = false;567 }568 Visibility::Unhide => {569 *visible = true;570 }571 };572 false573 },574 );575 out371 }576 }372 pub fn has_field(&self, name: IStr) -> bool {373 self.field_visibility(name)374 .map_or(false, |v| v.is_visible())375 }577}376578579impl ObjectLike for OopObject {377 pub fn iter(580 fn extend_from(&self, sup: ObjValue) -> ObjValue {378 &self,379 #[cfg(feature = "exp-preserve-order")] preserve_order: bool,380 ) -> impl Iterator<Item = (IStr, Result<Val>)> + '_ {581 ObjValue::new(match &self.sup {381 let fields = self.fields(582 None => Self::new(382 #[cfg(feature = "exp-preserve-order")]583 Some(sup),383 preserve_order,584 self.this_entries.clone(),384 );585 self.assertions.clone(),385 fields.into_iter().map(|field| {386 (586 ),587 Some(v) => Self::new(387 field.clone(),588 Some(v.extend_from(sup)),388 self.get(field)589 self.this_entries.clone(),389 .map(|opt| opt.expect("iterating over keys, field exists")),590 self.assertions.clone(),390 )591 ),391 })592 })392 }593 }594393 pub fn get_lazy(&self, key: IStr) -> Option<Thunk<Val>> {595 fn len(&self) -> usize {394 #[derive(Trace)]596 self.fields_visibility()395 struct ThunkGet {597 .into_iter()598 .filter(|(_, (visible, _))| *visible)396 obj: ObjValue,599 .count()600 }601602 fn is_empty(&self) -> bool {397 key: IStr,603 if !self.this_entries.is_empty() {604 return false;398 }605 }399 impl ThunkValue for ThunkGet {606 self.sup.as_ref().map_or(true, ObjValue::is_empty)400 type Output = Val;607 }401608402 fn get(self: Box<Self>) -> Result<Self::Output> {609 /// Run callback for every field found in object610 ///611 /// Returns true if ended prematurely612 fn enum_fields(&self, depth: SuperDepth, handler: &mut EnumFieldsHandler<'_>) -> bool {403 Ok(self.obj.get(self.key)?.expect("field exists"))613 if let Some(s) = &self.sup {614 if s.enum_fields(depth.deeper(), handler) {615 return true;404 }616 }405 }617 }618 for (name, member) in self.this_entries.iter() {619 if handler(620 depth,621 member.original_index,622 name.clone(),623 member.flags.visibility(),624 ) {625 return true;626 }627 }628 false629 }406630407 if !self.has_field_ex(key.clone(), true) {631 fn has_field_include_hidden(&self, name: IStr) -> bool {632 if self.this_entries.contains_key(&name) {633 true634 } else if let Some(super_obj) = &self.sup {408 return None;635 super_obj.has_field_include_hidden(name)636 } else {637 false409 }638 }410 Some(Thunk::new(ThunkGet {411 obj: self.clone(),412 key,413 }))414 }639 }415 pub fn get(&self, key: IStr) -> Result<Option<Val>> {640 fn has_field(&self, name: IStr) -> bool {416 self.get_for(key, self.0.this.clone().unwrap_or_else(|| self.clone()))641 self.field_visibility(name)642 .map_or(false, |v| v.is_visible())417 }643 }644418 pub fn get_for(&self, key: IStr, this: Self) -> Result<Option<Val>> {645 fn get_for(&self, key: IStr, this: ObjValue) -> Result<Option<Val>> {419 self.run_assertions()?;646 let cache_key = (key.clone(), Some(this.clone().downgrade()));420 let cache_key = (421 key.clone(),422 (!ObjValue::ptr_eq(&this, self)).then(|| this.clone().downgrade()),423 );424 if let Some(v) = self.0.value_cache.borrow().get(&cache_key) {647 if let Some(v) = self.value_cache.borrow().get(&cache_key) {425 return Ok(match v {648 return Ok(match v {426 CacheValue::Cached(v) => Some(v.clone()),649 CacheValue::Cached(v) => Some(v.clone()),427 CacheValue::NotFound => None,650 CacheValue::NotFound => None,428 CacheValue::Pending => throw!(InfiniteRecursionDetected),651 CacheValue::Pending => throw!(InfiniteRecursionDetected),429 CacheValue::Errored(e) => return Err(e.clone()),652 CacheValue::Errored(e) => return Err(e.clone()),430 });653 });431 }654 }432 self.0655 self.value_cache433 .value_cache434 .borrow_mut()656 .borrow_mut()435 .insert(cache_key.clone(), CacheValue::Pending);657 .insert(cache_key.clone(), CacheValue::Pending);436 let value = self.get_raw(key, this).map_err(|e| {658 let value = self.get_for_uncached(key, this).map_err(|e| {437 self.0659 self.value_cache438 .value_cache439 .borrow_mut()660 .borrow_mut()440 .insert(cache_key.clone(), CacheValue::Errored(e.clone()));661 .insert(cache_key.clone(), CacheValue::Errored(e.clone()));441 e662 e442 })?;663 })?;443 self.0.value_cache.borrow_mut().insert(664 self.value_cache.borrow_mut().insert(444 cache_key,665 cache_key,445 value666 value446 .as_ref()667 .as_ref()447 .map_or(CacheValue::NotFound, |v| CacheValue::Cached(v.clone())),668 .map_or(CacheValue::NotFound, |v| CacheValue::Cached(v.clone())),448 );669 );449 Ok(value)670 Ok(value)450 }671 }451452 fn get_raw(&self, key: IStr, real_this: Self) -> Result<Option<Val>> {672 fn get_for_uncached(&self, key: IStr, real_this: ObjValue) -> Result<Option<Val>> {453 match (self.0.this_entries.get(&key), &self.0.sup) {673 match (self.this_entries.get(&key), &self.sup) {454 (Some(k), None) => Ok(Some(self.evaluate_this(k, real_this)?)),674 (Some(k), None) => Ok(Some(self.evaluate_this(k, real_this)?)),455 (Some(k), Some(super_obj)) => {675 (Some(k), Some(super_obj)) => {456 let our = self.evaluate_this(k, real_this.clone())?;676 let our = self.evaluate_this(k, real_this.clone())?;457 if k.add {677 if k.flags.add() {458 super_obj678 super_obj459 .get_raw(key, real_this)?679 .get_raw(key, real_this)?460 .map_or(Ok(Some(our.clone())), |v| {680 .map_or(Ok(Some(our.clone())), |v| {468 (None, None) => Ok(None),688 (None, None) => Ok(None),469 }689 }470 }690 }471 fn evaluate_this(&self, v: &ObjMember, real_this: Self) -> Result<Val> {691 fn field_visibility(&self, name: IStr) -> Option<Visibility> {472 v.invoke.evaluate(self.0.sup.clone(), Some(real_this))692 if let Some(m) = self.this_entries.get(&name) {693 Some(match &m.flags.visibility() {694 Visibility::Normal => self695 .sup696 .as_ref()697 .and_then(|super_obj| super_obj.field_visibility(name))698 .unwrap_or(Visibility::Normal),699 v => *v,700 })701 } else if let Some(super_obj) = &self.sup {702 super_obj.field_visibility(name)703 } else {704 None705 }473 }706 }474707475 fn run_assertions_raw(&self, real_this: &Self) -> Result<()> {708 fn run_assertions_raw(&self, real_this: ObjValue) -> Result<()> {476 if self.0.assertions.is_empty() {709 if self.assertions.is_empty() {477 if let Some(super_obj) = &self.0.sup {710 if let Some(super_obj) = &self.sup {478 super_obj.run_assertions_raw(real_this)?;711 super_obj.run_assertions_raw(real_this)?;479 }712 }480 return Ok(());713 return Ok(());481 }714 }482 if self.0.assertions_ran.borrow_mut().insert(real_this.clone()) {715 if self.assertions_ran.borrow_mut().insert(real_this.clone()) {483 for assertion in self.0.assertions.iter() {716 for assertion in self.assertions.iter() {484 if let Err(e) = assertion.run(self.0.sup.clone(), Some(real_this.clone())) {717 if let Err(e) = assertion.run(self.sup.clone(), Some(real_this.clone())) {485 self.0.assertions_ran.borrow_mut().remove(real_this);718 self.assertions_ran.borrow_mut().remove(&real_this);486 return Err(e);719 return Err(e);487 }720 }488 }721 }489 if let Some(super_obj) = &self.0.sup {722 if let Some(super_obj) = &self.sup {490 super_obj.run_assertions_raw(real_this)?;723 super_obj.run_assertions_raw(real_this)?;491 }724 }492 }725 }493 Ok(())726 Ok(())494 }727 }495 pub fn run_assertions(&self) -> Result<()> {496 self.run_assertions_raw(self)497 }498499 pub fn ptr_eq(a: &Self, b: &Self) -> bool {500 Cc::ptr_eq(&a.0, &b.0)501 }502 pub fn downgrade(self) -> WeakObjValue {503 WeakObjValue(self.0.downgrade())504 }505}728}506729507impl PartialEq for ObjValue {730impl PartialEq for ObjValue {556 }779 }557780558 pub fn build(self) -> ObjValue {781 pub fn build(self) -> ObjValue {559 ObjValue::new(self.sup, Cc::new(self.map), Cc::new(self.assertions))782 if self.sup.is_none() && self.map.is_empty() && self.assertions.is_empty() {783 return ObjValue::new_empty();784 }785 ObjValue::new(OopObject::new(786 self.sup,787 Cc::new(self.map),788 Cc::new(self.assertions),789 ))560 }790 }561}791}562impl Default for ObjValueBuilder {792impl Default for ObjValueBuilder {612 self.kind,842 self.kind,613 self.name,843 self.name,614 ObjMember {844 ObjMember {615 add: self.add,845 flags: ObjFieldFlags::new(self.add, self.visibility),616 visibility: self.visibility,617 original_index: self.original_index,846 original_index: self.original_index,618 invoke: binding,847 invoke: binding,619 location: self.location,848 location: self.location,crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/val.rs
+++ b/crates/jrsonnet-evaluator/src/val.rs
@@ -1,6 +1,7 @@
use std::{
cell::RefCell,
fmt::{self, Debug, Display},
+ hash::Hasher,
mem::replace,
rc::Rc,
};
@@ -8,6 +9,7 @@
use jrsonnet_gcmodule::{Cc, Trace};
use jrsonnet_interner::IStr;
use jrsonnet_types::ValType;
+use rustc_hash::FxHasher;
pub use crate::arr::{ArrValue, ArrayLike};
use crate::{