git.delta.rocks / jrsonnet / refs/commits / eea91c38b18b

difftreelog

fix objectRemoveKey only skips the current stack

qsrrwpnwYaroslav Bolyukin2026-02-08parent: #3c9d13d.patch.diff
in: master

1 file changed

modifiedcrates/jrsonnet-evaluator/src/obj.rsdiffbeforeafterboth
5 fmt::{self, Debug},5 fmt::{self, Debug},
6 hash::{Hash, Hasher},6 hash::{Hash, Hasher},
7 mem,7 mem,
8 num::Saturating,
8 ops::ControlFlow,9 ops::ControlFlow,
9};10};
1011
48 impl SuperDepth {49 impl SuperDepth {
49 pub(super) fn deepen(self) {}50 pub(super) fn deepen(self) {}
50 }51 }
51
52 #[derive(Clone, Copy, Debug)]
53 pub struct FieldSortKey(());
54 impl FieldSortKey {
55 pub const fn new(_: SuperDepth, _: FieldIndex) -> Self {
56 Self(())
57 }
58 }
59}52}
6053
61#[cfg(feature = "exp-preserve-order")]54#[cfg(feature = "exp-preserve-order")]
89 }82 }
90}83}
9184
85#[cfg(feature = "exp-preserve-order")]
92use ordering::{FieldIndex, FieldSortKey, SuperDepth};86use ordering::FieldSortKey;
87use ordering::{FieldIndex, SuperDepth};
9388
94// 0 - add89// 0 - add
95// 12 - visibility90// 12 - visibility
177172
178pub enum EnumFields {173pub enum EnumFields {
179 Normal(Visibility),174 Normal(Visibility),
180 Omit,175 Omit(Skip),
181}176}
182177
183#[derive(Trace, Clone)]178#[derive(Trace, Clone)]
187 // Continue iterating over cores, add current value to sum stack182 // Continue iterating over cores, add current value to sum stack
188 SuperPlus(Val),183 SuperPlus(Val),
189 // Ignore the field value, stop at this layer instead184 // Ignore the field value, stop at this layer instead
190 Omit,185 Omit(#[trace(skip)] Skip),
191 NotFound,186 NotFound,
192}187}
193188
194#[derive(Acyclic, Clone)]189#[derive(Acyclic, Clone)]
195pub enum FieldVisibility {190pub enum FieldVisibility {
196 Found(Visibility),191 Found(Visibility),
197 Omit,192 Omit(Skip),
198 NotFound,193 NotFound,
199}194}
200195
201#[derive(Acyclic, Clone)]196#[derive(Acyclic, Clone)]
202pub enum HasFieldIncludeHidden {197pub enum HasFieldIncludeHidden {
203 Exists,198 Exists,
204 NotFound,199 NotFound,
205 Omit,200 Omit(Skip),
206}201}
207202
203type Skip = Saturating<usize>;
204
208pub trait ObjectCore: Trace + Any + Debug {205pub trait ObjectCore: Trace + Any + Debug {
209 // If callback returns false, iteration stops, and this call returns false.206 // If callback returns false, iteration stops, and this call returns false.
210 fn enum_fields_core(207 fn enum_fields_core(
215212
216 fn has_field_include_hidden_core(&self, name: IStr) -> HasFieldIncludeHidden;213 fn has_field_include_hidden_core(&self, name: IStr) -> HasFieldIncludeHidden;
217214
218 fn get_for_core(&self, key: IStr, sup_this: SupThis) -> Result<GetFor>;215 fn get_for_core(&self, key: IStr, sup_this: SupThis, omit_only: bool) -> Result<GetFor>;
219 fn field_visibility_core(&self, field: IStr) -> FieldVisibility;216 fn field_visibility_core(&self, field: IStr) -> FieldVisibility;
220217
221 fn run_assertions_core(&self, sup_this: SupThis) -> Result<()>;218 fn run_assertions_core(&self, sup_this: SupThis) -> Result<()>;
323 }320 }
324 }321 }
325322
326 fn get_for_core(&self, key: IStr, _sup_this: SupThis) -> Result<GetFor> {323 fn get_for_core(&self, key: IStr, _sup_this: SupThis, omit_only: bool) -> Result<GetFor> {
324 if omit_only {
325 return Ok(GetFor::NotFound);
326 }
327 let v = self.this.get_idx(key, self.sup)?;327 let v = self.this.get_idx(key, self.sup)?;
328 Ok(v.map_or(GetFor::NotFound, |v| GetFor::Final(v)))328 Ok(v.map_or(GetFor::NotFound, |v| GetFor::Final(v)))
329 }329 }
343#[derive(Debug, Acyclic)]343#[derive(Debug, Acyclic)]
344struct OmitFieldsCore {344struct OmitFieldsCore {
345 omit: FxHashSet<IStr>,345 omit: FxHashSet<IStr>,
346 prev_layers: usize,
346}347}
347impl ObjectCore for OmitFieldsCore {348impl ObjectCore for OmitFieldsCore {
348 fn enum_fields_core(349 fn enum_fields_core(
352 ) -> bool {353 ) -> bool {
353 let mut fi = FieldIndex::default();354 let mut fi = FieldIndex::default();
354 for f in &self.omit {355 for f in &self.omit {
355 if let ControlFlow::Break(()) = handler(*super_depth, fi, f.clone(), EnumFields::Omit) {356 if let ControlFlow::Break(()) = handler(
357 *super_depth,
358 fi,
359 f.clone(),
360 EnumFields::Omit(Saturating(self.prev_layers)),
361 ) {
356 return false;362 return false;
357 }363 }
358 fi = fi.next();364 fi = fi.next();
362368
363 fn has_field_include_hidden_core(&self, name: IStr) -> HasFieldIncludeHidden {369 fn has_field_include_hidden_core(&self, name: IStr) -> HasFieldIncludeHidden {
364 if self.omit.contains(&name) {370 if self.omit.contains(&name) {
365 return HasFieldIncludeHidden::Omit;371 return HasFieldIncludeHidden::Omit(Saturating(self.prev_layers));
366 }372 }
367 HasFieldIncludeHidden::NotFound373 HasFieldIncludeHidden::NotFound
368 }374 }
369375
370 fn get_for_core(&self, key: IStr, _sup_this: SupThis) -> Result<GetFor> {376 fn get_for_core(&self, key: IStr, _sup_this: SupThis, _omit_only: bool) -> Result<GetFor> {
371 if self.omit.contains(&key) {377 if self.omit.contains(&key) {
372 return Ok(GetFor::Omit);378 return Ok(GetFor::Omit(Saturating(self.prev_layers)));
373 }379 }
374 Ok(GetFor::NotFound)380 Ok(GetFor::NotFound)
375 }381 }
376382
377 fn field_visibility_core(&self, field: IStr) -> FieldVisibility {383 fn field_visibility_core(&self, field: IStr) -> FieldVisibility {
378 if self.omit.contains(&field) {384 if self.omit.contains(&field) {
379 return FieldVisibility::Omit;385 return FieldVisibility::Omit(Saturating(self.prev_layers));
380 }386 }
381 FieldVisibility::NotFound387 FieldVisibility::NotFound
382 }388 }
503 /// If object only contains hidden fields - may return zero.509 /// If object only contains hidden fields - may return zero.
504 pub fn len(&self) -> usize {510 pub fn len(&self) -> usize {
505 self.fields_visibility()511 self.fields_visibility()
506 .iter()512 .values()
507 .filter(|(_, (visible, _))| *visible)513 .filter(|d| d.visible())
508 .count()514 .count()
509 }515 }
510 /// For each field, calls callback.516 /// For each field, calls callback.
527 handler: &mut EnumFieldsHandler<'_>,533 handler: &mut EnumFieldsHandler<'_>,
528 idx: CoreIdx,534 idx: CoreIdx,
529 ) -> bool {535 ) -> bool {
530 for core in self.0.cores[..idx.idx].iter() {536 for core in self.0.cores[..idx.idx].iter().rev() {
531 if !core.0.enum_fields_core(super_depth, handler) {537 if !core.0.enum_fields_core(super_depth, handler) {
532 return false;538 return false;
533 }539 }
545 )551 )
546 }552 }
547 fn has_field_include_hidden_idx(&self, name: IStr, core: CoreIdx) -> bool {553 fn has_field_include_hidden_idx(&self, name: IStr, core: CoreIdx) -> bool {
554 let mut skip = Saturating(0usize);
548 for ele in self.0.cores[..core.idx].iter().rev() {555 for ele in self.0.cores[..core.idx].iter().rev() {
549 match ele.0.has_field_include_hidden_core(name.clone()) {556 match ele.0.has_field_include_hidden_core(name.clone()) {
550 HasFieldIncludeHidden::Exists => return true,557 HasFieldIncludeHidden::Exists => {
558 if skip.0 == 0 {
559 return true;
560 }
561 }
562 HasFieldIncludeHidden::Omit(new_skip) => {
563 // +1 including this core
564 skip = skip.max(new_skip + Saturating(1));
565 }
551 HasFieldIncludeHidden::NotFound => {}566 HasFieldIncludeHidden::NotFound => {}
552 HasFieldIncludeHidden::Omit => break,
553 }567 }
568 skip -= 1;
554 }569 }
555 false570 false
556 }571 }
605 fn get_idx_uncached(&self, key: IStr, core: CoreIdx) -> Result<Option<Val>> {620 fn get_idx_uncached(&self, key: IStr, core: CoreIdx) -> Result<Option<Val>> {
606 self.run_assertions()?;621 self.run_assertions()?;
607 let mut add_stack = Vec::with_capacity(2);622 let mut add_stack = Vec::with_capacity(2);
623 let mut skip = Saturating(0);
608 for (sup, core) in self.0.cores[..core.idx].iter().enumerate().rev() {624 for (sup, core) in self.0.cores[..core.idx].iter().enumerate().rev() {
609 let sup_this = SupThis {625 let sup_this = SupThis {
610 sup: CoreIdx { idx: sup },626 sup: CoreIdx { idx: sup },
611 this: self.clone(),627 this: self.clone(),
612 };628 };
613 match core.0.get_for_core(key.clone(), sup_this)? {629 match core.0.get_for_core(key.clone(), sup_this, skip.0 != 0)? {
614 GetFor::Final(val) if add_stack.is_empty() => return Ok(Some(val)),630 GetFor::Final(val) if add_stack.is_empty() => {
631 if skip.0 == 0 {
632 return Ok(Some(val));
633 }
634 }
615 GetFor::Final(val) => {635 GetFor::Final(val) => {
616 add_stack.push(val);636 if skip.0 == 0 {
637 add_stack.push(val);
617 break;638 break;
639 }
618 }640 }
619 GetFor::SuperPlus(val) => {641 GetFor::SuperPlus(val) => {
620 add_stack.push(val);642 if skip.0 == 0 {
643 add_stack.push(val);
644 }
621 }645 }
622 GetFor::Omit => {646 GetFor::Omit(new_skip) => {
623 break;647 // +1 including this core
648 skip = skip.max(new_skip + Saturating(1));
624 }649 }
625 GetFor::NotFound => {650 GetFor::NotFound => {}
626 continue;
627 }
628 }651 }
652 skip -= 1;
629 }653 }
630 if add_stack.is_empty() {654 if add_stack.is_empty() {
631 // None of layers had this field655 // None of layers had this field
663 }687 }
664 fn field_visibility_idx(&self, field: IStr, core: CoreIdx) -> Option<Visibility> {688 fn field_visibility_idx(&self, field: IStr, core: CoreIdx) -> Option<Visibility> {
665 let mut exists = false;689 let mut exists = false;
690 let mut skip = Saturating(0usize);
666 for ele in self.0.cores[..core.idx].iter().rev() {691 for ele in self.0.cores[..core.idx].iter().rev() {
667 let vis = ele.0.field_visibility_core(field.clone());692 let vis = ele.0.field_visibility_core(field.clone());
668 match vis {693 match vis {
669 FieldVisibility::Found(vis @ (Visibility::Unhide | Visibility::Hidden)) => {694 FieldVisibility::Found(vis @ (Visibility::Unhide | Visibility::Hidden)) => {
670 return Some(vis)695 if skip.0 == 0 {
696 return Some(vis);
697 }
671 }698 }
672 FieldVisibility::Found(Visibility::Normal) => exists = true,699 FieldVisibility::Found(Visibility::Normal) => {
700 if skip.0 == 0 {
701 exists = true
702 }
703 }
673 FieldVisibility::NotFound => {}704 FieldVisibility::NotFound => {}
674 FieldVisibility::Omit => break,705 FieldVisibility::Omit(new_skip) => {
706 // +1 including this core
707 skip = skip.max(new_skip + Saturating(1));
708 }
675 }709 }
710 skip -= 1;
676 }711 }
677 exists.then_some(Visibility::Normal)712 exists.then_some(Visibility::Normal)
678 }713 }
732 pub fn downgrade(self) -> WeakObjValue {767 pub fn downgrade(self) -> WeakObjValue {
733 WeakObjValue(self.0.downgrade())768 WeakObjValue(self.0.downgrade())
734 }769 }
770}
771
772#[derive(Debug)]
773struct FieldVisibilityData {
735 fn fields_visibility(&self) -> FxHashMap<IStr, (bool, FieldSortKey)> {774 omitted_until: Saturating<usize>,
775 exists_visible: Option<Visibility>,
776 #[cfg(feature = "exp-preserve-order")]
777 key: FieldSortKey,
778}
779impl FieldVisibilityData {
780 fn visible(&self) -> bool {
781 self.exists_visible
782 .expect("non-existing fields shall be dropped at the end of fn fields_visibility()")
783 .is_visible()
784 }
785 #[cfg(feature = "exp-preserve-order")]
786 fn sort_key(&self) -> FieldSortKey {
787 self.key
788 }
789}
790
791impl ObjValue {
792 fn fields_visibility(&self) -> FxHashMap<IStr, FieldVisibilityData> {
736 let mut out = FxHashMap::default();793 let mut out = FxHashMap::default();
794
737 self.enum_fields(&mut |depth, index, name, visibility| {795 let mut super_depth = SuperDepth::default();
796 let mut omit_index = Saturating(0);
797 for core in self.0.cores.iter().rev() {
798 core.0
799 .enum_fields_core(&mut super_depth, &mut |_depth, _index, name, visibility| {
738 let new_sort_key = FieldSortKey::new(depth, index);800 let entry = out.entry(name);
739 let entry = out.entry(name);801 let data = entry.or_insert(FieldVisibilityData {
802 exists_visible: None,
803 #[cfg(feature = "exp-preserve-order")]
740 if matches!(visibility, EnumFields::Omit) {804 key: FieldSortKey::new(_depth, _index),
805 omitted_until: omit_index,
806 });
807 match visibility {
741 if let Entry::Occupied(v) = entry {808 EnumFields::Omit(new_skip) => {
742 v.remove();809 // +1 including this core
810 data.omitted_until = data
743 }811 .omitted_until
744 return ControlFlow::Continue(());812 .max(omit_index + new_skip + Saturating(1));
745 }813 }
746 let (visible, _) = entry.or_insert((true, new_sort_key));814 EnumFields::Normal(Visibility::Normal) => {
815 if data.omitted_until <= omit_index {
747 match visibility {816 if data.exists_visible.is_none() {
748 EnumFields::Omit => unreachable!(),817 data.exists_visible = Some(Visibility::Normal);
749 EnumFields::Normal(Visibility::Normal) => {}818 }
819 }
820 }
821 EnumFields::Normal(Visibility::Hidden) => {
750 EnumFields::Normal(Visibility::Hidden) => {822 if data.omitted_until <= omit_index {
823 data.exists_visible = Some(match data.exists_visible {
824 // We're iterating in reverse, later unhide is preserved
825 Some(Visibility::Unhide) => Visibility::Unhide,
751 *visible = false;826 _ => Visibility::Hidden,
827 });
752 }828 }
753 EnumFields::Normal(Visibility::Unhide) => {829 }
830 EnumFields::Normal(Visibility::Unhide) => {
754 *visible = true;831 if data.omitted_until <= omit_index {
832 data.exists_visible = Some(match data.exists_visible {
833 // We're iterating in reverse, later hide is preserved
834 Some(Visibility::Hidden) => Visibility::Hidden,
835 _ => Visibility::Unhide,
836 });
755 }837 }
756 };838 }
839 };
757 return ControlFlow::Continue(());840 return ControlFlow::Continue(());
758 });841 });
842
843 super_depth.deepen();
844 omit_index += 1;
845 }
846
847 out.retain(|_, v| v.exists_visible.is_some());
848
759 out849 out
760 }850 }
768 let (mut fields, mut keys): (Vec<_>, Vec<_>) = self858 let (mut fields, mut keys): (Vec<_>, Vec<_>) = self
769 .fields_visibility()859 .fields_visibility()
770 .into_iter()860 .into_iter()
771 .filter(|(_, (visible, _))| include_hidden || *visible)861 .filter(|(_, d)| include_hidden || d.visible())
772 .enumerate()862 .enumerate()
773 .map(|(idx, (k, (_, sk)))| (k, (sk, idx)))863 .map(|(idx, (k, d))| (k, (d.sort_key(), idx)))
774 .unzip();864 .unzip();
775 keys.sort_unstable_by_key(|v| v.0);865 keys.sort_unstable_by_key(|v| v.0);
776 // Reorder in-place by resulting indexes866 // Reorder in-place by resulting indexes
794 let mut fields: Vec<_> = self884 let mut fields: Vec<_> = self
795 .fields_visibility()885 .fields_visibility()
796 .into_iter()886 .into_iter()
797 .filter(|(_, (visible, _))| include_hidden || *visible)887 .filter(|(_, d)| include_hidden || d.visible())
798 .map(|(k, _)| k)888 .map(|(k, _)| k)
799 .collect();889 .collect();
800 fields.sort_unstable();890 fields.sort_unstable();
896 }986 }
897 }987 }
898988
899 fn get_for_core(&self, key: IStr, sup_this: SupThis) -> Result<GetFor> {989 fn get_for_core(&self, key: IStr, sup_this: SupThis, omit_only: bool) -> Result<GetFor> {
990 if omit_only {
991 return Ok(GetFor::NotFound);
992 }
900 match self.this_entries.get(&key) {993 match self.this_entries.get(&key) {
901 Some(k) => {994 Some(k) => {
902 let v = k.invoke.evaluate(sup_this)?;995 let v = k.invoke.evaluate(sup_this)?;
10011094
1002 pub fn with_fields_omitted(&mut self, omit: FxHashSet<IStr>) {1095 pub fn with_fields_omitted(&mut self, omit: FxHashSet<IStr>) {
1003 self.commit();1096 self.commit();
1004 self.sup.push(CcObjectCore::new(OmitFieldsCore { omit }));1097 self.sup.push(CcObjectCore::new(OmitFieldsCore {
1098 omit,
1099 prev_layers: self.sup.len(),
1100 }));
1005 }1101 }
10061102
1007 pub fn build(mut self) -> ObjValue {1103 pub fn build(mut self) -> ObjValue {