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

difftreelog

refactor dyn ObjValue

Yaroslav Bolyukin2023-08-10parent: #407ab24.patch.diff
in: master

5 files changed

modifiedCargo.lockdiffbeforeafterboth
218 "typenum",218 "typenum",
219]219]
220
221[[package]]
222name = "derivative"
223version = "2.2.0"
224source = "registry+https://github.com/rust-lang/crates.io-index"
225checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
226dependencies = [
227 "proc-macro2",
228 "quote",
229 "syn 1.0.109",
230]
220231
221[[package]]232[[package]]
222name = "digest"233name = "digest"
346 "anyhow",357 "anyhow",
347 "async-trait",358 "async-trait",
348 "bincode",359 "bincode",
360 "derivative",
349 "hashbrown 0.13.2",361 "hashbrown 0.13.2",
350 "jrsonnet-gcmodule",362 "jrsonnet-gcmodule",
351 "jrsonnet-interner",363 "jrsonnet-interner",
modifiedcrates/jrsonnet-evaluator/Cargo.tomldiffbeforeafterboth
58async-trait = { version = "0.1.60", optional = true }58async-trait = { version = "0.1.60", optional = true }
59# Bigint59# Bigint
60num-bigint = { version = "0.4.3", features = ["serde"], optional = true }60num-bigint = { version = "0.4.3", features = ["serde"], optional = true }
61derivative = "2.2.0"
6162
modifiedcrates/jrsonnet-evaluator/src/gc.rsdiffbeforeafterboth
116 }116 }
117}117}
118118
119#[derive(Debug)]
119pub struct GcHashMap<K, V>(pub HashMap<K, V, BuildHasherDefault<FxHasher>>);120pub struct GcHashMap<K, V>(
121 pub HashMap<K, V, BuildHasherDefault<FxHasher>>
122);
modifiedcrates/jrsonnet-evaluator/src/obj.rsdiffbeforeafterboth
1use 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},
9495
95use ordering::*;96use ordering::*;
9697
98// 0 - add
99// 12 - visibility
100#[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 != 0
117 }
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}
135
97#[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>,
127
128 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}
133182
183type EnumFieldsHandler<'a> = dyn FnMut(SuperDepth, FieldIndex, IStr, Visibility) -> bool + 'a;
184
185pub 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 executed
188 fn with_this(&self, me: ObjValue, this: ObjValue) -> ObjValue {
189 ObjValue::new(ThisOverride { inner: me, this })
190 }
191 fn this(&self) -> Option<ObjValue> {
192 None
193 }
194 fn len(&self) -> usize;
195 fn is_empty(&self) -> bool;
196 // If callback returns false, iteration stops
197 fn enum_fields(&self, depth: SuperDepth, handler: &mut EnumFieldsHandler<'_>) -> bool;
198
199 fn has_field_include_hidden(&self, name: IStr) -> bool;
200 fn has_field(&self, name: IStr) -> bool;
201
202 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>;
205
206 fn run_assertions_raw(&self, this: ObjValue) -> Result<()>;
207}
208
134#[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>>);
136211
137impl PartialEq for WeakObjValue {212impl PartialEq for WeakObjValue {
138 fn eq(&self, other: &Self) -> bool {213 fn eq(&self, other: &Self) -> bool {
150}225}
151226
152#[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>>);
230
231#[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 + {} == obj
158 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 sup
167 debug.field(name, member);
168 }
169 debug.finish_non_exhaustive()
170 }237 }
238
239 fn this(&self) -> Option<ObjValue> {
240 None
241 }
242
243 fn len(&self) -> usize {
244 0
245 }
246
247 fn is_empty(&self) -> bool {
248 true
249 }
250
251 fn enum_fields(&self, _depth: SuperDepth, _handler: &mut EnumFieldsHandler<'_>) -> bool {
252 false
253 }
254
255 fn has_field_include_hidden(&self, _name: IStr) -> bool {
256 false
257 }
258
259 fn has_field(&self, _name: IStr) -> bool {
260 false
261 }
262
263 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 }
269
270 fn run_assertions_raw(&self, _this: ObjValue) -> Result<()> {
271 Ok(())
272 }
273
274 fn field_visibility(&self, _field: IStr) -> Option<Visibility> {
275 None
276 }
171}277}
172278
279#[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 }
291
292 fn extend_from(&self, sup: ObjValue) -> ObjValue {
293 self.inner.extend_from(sup).with_this(self.this.clone())
294 }
295
296 fn this(&self) -> Option<ObjValue> {
297 Some(self.this.clone())
298 }
299
300 fn len(&self) -> usize {
301 self.inner.len()
302 }
303
304 fn is_empty(&self) -> bool {
305 self.inner.is_empty()
306 }
307
308 fn enum_fields(&self, depth: SuperDepth, handler: &mut EnumFieldsHandler<'_>) -> bool {
309 self.inner.enum_fields(depth, handler)
310 }
311
312 fn has_field_include_hidden(&self, name: IStr) -> bool {
313 self.inner.has_field_include_hidden(name)
314 }
315
316 fn has_field(&self, name: IStr) -> bool {
317 self.inner.has_field(name)
318 }
319
320 fn get_for(&self, key: IStr, this: ObjValue) -> Result<Option<Val>> {
321 self.inner.get_for(key, this)
322 }
323
324 fn get_for_uncached(&self, key: IStr, this: ObjValue) -> Result<Option<Val>> {
325 self.inner.get_raw(key, this)
326 }
327
328 fn field_visibility(&self, field: IStr) -> Option<Visibility> {
329 self.inner.field_visibility(field)
330 }
331
332 fn run_assertions_raw(&self, this: ObjValue) -> Result<()> {
333 self.inner.run_assertions_raw(this)
334 }
335}
336
173impl 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 }
220359
221 #[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 }
232
233 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 }
239377
240 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 }
246391
247 /// 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 }
396
397 pub fn get_for(&self, key: IStr, this: ObjValue) -> Result<Option<Val>> {
398 self.0.get_for(key, this)
399 }
400
401 fn get_raw(&self, key: IStr, this: ObjValue) -> Result<Option<Val>> {
402 self.0.get_for_uncached(key, this)
403 }
404
405 fn field_visibility(&self, field: IStr) -> Option<Visibility> {
248 ///406 self.0.field_visibility(field)
249 /// Returns true if ended prematurely407 }
408
409 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 }
416
417 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;
441
261 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 }
446
447 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 false
284 });479 },
480 );
285 out481 out
286 }482 }
287 pub fn fields_ex(483 pub fn fields_ex(
333 preserve_order,529 preserve_order,
334 )530 )
335 }531 }
532}
336533
534impl 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 None
352 }547 }
353 }548 }
354549
355 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 true
358 } else if let Some(super_obj) = &self.0.sup {
359 super_obj.has_field_include_hidden(name)
360 } else {
361 false
362 }
363 }552 }
364553
365 pub fn has_field_ex(&self, name: IStr, include_hidden: bool) -> bool {554 // FIXME: Duplication between ObjValue and OopObject
555 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 false
573 },
574 );
575 out
371 }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}
376578
579impl 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 }
594
393 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 }
601
602 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 }
401608
402 fn get(self: Box<Self>) -> Result<Self::Output> {609 /// Run callback for every field found in object
610 ///
611 /// Returns true if ended prematurely
612 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 false
629 }
406630
407 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 true
634 } else if let Some(super_obj) = &self.sup {
408 return None;635 super_obj.has_field_include_hidden(name)
636 } else {
637 false
409 }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 }
644
418 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_cache
433 .value_cache
434 .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_cache
438 .value_cache
439 .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 e
442 })?;663 })?;
443 self.0.value_cache.borrow_mut().insert(664 self.value_cache.borrow_mut().insert(
444 cache_key,665 cache_key,
445 value666 value
446 .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 }
451
452 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_obj
459 .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 => self
695 .sup
696 .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 None
705 }
473 }706 }
474707
475 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 }
498
499 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}
506729
507impl PartialEq for ObjValue {730impl PartialEq for ObjValue {
556 }779 }
557780
558 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,
modifiedcrates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth
1use std::{1use std::{
2 cell::RefCell,2 cell::RefCell,
3 fmt::{self, Debug, Display},3 fmt::{self, Debug, Display},
4 hash::Hasher,
4 mem::replace,5 mem::replace,
5 rc::Rc,6 rc::Rc,
6};7};
78
8use jrsonnet_gcmodule::{Cc, Trace};9use jrsonnet_gcmodule::{Cc, Trace};
9use jrsonnet_interner::IStr;10use jrsonnet_interner::IStr;
10use jrsonnet_types::ValType;11use jrsonnet_types::ValType;
12use rustc_hash::FxHasher;
1113
12pub use crate::arr::{ArrValue, ArrayLike};14pub use crate::arr::{ArrValue, ArrayLike};
13use crate::{15use crate::{