git.delta.rocks / jrsonnet / refs/commits / 3c9d13d48c21

difftreelog

feat OOP-aware objectRemoveKey

zkxotrvkYaroslav Bolyukin2026-02-08parent: #5ac33cf.patch.diff
in: master

17 files changed

modifiedbindings/jsonnet/src/val_make.rsdiffbeforeafterboth
56/// Make a `JsonnetJsonValue` representing an object.56/// Make a `JsonnetJsonValue` representing an object.
57#[no_mangle]57#[no_mangle]
58pub extern "C" fn jsonnet_json_make_object(_vm: &VM) -> *mut Val {58pub extern "C" fn jsonnet_json_make_object(_vm: &VM) -> *mut Val {
59 Box::into_raw(Box::new(Val::Obj(ObjValue::new_empty())))59 Box::into_raw(Box::new(Val::Obj(ObjValue::empty())))
60}60}
6161
modifiedcrates/jrsonnet-cli/src/tla.rsdiffbeforeafterboth
1use clap::Parser;1use clap::Parser;
2use jrsonnet_evaluator::{IStr, error::Result, function::TlaArg, gc::WithCapacityExt as _, rustc_hash::FxHashMap};2use jrsonnet_evaluator::{
3 error::Result, function::TlaArg, gc::WithCapacityExt as _, rustc_hash::FxHashMap, IStr,
4};
35
4use crate::{ExtFile, ExtStr};6use crate::{ExtFile, ExtStr};
modifiedcrates/jrsonnet-evaluator/src/dynamic.rsdiffbeforeafterboth
1use std::ptr::addr_of;
2use std::{cell::OnceCell, hash::Hasher};1use std::{cell::OnceCell, hash::Hasher, ptr::addr_of};
32
4use educe::Educe;3use educe::Educe;
5use jrsonnet_gcmodule::{Cc, Trace};4use jrsonnet_gcmodule::{Cc, Trace};
modifiedcrates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth
1111
12use self::destructure::destruct;12use self::destructure::destruct;
13use crate::{13use crate::{
14 Context, Error, ObjValue, ObjValueBuilder, ObjectAssertion, Pending, Result, ResultExt, SupThis, Unbound, Val, arr::ArrValue, bail, destructure::evaluate_dest, error::{ErrorKind::*, suggest_object_fields}, evaluate::operator::{evaluate_add_op, evaluate_binary_op_special, evaluate_unary_op}, function::{CallLocation, FuncDesc, FuncVal}, gc::WithCapacityExt as _, in_frame, typed::Typed, val::{CachedUnbound, IndexableVal, NumValue, StrValue, Thunk}, with_state14 arr::ArrValue,
15 bail,
16 destructure::evaluate_dest,
17 error::{suggest_object_fields, ErrorKind::*},
18 evaluate::operator::{evaluate_add_op, evaluate_binary_op_special, evaluate_unary_op},
19 function::{CallLocation, FuncDesc, FuncVal},
20 gc::WithCapacityExt as _,
21 in_frame,
22 typed::Typed,
23 val::{CachedUnbound, IndexableVal, NumValue, StrValue, Thunk},
24 with_state, Context, Error, ObjValue, ObjValueBuilder, ObjectAssertion, Pending, Result,
25 ResultExt, SupThis, Unbound, Val,
15};26};
16pub mod destructure;27pub mod destructure;
17pub mod operator;28pub mod operator;
137 )),148 )),
138 ])));149 ])));
139 destruct(var, value, fctx.clone(), &mut new_bindings)?;150 destruct(var, value, fctx.clone(), &mut new_bindings)?;
140 let ctx = ctx151 let ctx = ctx.clone().extend_bindings(new_bindings).into_future(fctx);
141 .clone()
142 .extend(new_bindings, None, None, None)
143 .into_future(fctx);
144152
145 evaluate_comp(ctx, &specs[1..], callback)?;153 evaluate_comp(ctx, &specs[1..], callback)?;
modifiedcrates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth
27use std::{27use std::{
28 any::Any,28 any::Any,
29 cell::{RefCell, RefMut},29 cell::{RefCell, RefMut},
30 clone::Clone,
30 collections::hash_map::Entry,31 collections::hash_map::Entry,
31 clone::Clone,
32 fmt::{self, Debug},32 fmt::{self, Debug},
33 rc::Rc,33 marker::PhantomData,
34 marker::PhantomData,34 rc::Rc,
35};35};
3636
37pub use ctx::*;37pub use ctx::*;
modifiedcrates/jrsonnet-evaluator/src/obj.rsdiffbeforeafterboth
4 collections::hash_map::Entry,4 collections::hash_map::Entry,
5 fmt::{self, Debug},5 fmt::{self, Debug},
6 hash::{Hash, Hasher},6 hash::{Hash, Hasher},
7 mem,
8 ops::ControlFlow,
7};9};
810
9use educe::Educe;11use educe::Educe;
10use jrsonnet_gcmodule::{cc_dyn, Cc, Trace, Weak};12use jrsonnet_gcmodule::{cc_dyn, Acyclic, Cc, Trace, Weak};
11use jrsonnet_interner::IStr;13use jrsonnet_interner::IStr;
12use jrsonnet_parser::{Span, Visibility};14use jrsonnet_parser::{Span, Visibility};
13use rustc_hash::{FxHashMap, FxHashSet};15use rustc_hash::{FxHashMap, FxHashSet};
74 pub struct SuperDepth(u32);76 pub struct SuperDepth(u32);
75 impl SuperDepth {77 impl SuperDepth {
76 pub(super) fn deepen(&mut self) {78 pub(super) fn deepen(&mut self) {
77 *self.0 += 179 self.0 += 1
78 }80 }
79 }81 }
8082
151}153}
152154
153#[allow(clippy::module_name_repetitions)]155#[allow(clippy::module_name_repetitions)]
154#[derive(Trace)]156#[derive(Trace, Default)]
155#[trace(tracking(force))]157#[trace(tracking(force))]
156pub struct OopObject {158pub struct OopObject {
157 // this: Option<ObjValue>,159 assertions: Vec<CcObjectAssertion>,
158 assertions: Cc<Vec<CcObjectAssertion>>,
159 this_entries: Cc<FxHashMap<IStr, ObjMember>>,160 this_entries: FxHashMap<IStr, ObjMember>,
160 value_cache: RefCell<FxHashMap<(IStr, Option<WeakObjValue>), CacheValue>>,
161}161}
162impl Debug for OopObject {162impl Debug for OopObject {
163 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {163 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
164 f.debug_struct("OopObject")164 f.debug_struct("OopObject")
165 // .field("assertions", &self.assertions)
166 // .field("assertions_ran", &self.assertions_ran)
167 .field("this_entries", &self.this_entries)165 .field("this_entries", &self.this_entries)
168 // .field("value_cache", &self.value_cache)
169 .finish_non_exhaustive()166 .finish_non_exhaustive()
170 }167 }
171}168}
169impl OopObject {
170 fn is_empty(&self) -> bool {
171 self.assertions.is_empty() && self.this_entries.is_empty()
172 }
173}
172174
173type EnumFieldsHandler<'a> = dyn FnMut(SuperDepth, FieldIndex, IStr, Visibility) -> bool + 'a;175type EnumFieldsHandler<'a> =
176 dyn FnMut(SuperDepth, FieldIndex, IStr, EnumFields) -> ControlFlow<()> + 'a;
174177
178pub enum EnumFields {
179 Normal(Visibility),
180 Omit,
181}
182
175#[derive(Trace, Clone)]183#[derive(Trace, Clone)]
176pub enum ValueProcess {184pub enum GetFor {
177 None,185 // Return value
186 Final(Val),
178 SuperPlus,187 // Continue iterating over cores, add current value to sum stack
188 SuperPlus(Val),
189 // Ignore the field value, stop at this layer instead
190 Omit,
191 NotFound,
179}192}
180193
194#[derive(Acyclic, Clone)]
195pub enum FieldVisibility {
196 Found(Visibility),
197 Omit,
198 NotFound,
199}
200
201#[derive(Acyclic, Clone)]
202pub enum HasFieldIncludeHidden {
203 Exists,
204 NotFound,
205 Omit,
206}
207
181pub trait ObjectCore: Trace + Any + Debug {208pub trait ObjectCore: Trace + Any + Debug {
182 // If callback returns false, iteration stops, and this call returns false.209 // If callback returns false, iteration stops, and this call returns false.
183 fn enum_fields_core(210 fn enum_fields_core(
186 handler: &mut EnumFieldsHandler<'_>,213 handler: &mut EnumFieldsHandler<'_>,
187 ) -> bool;214 ) -> bool;
188215
189 fn has_field_include_hidden(&self, name: IStr) -> bool;216 fn has_field_include_hidden_core(&self, name: IStr) -> HasFieldIncludeHidden;
190217
191 fn get_for(&self, key: IStr, sup_this: SupThis) -> Result<Option<(Val, ValueProcess)>>;218 fn get_for_core(&self, key: IStr, sup_this: SupThis) -> Result<GetFor>;
192 // fn get_for_uncached(&self, key: IStr, this: ObjValue) -> Result<Option<(Val, ValueProcess)>>;219 fn field_visibility_core(&self, field: IStr) -> FieldVisibility;
193 fn field_visibility(&self, field: IStr) -> Option<Visibility>;
194220
195 fn run_assertions_raw(&self, sup_this: SupThis) -> Result<()>;221 fn run_assertions_core(&self, sup_this: SupThis) -> Result<()>;
196}222}
197223
198#[derive(Clone, Trace)]224#[derive(Clone, Trace)]
220246
221cc_dyn!(247cc_dyn!(
222 #[derive(Clone, Debug)]248 #[derive(Clone, Debug)]
223 ObjCore, ObjectCore,249 CcObjectCore, ObjectCore,
224 pub fn new() {...}250 pub fn new() {...}
225);251);
226#[derive(Trace, Educe)]252#[derive(Trace, Educe)]
227#[educe(Debug)]253#[educe(Debug)]
228struct ObjValueInner {254struct ObjValueInner {
229 cores: Vec<ObjCore>,255 cores: Vec<CcObjectCore>,
230 assertions_ran: Cell<bool>,256 assertions_ran: Cell<bool>,
231 value_cache: RefCell<FxHashMap<(IStr, CoreIdx), CacheValue>>,257 value_cache: RefCell<FxHashMap<(IStr, CoreIdx), CacheValue>>,
232}258}
251 });277 });
252}278}
253279
280thread_local! {
281 static EMPTY_OBJ: ObjValue = ObjValue(Cc::new(ObjValueInner {
282 cores: vec![],
283 assertions_ran: Cell::new(true),
284 value_cache: Default::default(),
285 }))
286}
287
254#[allow(clippy::module_name_repetitions)]288#[allow(clippy::module_name_repetitions)]
255#[derive(Clone, Trace, Debug, Educe)]289#[derive(Clone, Trace, Debug, Educe)]
256#[educe(PartialEq, Hash, Eq)]290#[educe(PartialEq, Hash, Eq)]
257pub struct ObjValue(291pub struct ObjValue(
258 #[educe(PartialEq(method(Cc::ptr_eq)), Hash(method(identity_hash)))] Cc<ObjValueInner>,292 #[educe(PartialEq(method(Cc::ptr_eq)), Hash(method(identity_hash)))] Cc<ObjValueInner>,
259);293);
260294
295impl ObjValue {
296 pub fn empty() -> Self {
297 EMPTY_OBJ.with(|v| v.clone())
298 }
299 pub fn is_empty(&self) -> bool {
300 self.0.cores.is_empty() || self.len() == 0
301 }
302}
303
261#[derive(Trace, Debug)]304#[derive(Trace, Debug)]
262struct StandaloneSuperCore {305struct StandaloneSuperCore {
263 sup: CoreIdx,306 sup: CoreIdx,
269 super_depth: &mut SuperDepth,312 super_depth: &mut SuperDepth,
270 handler: &mut EnumFieldsHandler<'_>,313 handler: &mut EnumFieldsHandler<'_>,
271 ) -> bool {314 ) -> bool {
272 self.this315 self.this.enum_fields_idx(super_depth, handler, self.sup)
273 .enum_fields_internal(super_depth, handler, self.sup)
274 }316 }
275317
276 fn has_field_include_hidden(&self, name: IStr) -> bool {318 fn has_field_include_hidden_core(&self, name: IStr) -> HasFieldIncludeHidden {
277 self.this.has_field_include_hidden_idx(name, self.sup)319 if self.this.has_field_include_hidden_idx(name, self.sup) {
320 HasFieldIncludeHidden::Exists
321 } else {
322 HasFieldIncludeHidden::NotFound
323 }
278 }324 }
279325
280 fn get_for(&self, key: IStr, _sup_this: SupThis) -> Result<Option<(Val, ValueProcess)>> {326 fn get_for_core(&self, key: IStr, _sup_this: SupThis) -> Result<GetFor> {
281 let v = self.this.get_idx(key, self.sup)?;327 let v = self.this.get_idx(key, self.sup)?;
282 Ok(v.map(|v| (v, ValueProcess::None)))328 Ok(v.map_or(GetFor::NotFound, |v| GetFor::Final(v)))
283 }329 }
284330
285 fn field_visibility(&self, field: IStr) -> Option<Visibility> {331 fn field_visibility_core(&self, field: IStr) -> FieldVisibility {
286 self.this.field_visibility_idx(field, self.sup)332 match self.this.field_visibility_idx(field, self.sup) {
333 Some(c) => FieldVisibility::Found(c),
334 None => FieldVisibility::NotFound,
335 }
287 }336 }
288337
289 fn run_assertions_raw(&self, _sup_this: SupThis) -> Result<()> {338 fn run_assertions_core(&self, _sup_this: SupThis) -> Result<()> {
290 self.this.run_assertions()339 self.this.run_assertions()
291 }340 }
292}341}
293342
294#[derive(Debug, Trace)]343#[derive(Debug, Acyclic)]
295struct EmptyObject;344struct OmitFieldsCore {
345 omit: FxHashSet<IStr>,
346}
296impl ObjectCore for EmptyObject {347impl ObjectCore for OmitFieldsCore {
297 fn enum_fields_core(348 fn enum_fields_core(
298 &self,349 &self,
299 _super_depth: &mut SuperDepth,350 super_depth: &mut SuperDepth,
300 _handler: &mut EnumFieldsHandler<'_>,351 handler: &mut EnumFieldsHandler<'_>,
301 ) -> bool {352 ) -> bool {
353 let mut fi = FieldIndex::default();
354 for f in &self.omit {
355 if let ControlFlow::Break(()) = handler(*super_depth, fi, f.clone(), EnumFields::Omit) {
356 return false;
357 }
358 fi = fi.next();
359 }
302 true360 true
303 }361 }
304362
305 fn has_field_include_hidden(&self, _name: IStr) -> bool {363 fn has_field_include_hidden_core(&self, name: IStr) -> HasFieldIncludeHidden {
306 false364 if self.omit.contains(&name) {
365 return HasFieldIncludeHidden::Omit;
366 }
367 HasFieldIncludeHidden::NotFound
307 }368 }
308369
309 fn get_for(&self, _key: IStr, _sup_this: SupThis) -> Result<Option<(Val, ValueProcess)>> {370 fn get_for_core(&self, key: IStr, _sup_this: SupThis) -> Result<GetFor> {
371 if self.omit.contains(&key) {
310 Ok(None)372 return Ok(GetFor::Omit);
373 }
374 Ok(GetFor::NotFound)
311 }375 }
312376
313 fn run_assertions_raw(&self, _sup_this: SupThis) -> Result<()> {377 fn field_visibility_core(&self, field: IStr) -> FieldVisibility {
378 if self.omit.contains(&field) {
314 Ok(())379 return FieldVisibility::Omit;
380 }
381 FieldVisibility::NotFound
315 }382 }
316383
317 fn field_visibility(&self, _field: IStr) -> Option<Visibility> {384 fn run_assertions_core(&self, _sup_this: SupThis) -> Result<()> {
318 None385 Ok(())
319 }386 }
320}387}
321388
363 if !self.sup.super_exists() {430 if !self.sup.super_exists() {
364 bail!(NoSuperFound)431 bail!(NoSuperFound)
365 }432 }
366 Ok(ObjValue::new(StandaloneSuperCore {433 let mut out = ObjValue::builder();
434 out.reserve_cores(1).extend_with_core(StandaloneSuperCore {
367 sup: self.sup,435 sup: self.sup,
368 this: self.this.clone(),436 this: self.this.clone(),
369 }))437 });
438 Ok(out.build())
370 }439 }
371 pub fn this(&self) -> &ObjValue {440 pub fn this(&self) -> &ObjValue {
372 &self.this441 &self.this
385}454}
386455
387impl ObjValue {456impl ObjValue {
388 pub fn new(v: impl ObjectCore) -> Self {
389 Self(Cc::new(ObjValueInner {
390 cores: vec![ObjCore::new(v)],
391 assertions_ran: Cell::new(false),
392 value_cache: RefCell::new(FxHashMap::new()),
393 }))
394 }
395 pub fn new_empty() -> Self {
396 Self::new(EmptyObject)
397 }
398 pub fn builder() -> ObjValueBuilder {457 pub fn builder() -> ObjValueBuilder {
399 ObjValueBuilder::new()458 ObjValueBuilder::new()
400 }459 }
420 ObjMemberBuilder::new(ExtendBuilder(self), name, FieldIndex::default())479 ObjMemberBuilder::new(ExtendBuilder(self), name, FieldIndex::default())
421 }480 }
422481
482 pub fn extend(&mut self) -> ObjValueBuilder {
483 let mut out = ObjValueBuilder::new();
484 out.with_super(self.clone());
485 out
486 }
487
423 #[must_use]488 #[must_use]
424 pub fn extend_from(&self, sup: Self) -> Self {489 pub fn extend_from(&self, sup: Self) -> Self {
425 let mut cores = sup.0.cores.clone();490 let mut cores = sup.0.cores.clone();
442 .filter(|(_, (visible, _))| *visible)507 .filter(|(_, (visible, _))| *visible)
443 .count()508 .count()
444 }509 }
445 pub fn is_empty(&self) -> bool {
446 self.len() == 0
447 }
448 /// For each field, calls callback.510 /// For each field, calls callback.
449 /// If callback returns false - ends iteration prematurely.511 /// If callback returns false - ends iteration prematurely.
450 ///512 ///
451 /// Returns false if ended prematurely513 /// Returns false if ended prematurely
452 pub fn enum_fields(&self, handler: &mut EnumFieldsHandler<'_>) -> bool {514 pub fn enum_fields(&self, handler: &mut EnumFieldsHandler<'_>) -> bool {
453 let mut super_depth = SuperDepth::default();515 let mut super_depth = SuperDepth::default();
454 self.enum_fields_internal(516 self.enum_fields_idx(
455 &mut super_depth,517 &mut super_depth,
456 handler,518 handler,
457 CoreIdx {519 CoreIdx {
458 idx: self.0.cores.len(),520 idx: self.0.cores.len(),
459 },521 },
460 )522 )
461 }523 }
462 fn enum_fields_internal(524 fn enum_fields_idx(
463 &self,525 &self,
464 super_depth: &mut SuperDepth,526 super_depth: &mut SuperDepth,
465 handler: &mut EnumFieldsHandler<'_>,527 handler: &mut EnumFieldsHandler<'_>,
483 )545 )
484 }546 }
485 fn has_field_include_hidden_idx(&self, name: IStr, core: CoreIdx) -> bool {547 fn has_field_include_hidden_idx(&self, name: IStr, core: CoreIdx) -> bool {
486 self.0.cores[..core.idx]548 for ele in self.0.cores[..core.idx].iter().rev() {
487 .iter()
488 .rev()
489 .any(|v| v.0.has_field_include_hidden(name.clone()))549 match ele.0.has_field_include_hidden_core(name.clone()) {
550 HasFieldIncludeHidden::Exists => return true,
551 HasFieldIncludeHidden::NotFound => {}
552 HasFieldIncludeHidden::Omit => break,
553 }
554 }
555 false
490 }556 }
491 pub fn has_field(&self, name: IStr) -> bool {557 pub fn has_field(&self, name: IStr) -> bool {
492 match self.field_visibility(name) {558 match self.field_visibility(name) {
544 sup: CoreIdx { idx: sup },610 sup: CoreIdx { idx: sup },
545 this: self.clone(),611 this: self.clone(),
546 };612 };
547 if let Some((val, proc)) = core.0.get_for(key.clone(), sup_this)? {613 match core.0.get_for_core(key.clone(), sup_this)? {
548 match proc {614 GetFor::Final(val) if add_stack.is_empty() => return Ok(Some(val)),
549 ValueProcess::None if add_stack.is_empty() => return Ok(Some(val)),
550 ValueProcess::None => {615 GetFor::Final(val) => {
551 add_stack.push(val);
552 break;
553 }
554 ValueProcess::SuperPlus => {
555 add_stack.push(val);616 add_stack.push(val);
556 }617 break;
557 }618 }
619 GetFor::SuperPlus(val) => {
620 add_stack.push(val);
621 }
622 GetFor::Omit => {
623 break;
624 }
625 GetFor::NotFound => {
626 continue;
627 }
558 }628 }
559 }629 }
560 if add_stack.is_empty() {630 if add_stack.is_empty() {
594 fn field_visibility_idx(&self, field: IStr, core: CoreIdx) -> Option<Visibility> {664 fn field_visibility_idx(&self, field: IStr, core: CoreIdx) -> Option<Visibility> {
595 let mut exists = false;665 let mut exists = false;
596 for ele in self.0.cores[..core.idx].iter().rev() {666 for ele in self.0.cores[..core.idx].iter().rev() {
597 let vis = ele.0.field_visibility(field.clone());667 let vis = ele.0.field_visibility_core(field.clone());
598 match vis {668 match vis {
599 Some(Visibility::Unhide | Visibility::Hidden) => return vis,669 FieldVisibility::Found(vis @ (Visibility::Unhide | Visibility::Hidden)) => {
670 return Some(vis)
600 Some(Visibility::Normal) => exists = true,671 }
672 FieldVisibility::Found(Visibility::Normal) => exists = true,
601 None => {}673 FieldVisibility::NotFound => {}
674 FieldVisibility::Omit => break,
602 }675 }
603 }676 }
604 exists.then_some(Visibility::Normal)677 exists.then_some(Visibility::Normal)
616 sup: CoreIdx { idx },689 sup: CoreIdx { idx },
617 this: self.clone(),690 this: self.clone(),
618 };691 };
619 ele.0.run_assertions_raw(sup_this).inspect_err(|_e| {692 ele.0.run_assertions_core(sup_this).inspect_err(|_e| {
620 finish_asserting(self);693 finish_asserting(self);
621 })?;694 })?;
622 }695 }
664 self.enum_fields(&mut |depth, index, name, visibility| {737 self.enum_fields(&mut |depth, index, name, visibility| {
665 let new_sort_key = FieldSortKey::new(depth, index);738 let new_sort_key = FieldSortKey::new(depth, index);
666 let entry = out.entry(name);739 let entry = out.entry(name);
740 if matches!(visibility, EnumFields::Omit) {
741 if let Entry::Occupied(v) = entry {
742 v.remove();
743 }
744 return ControlFlow::Continue(());
745 }
667 let (visible, _) = entry.or_insert((true, new_sort_key));746 let (visible, _) = entry.or_insert((true, new_sort_key));
668 match visibility {747 match visibility {
669 Visibility::Normal => {}748 EnumFields::Omit => unreachable!(),
749 EnumFields::Normal(Visibility::Normal) => {}
670 Visibility::Hidden => {750 EnumFields::Normal(Visibility::Hidden) => {
671 *visible = false;751 *visible = false;
672 }752 }
673 Visibility::Unhide => {753 EnumFields::Normal(Visibility::Unhide) => {
674 *visible = true;754 *visible = true;
675 }755 }
676 };756 };
677 false757 return ControlFlow::Continue(());
678 });758 });
679 out759 out
680 }760 }
776856
777impl OopObject {857impl OopObject {
778 pub fn new(858 pub fn new(
779 this_entries: Cc<FxHashMap<IStr, ObjMember>>,859 this_entries: FxHashMap<IStr, ObjMember>,
780 assertions: Cc<Vec<CcObjectAssertion>>,860 assertions: Vec<CcObjectAssertion>,
781 ) -> Self {861 ) -> Self {
782 Self {862 Self {
783 this_entries,863 this_entries,
784 value_cache: RefCell::new(FxHashMap::new()),
785 assertions,864 assertions,
786 }865 }
787 }866 }
794 handler: &mut EnumFieldsHandler<'_>,873 handler: &mut EnumFieldsHandler<'_>,
795 ) -> bool {874 ) -> bool {
796 for (name, member) in self.this_entries.iter() {875 for (name, member) in self.this_entries.iter() {
797 if handler(876 if matches!(
877 handler(
798 *super_depth,878 *super_depth,
799 member.original_index,879 member.original_index,
800 name.clone(),880 name.clone(),
801 member.flags.visibility(),881 EnumFields::Normal(member.flags.visibility()),
882 ),
883 ControlFlow::Break(())
802 ) {884 ) {
803 return false;885 return false;
804 }886 }
805 }887 }
806 true888 true
807 }889 }
808890
809 fn has_field_include_hidden(&self, name: IStr) -> bool {891 fn has_field_include_hidden_core(&self, name: IStr) -> HasFieldIncludeHidden {
810 self.this_entries.contains_key(&name)892 if self.this_entries.contains_key(&name) {
893 HasFieldIncludeHidden::Exists
894 } else {
895 HasFieldIncludeHidden::NotFound
896 }
811 }897 }
812898
813 fn get_for(&self, key: IStr, sup_this: SupThis) -> Result<Option<(Val, ValueProcess)>> {899 fn get_for_core(&self, key: IStr, sup_this: SupThis) -> Result<GetFor> {
814 match self.this_entries.get(&key) {900 match self.this_entries.get(&key) {
815 Some(k) => Ok(Some((901 Some(k) => {
816 k.invoke.evaluate(sup_this)?,902 let v = k.invoke.evaluate(sup_this)?;
817 if k.flags.add() {903 Ok(if k.flags.add() {
818 ValueProcess::SuperPlus904 GetFor::SuperPlus(v)
819 } else {905 } else {
820 ValueProcess::None906 GetFor::Final(v)
821 },907 })
822 ))),908 }
823 None => Ok(None),909 None => Ok(GetFor::NotFound),
824 }910 }
825 }911 }
826 fn field_visibility(&self, name: IStr) -> Option<Visibility> {912 fn field_visibility_core(&self, name: IStr) -> FieldVisibility {
827 Some(self.this_entries.get(&name)?.flags.visibility())913 match self.this_entries.get(&name) {
914 Some(f) => FieldVisibility::Found(f.flags.visibility()),
915 None => FieldVisibility::NotFound,
916 }
828 }917 }
829918
830 fn run_assertions_raw(&self, sup_this: SupThis) -> Result<()> {919 fn run_assertions_core(&self, sup_this: SupThis) -> Result<()> {
831 if self.assertions.is_empty() {920 if self.assertions.is_empty() {
832 return Ok(());921 return Ok(());
833 }922 }
840929
841#[allow(clippy::module_name_repetitions)]930#[allow(clippy::module_name_repetitions)]
842pub struct ObjValueBuilder {931pub struct ObjValueBuilder {
843 sup: Option<ObjValue>,932 sup: Vec<CcObjectCore>,
844 map: FxHashMap<IStr, ObjMember>,933
845 assertions: Vec<CcObjectAssertion>,934 new: OopObject,
846 next_field_index: FieldIndex,935 next_field_index: FieldIndex,
847}936}
848impl ObjValueBuilder {937impl ObjValueBuilder {
851 }940 }
852 pub fn with_capacity(capacity: usize) -> Self {941 pub fn with_capacity(capacity: usize) -> Self {
853 Self {942 Self {
854 sup: None,943 sup: vec![],
855 map: FxHashMap::with_capacity(capacity),944 new: OopObject {
945 assertions: vec![],
946 this_entries: FxHashMap::with_capacity(capacity),
856 assertions: Vec::new(),947 },
857 next_field_index: FieldIndex::default(),948 next_field_index: FieldIndex::default(),
858 }949 }
859 }950 }
951 pub fn reserve_cores(&mut self, capacity: usize) -> &mut Self {
952 self.sup.reserve_exact(capacity);
953 self
954 }
860 pub fn reserve_asserts(&mut self, capacity: usize) -> &mut Self {955 pub fn reserve_asserts(&mut self, capacity: usize) -> &mut Self {
861 self.assertions.reserve_exact(capacity);956 self.new.assertions.reserve_exact(capacity);
862 self957 self
863 }958 }
864 pub fn with_super(&mut self, super_obj: ObjValue) -> &mut Self {959 pub fn with_super(&mut self, super_obj: ObjValue) -> &mut Self {
865 self.sup = Some(super_obj);960 self.sup = super_obj.0.cores.clone();
866 self961 self
867 }962 }
868963
869 pub fn assert(&mut self, assertion: impl ObjectAssertion + 'static) -> &mut Self {964 pub fn assert(&mut self, assertion: impl ObjectAssertion + 'static) -> &mut Self {
870 self.assertions.push(CcObjectAssertion::new(assertion));965 self.new.assertions.push(CcObjectAssertion::new(assertion));
871 self966 self
872 }967 }
873 pub fn field(&mut self, name: impl Into<IStr>) -> ObjMemberBuilder<ValueBuilder<'_>> {968 pub fn field(&mut self, name: impl Into<IStr>) -> ObjMemberBuilder<ValueBuilder<'_>> {
892 Ok(self)987 Ok(self)
893 }988 }
894989
895 pub fn build(self) -> ObjValue {990 pub fn extend_with_core(&mut self, core: impl ObjectCore) {
896 if self.sup.is_none() && self.map.is_empty() && self.assertions.is_empty() {991 self.commit();
992 self.sup.push(CcObjectCore::new(core));
993 }
994
995 fn commit(&mut self) {
996 if !self.new.is_empty() {
897 return ObjValue::new_empty();997 self.sup.push(CcObjectCore::new(mem::take(&mut self.new)));
898 }998 }
899 let res = ObjValue::new(OopObject::new(Cc::new(self.map), Cc::new(self.assertions)));999 self.next_field_index = FieldIndex::default();
1000 }
1001
1002 pub fn with_fields_omitted(&mut self, omit: FxHashSet<IStr>) {
1003 self.commit();
1004 self.sup.push(CcObjectCore::new(OmitFieldsCore { omit }));
1005 }
1006
1007 pub fn build(mut self) -> ObjValue {
1008 self.commit();
900 self.sup.map(|sup| res.extend_from(sup)).unwrap_or(res)1009 if self.sup.is_empty() {
1010 return ObjValue::empty();
1011 }
1012 ObjValue(Cc::new(ObjValueInner {
1013 cores: self.sup,
1014 assertions_ran: Cell::new(false),
1015 value_cache: Default::default(),
1016 }))
901 }1017 }
902}1018}
903impl Default for ObjValueBuilder {1019impl Default for ObjValueBuilder {
968 pub fn value(self, value: impl Into<Val>) {1084 pub fn value(self, value: impl Into<Val>) {
969 let (receiver, name, member) =1085 let (receiver, name, member) =
970 self.build_member(MaybeUnbound::Bound(Thunk::evaluated(value.into())));1086 self.build_member(MaybeUnbound::Bound(Thunk::evaluated(value.into())));
971 let entry = receiver.0.map.entry(name);1087 let entry = receiver.0.new.this_entries.entry(name);
972 entry.insert_entry(member);1088 entry.insert_entry(member);
973 }1089 }
9741090
985 pub fn binding(self, binding: MaybeUnbound) -> Result<()> {1101 pub fn binding(self, binding: MaybeUnbound) -> Result<()> {
986 let (receiver, name, member) = self.build_member(binding);1102 let (receiver, name, member) = self.build_member(binding);
987 let location = member.location.clone();1103 let location = member.location.clone();
988 let old = receiver.0.map.insert(name.clone(), member);1104 let old = receiver.0.new.this_entries.insert(name.clone(), member);
989 if old.is_some() {1105 if old.is_some() {
990 in_frame(1106 in_frame(
991 CallLocation(location.as_ref()),1107 CallLocation(location.as_ref()),
modifiedcrates/jrsonnet-stdlib/src/manifest/xml.rsdiffbeforeafterboth
62 if let Val::Obj(attrs) = maybe_attrs {62 if let Val::Obj(attrs) = maybe_attrs {
63 (true, attrs)63 (true, attrs)
64 } else {64 } else {
65 (false, ObjValue::new_empty())65 (false, ObjValue::empty())
66 }66 }
67 } else {67 } else {
68 (false, ObjValue::new_empty())68 (false, ObjValue::empty())
69 };69 };
70 Ok(Self::Tag {70 Ok(Self::Tag {
71 tag,71 tag,
modifiedcrates/jrsonnet-stdlib/src/misc.rsdiffbeforeafterboth
172 let Some(patch) = patch.as_obj() else {172 let Some(patch) = patch.as_obj() else {
173 return Ok(patch);173 return Ok(patch);
174 };174 };
175 let target = target.as_obj().unwrap_or_else(|| ObjValue::new_empty());175 let target = target.as_obj().unwrap_or_else(|| ObjValue::empty());
176 let target_fields = target176 let target_fields = target
177 .fields(177 .fields(
178 // FIXME: Makes no sense to preserve order for BTreeSet, it would be better to use IndexSet here?178 // FIXME: Makes no sense to preserve order for BTreeSet, it would be better to use IndexSet here?
modifiedcrates/jrsonnet-stdlib/src/objects.rsdiffbeforeafterboth
1use jrsonnet_evaluator::{1use jrsonnet_evaluator::{
2 function::builtin,2 function::builtin,
3 gc::WithCapacityExt,
3 rustc_hash::FxHashSet,4 rustc_hash::FxHashSet,
4 val::{ArrValue, Val},5 val::{ArrValue, Val},
5 IStr, MaybeUnbound, ObjValue, ObjValueBuilder, Thunk,6 IStr, ObjValue, ObjValueBuilder,
6};7};
78
8#[builtin]9#[builtin]
158#[builtin]159#[builtin]
159pub fn builtin_object_remove_key(160pub fn builtin_object_remove_key(obj: ObjValue, key: IStr) -> ObjValue {
160 obj: ObjValue,
161 key: IStr,
162
163 // Standard implementation uses std.objectFields without such argument, we can't
164 // assume order preservation should always be enabled/disabled
165 #[default(false)]
166 #[cfg(feature = "exp-preserve-order")]
167 preserve_order: bool,
168) -> ObjValue {
169 let mut new_obj = ObjValueBuilder::with_capacity(obj.len() - 1);161 let mut omit = FxHashSet::with_capacity(1);
170 let all_fields = obj.fields_ex(162 omit.insert(key);
171 true,163
172 #[cfg(feature = "exp-preserve-order")]
173 preserve_order,
174 );
175 let visible_fields = obj164 let mut out = ObjValueBuilder::new();
176 .fields_ex(
177 false,
178 #[cfg(feature = "exp-preserve-order")]
179 preserve_order,
180 )
181 .into_iter()
182 .collect::<FxHashSet<_>>();
183
184 for field in &all_fields {
185 if *field == key {
186 continue;
187 }
188 let mut b = new_obj.field(field.clone());
189 if !visible_fields.contains(&field) {165 out.with_super(obj).with_fields_omitted(omit);
190 b = b.hide();
191 }
192 let _ = b.binding(MaybeUnbound::Bound(Thunk::result(
193 obj.get(field.clone()).transpose().expect("field exists"),
194 )));
195 }
196
197 new_obj.build()166 out.build()
198}167}
199168
modifiedtests/tests/as_native.rsdiffbeforeafterboth
1use jrsonnet_evaluator::{trace::PathResolver, FileImportResolver, Result, State};1use jrsonnet_evaluator::{FileImportResolver, Result, State, trace::PathResolver};
2use jrsonnet_stdlib::ContextInitializer;2use jrsonnet_stdlib::ContextInitializer;
33
4mod common;4mod common;
modifiedtests/tests/builtin.rsdiffbeforeafterboth
1mod common;1mod common;
22
3use jrsonnet_evaluator::{3use jrsonnet_evaluator::{
4 ContextBuilder, ContextInitializer, FileImportResolver, Result, State, Thunk, Val,
4 function::{builtin, builtin::Builtin, CallLocation, FuncVal},5 function::{CallLocation, FuncVal, builtin, builtin::Builtin},
5 parser::Source,6 parser::Source,
6 trace::PathResolver,7 trace::PathResolver,
7 typed::Typed,8 typed::Typed,
8 ContextBuilder, ContextInitializer, FileImportResolver, Result, State, Thunk, Val,
9};9};
10use jrsonnet_gcmodule::Trace;10use jrsonnet_gcmodule::Trace;
11use jrsonnet_stdlib::ContextInitializer as StdContextInitializer;11use jrsonnet_stdlib::ContextInitializer as StdContextInitializer;
modifiedtests/tests/common.rsdiffbeforeafterboth
1use jrsonnet_evaluator::{1use jrsonnet_evaluator::{
2 bail,
3 function::{builtin, FuncVal},
4 parser::Source,
5 ContextBuilder, ContextInitializer as ContextInitializerT, ObjValueBuilder, Result, Thunk, Val,2 ContextBuilder, ContextInitializer as ContextInitializerT, ObjValueBuilder, Result, Thunk, Val,
3 bail,
4 function::{FuncVal, builtin},
5 parser::Source,
6};6};
7use jrsonnet_gcmodule::Trace;7use jrsonnet_gcmodule::Trace;
88
modifiedtests/tests/golden.rsdiffbeforeafterboth
4};4};
55
6use jrsonnet_evaluator::{6use jrsonnet_evaluator::{
7 FileImportResolver, State,
7 manifest::JsonFormat,8 manifest::JsonFormat,
8 trace::{CompactFormat, PathResolver, TraceFormat},9 trace::{CompactFormat, PathResolver, TraceFormat},
9 FileImportResolver, State,
10};10};
11use jrsonnet_stdlib::ContextInitializer;11use jrsonnet_stdlib::ContextInitializer;
12mod common;12mod common;
modifiedtests/tests/sanity.rsdiffbeforeafterboth
1use jrsonnet_evaluator::{1use jrsonnet_evaluator::{
2 bail,2 FileImportResolver, Result, State, Val, bail,
3 trace::{CompactFormat, PathResolver, TraceFormat},3 trace::{CompactFormat, PathResolver, TraceFormat},
4 FileImportResolver, Result, State, Val,
5};4};
6use jrsonnet_stdlib::ContextInitializer;5use jrsonnet_stdlib::ContextInitializer;
76
modifiedtests/tests/std_native.rsdiffbeforeafterboth
1use jrsonnet_evaluator::{function::builtin, trace::PathResolver, State};1use jrsonnet_evaluator::{State, function::builtin, trace::PathResolver};
2use jrsonnet_stdlib::ContextInitializer;2use jrsonnet_stdlib::ContextInitializer;
33
4#[builtin]4#[builtin]
modifiedtests/tests/suite.rsdiffbeforeafterboth
4};4};
55
6use jrsonnet_evaluator::{6use jrsonnet_evaluator::{
7 FileImportResolver, State, Val,
7 trace::{CompactFormat, PathResolver, TraceFormat},8 trace::{CompactFormat, PathResolver, TraceFormat},
8 FileImportResolver, State, Val,
9};9};
10use jrsonnet_stdlib::ContextInitializer;10use jrsonnet_stdlib::ContextInitializer;
1111
modifiedtests/tests/typed_obj.rsdiffbeforeafterboth
22
3use std::fmt::Debug;3use std::fmt::Debug;
44
5use jrsonnet_evaluator::{trace::PathResolver, typed::Typed, Result, State};5use jrsonnet_evaluator::{Result, State, trace::PathResolver, typed::Typed};
6use jrsonnet_stdlib::ContextInitializer;6use jrsonnet_stdlib::ContextInitializer;
77
8#[derive(Clone, Typed, PartialEq, Debug)]8#[derive(Clone, Typed, PartialEq, Debug)]