difftreelog
feat OOP-aware objectRemoveKey
in: master
17 files changed
bindings/jsonnet/src/val_make.rsdiffbeforeafterboth--- a/bindings/jsonnet/src/val_make.rs
+++ b/bindings/jsonnet/src/val_make.rs
@@ -56,5 +56,5 @@
/// Make a `JsonnetJsonValue` representing an object.
#[no_mangle]
pub extern "C" fn jsonnet_json_make_object(_vm: &VM) -> *mut Val {
- Box::into_raw(Box::new(Val::Obj(ObjValue::new_empty())))
+ Box::into_raw(Box::new(Val::Obj(ObjValue::empty())))
}
crates/jrsonnet-cli/src/tla.rsdiffbeforeafterboth--- a/crates/jrsonnet-cli/src/tla.rs
+++ b/crates/jrsonnet-cli/src/tla.rs
@@ -1,5 +1,7 @@
use clap::Parser;
-use jrsonnet_evaluator::{IStr, error::Result, function::TlaArg, gc::WithCapacityExt as _, rustc_hash::FxHashMap};
+use jrsonnet_evaluator::{
+ error::Result, function::TlaArg, gc::WithCapacityExt as _, rustc_hash::FxHashMap, IStr,
+};
use crate::{ExtFile, ExtStr};
crates/jrsonnet-evaluator/src/dynamic.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/dynamic.rs
+++ b/crates/jrsonnet-evaluator/src/dynamic.rs
@@ -1,5 +1,4 @@
-use std::ptr::addr_of;
-use std::{cell::OnceCell, hash::Hasher};
+use std::{cell::OnceCell, hash::Hasher, ptr::addr_of};
use educe::Educe;
use jrsonnet_gcmodule::{Cc, Trace};
crates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs
@@ -11,7 +11,18 @@
use self::destructure::destruct;
use crate::{
- 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_state
+ arr::ArrValue,
+ bail,
+ destructure::evaluate_dest,
+ error::{suggest_object_fields, ErrorKind::*},
+ 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_state, Context, Error, ObjValue, ObjValueBuilder, ObjectAssertion, Pending, Result,
+ ResultExt, SupThis, Unbound, Val,
};
pub mod destructure;
pub mod operator;
@@ -137,10 +148,7 @@
)),
])));
destruct(var, value, fctx.clone(), &mut new_bindings)?;
- let ctx = ctx
- .clone()
- .extend(new_bindings, None, None, None)
- .into_future(fctx);
+ let ctx = ctx.clone().extend_bindings(new_bindings).into_future(fctx);
evaluate_comp(ctx, &specs[1..], callback)?;
}
crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/lib.rs
+++ b/crates/jrsonnet-evaluator/src/lib.rs
@@ -27,11 +27,11 @@
use std::{
any::Any,
cell::{RefCell, RefMut},
+ clone::Clone,
collections::hash_map::Entry,
- clone::Clone,
fmt::{self, Debug},
+ marker::PhantomData,
rc::Rc,
- marker::PhantomData,
};
pub use ctx::*;
crates/jrsonnet-evaluator/src/obj.rsdiffbeforeafterboth4 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};8109use 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 += 178 }80 }79 }81 }8082151}153}152154153#[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}172174173type EnumFieldsHandler<'a> = dyn FnMut(SuperDepth, FieldIndex, IStr, Visibility) -> bool + 'a;175type EnumFieldsHandler<'a> =176 dyn FnMut(SuperDepth, FieldIndex, IStr, EnumFields) -> ControlFlow<()> + 'a;174177178pub enum EnumFields {179 Normal(Visibility),180 Omit,181}182175#[derive(Trace, Clone)]183#[derive(Trace, Clone)]176pub enum ValueProcess {184pub enum GetFor {177 None,185 // Return value186 Final(Val),178 SuperPlus,187 // Continue iterating over cores, add current value to sum stack188 SuperPlus(Val),189 // Ignore the field value, stop at this layer instead190 Omit,191 NotFound,179}192}180193194#[derive(Acyclic, Clone)]195pub enum FieldVisibility {196 Found(Visibility),197 Omit,198 NotFound,199}200201#[derive(Acyclic, Clone)]202pub enum HasFieldIncludeHidden {203 Exists,204 NotFound,205 Omit,206}207181pub 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;188215189 fn has_field_include_hidden(&self, name: IStr) -> bool;216 fn has_field_include_hidden_core(&self, name: IStr) -> HasFieldIncludeHidden;190217191 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>;194220195 fn run_assertions_raw(&self, sup_this: SupThis) -> Result<()>;221 fn run_assertions_core(&self, sup_this: SupThis) -> Result<()>;196}222}197223198#[derive(Clone, Trace)]224#[derive(Clone, Trace)]220246221cc_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}253279280thread_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}287254#[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);260294295impl 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() == 0301 }302}303261#[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 }275317276 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::Exists321 } else {322 HasFieldIncludeHidden::NotFound323 }278 }324 }279325280 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 }284330285 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 }288337289 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}293342294#[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 true303 }361 }304362305 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::NotFound307 }368 }308369309 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 }312376313 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::NotFound315 }382 }316383317 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}321388363 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.this385}454}386455387impl 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 }422481482 pub fn extend(&mut self) -> ObjValueBuilder {483 let mut out = ObjValueBuilder::new();484 out.with_super(self.clone());485 out486 }487423 #[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() == 0447 }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 prematurely452 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 false490 }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 out680 }760 }776856777impl 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 true807 }889 }808890809 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::Exists894 } else {895 HasFieldIncludeHidden::NotFound896 }811 }897 }812898813 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 }829918830 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 }840929841#[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>,933845 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 self954 }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 self863 }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 self867 }962 }868963869 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 self872 }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 }894989895 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 }994995 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 }10011002 pub fn with_fields_omitted(&mut self, omit: FxHashSet<IStr>) {1003 self.commit();1004 self.sup.push(CcObjectCore::new(OmitFieldsCore { omit }));1005 }10061007 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 }9741090985 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()),crates/jrsonnet-stdlib/src/manifest/xml.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/manifest/xml.rs
+++ b/crates/jrsonnet-stdlib/src/manifest/xml.rs
@@ -62,10 +62,10 @@
if let Val::Obj(attrs) = maybe_attrs {
(true, attrs)
} else {
- (false, ObjValue::new_empty())
+ (false, ObjValue::empty())
}
} else {
- (false, ObjValue::new_empty())
+ (false, ObjValue::empty())
};
Ok(Self::Tag {
tag,
crates/jrsonnet-stdlib/src/misc.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/misc.rs
+++ b/crates/jrsonnet-stdlib/src/misc.rs
@@ -172,7 +172,7 @@
let Some(patch) = patch.as_obj() else {
return Ok(patch);
};
- let target = target.as_obj().unwrap_or_else(|| ObjValue::new_empty());
+ let target = target.as_obj().unwrap_or_else(|| ObjValue::empty());
let target_fields = target
.fields(
// FIXME: Makes no sense to preserve order for BTreeSet, it would be better to use IndexSet here?
crates/jrsonnet-stdlib/src/objects.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/objects.rs
+++ b/crates/jrsonnet-stdlib/src/objects.rs
@@ -1,8 +1,9 @@
use jrsonnet_evaluator::{
function::builtin,
+ gc::WithCapacityExt,
rustc_hash::FxHashSet,
val::{ArrValue, Val},
- IStr, MaybeUnbound, ObjValue, ObjValueBuilder, Thunk,
+ IStr, ObjValue, ObjValueBuilder,
};
#[builtin]
@@ -156,43 +157,11 @@
}
#[builtin]
-pub fn builtin_object_remove_key(
- obj: ObjValue,
- key: IStr,
-
- // Standard implementation uses std.objectFields without such argument, we can't
- // assume order preservation should always be enabled/disabled
- #[default(false)]
- #[cfg(feature = "exp-preserve-order")]
- preserve_order: bool,
-) -> ObjValue {
- let mut new_obj = ObjValueBuilder::with_capacity(obj.len() - 1);
- let all_fields = obj.fields_ex(
- true,
- #[cfg(feature = "exp-preserve-order")]
- preserve_order,
- );
- let visible_fields = obj
- .fields_ex(
- false,
- #[cfg(feature = "exp-preserve-order")]
- preserve_order,
- )
- .into_iter()
- .collect::<FxHashSet<_>>();
-
- for field in &all_fields {
- if *field == key {
- continue;
- }
- let mut b = new_obj.field(field.clone());
- if !visible_fields.contains(&field) {
- b = b.hide();
- }
- let _ = b.binding(MaybeUnbound::Bound(Thunk::result(
- obj.get(field.clone()).transpose().expect("field exists"),
- )));
- }
+pub fn builtin_object_remove_key(obj: ObjValue, key: IStr) -> ObjValue {
+ let mut omit = FxHashSet::with_capacity(1);
+ omit.insert(key);
- new_obj.build()
+ let mut out = ObjValueBuilder::new();
+ out.with_super(obj).with_fields_omitted(omit);
+ out.build()
}
tests/tests/as_native.rsdiffbeforeafterboth--- a/tests/tests/as_native.rs
+++ b/tests/tests/as_native.rs
@@ -1,4 +1,4 @@
-use jrsonnet_evaluator::{trace::PathResolver, FileImportResolver, Result, State};
+use jrsonnet_evaluator::{FileImportResolver, Result, State, trace::PathResolver};
use jrsonnet_stdlib::ContextInitializer;
mod common;
tests/tests/builtin.rsdiffbeforeafterboth--- a/tests/tests/builtin.rs
+++ b/tests/tests/builtin.rs
@@ -1,11 +1,11 @@
mod common;
use jrsonnet_evaluator::{
- function::{builtin, builtin::Builtin, CallLocation, FuncVal},
+ ContextBuilder, ContextInitializer, FileImportResolver, Result, State, Thunk, Val,
+ function::{CallLocation, FuncVal, builtin, builtin::Builtin},
parser::Source,
trace::PathResolver,
typed::Typed,
- ContextBuilder, ContextInitializer, FileImportResolver, Result, State, Thunk, Val,
};
use jrsonnet_gcmodule::Trace;
use jrsonnet_stdlib::ContextInitializer as StdContextInitializer;
@@ -18,11 +18,8 @@
#[test]
fn basic_function() -> Result<()> {
let a: a = a {};
- let v = u32::from_untyped(a.call(
- ContextBuilder::new().build(),
- CallLocation::native(),
- &(),
- )?)?;
+ let v =
+ u32::from_untyped(a.call(ContextBuilder::new().build(), CallLocation::native(), &())?)?;
ensure_eq!(v, 1);
Ok(())
tests/tests/common.rsdiffbeforeafterboth--- a/tests/tests/common.rs
+++ b/tests/tests/common.rs
@@ -1,8 +1,8 @@
use jrsonnet_evaluator::{
+ ContextBuilder, ContextInitializer as ContextInitializerT, ObjValueBuilder, Result, Thunk, Val,
bail,
- function::{builtin, FuncVal},
+ function::{FuncVal, builtin},
parser::Source,
- ContextBuilder, ContextInitializer as ContextInitializerT, ObjValueBuilder, Result, Thunk, Val,
};
use jrsonnet_gcmodule::Trace;
tests/tests/golden.rsdiffbeforeafterboth--- a/tests/tests/golden.rs
+++ b/tests/tests/golden.rs
@@ -4,9 +4,9 @@
};
use jrsonnet_evaluator::{
+ FileImportResolver, State,
manifest::JsonFormat,
trace::{CompactFormat, PathResolver, TraceFormat},
- FileImportResolver, State,
};
use jrsonnet_stdlib::ContextInitializer;
mod common;
tests/tests/sanity.rsdiffbeforeafterboth--- a/tests/tests/sanity.rs
+++ b/tests/tests/sanity.rs
@@ -1,7 +1,6 @@
use jrsonnet_evaluator::{
- bail,
+ FileImportResolver, Result, State, Val, bail,
trace::{CompactFormat, PathResolver, TraceFormat},
- FileImportResolver, Result, State, Val,
};
use jrsonnet_stdlib::ContextInitializer;
tests/tests/std_native.rsdiffbeforeafterboth--- a/tests/tests/std_native.rs
+++ b/tests/tests/std_native.rs
@@ -1,4 +1,4 @@
-use jrsonnet_evaluator::{function::builtin, trace::PathResolver, State};
+use jrsonnet_evaluator::{State, function::builtin, trace::PathResolver};
use jrsonnet_stdlib::ContextInitializer;
#[builtin]
@@ -14,9 +14,11 @@
state.context_initializer(std);
let state = state.build();
- assert!(state
- .evaluate_snippet("test", "std.native('example')(1, 3) == 4")
- .unwrap()
- .as_bool()
- .expect("boolean output"));
+ assert!(
+ state
+ .evaluate_snippet("test", "std.native('example')(1, 3) == 4")
+ .unwrap()
+ .as_bool()
+ .expect("boolean output")
+ );
}
tests/tests/suite.rsdiffbeforeafterboth--- a/tests/tests/suite.rs
+++ b/tests/tests/suite.rs
@@ -4,8 +4,8 @@
};
use jrsonnet_evaluator::{
+ FileImportResolver, State, Val,
trace::{CompactFormat, PathResolver, TraceFormat},
- FileImportResolver, State, Val,
};
use jrsonnet_stdlib::ContextInitializer;
tests/tests/typed_obj.rsdiffbeforeafterboth--- a/tests/tests/typed_obj.rs
+++ b/tests/tests/typed_obj.rs
@@ -2,7 +2,7 @@
use std::fmt::Debug;
-use jrsonnet_evaluator::{trace::PathResolver, typed::Typed, Result, State};
+use jrsonnet_evaluator::{Result, State, trace::PathResolver, typed::Typed};
use jrsonnet_stdlib::ContextInitializer;
#[derive(Clone, Typed, PartialEq, Debug)]