--- a/Cargo.lock +++ b/Cargo.lock @@ -163,6 +163,15 @@ checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] +name = "bitmaps" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" +dependencies = [ + "typenum", +] + +[[package]] name = "block-buffer" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -682,6 +691,20 @@ checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" [[package]] +name = "im-rc" +version = "15.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1955a75fa080c677d3972822ec4bad316169ab1cfc6c257a942c2265dbe5fe" +dependencies = [ + "bitmaps", + "rand_core 0.6.4", + "rand_xoshiro", + "sized-chunks", + "typenum", + "version_check", +] + +[[package]] name = "indexmap" version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -793,6 +816,7 @@ "anyhow", "educe", "hi-doc", + "im-rc", "jrsonnet-gcmodule", "jrsonnet-interner", "jrsonnet-ir", @@ -837,18 +861,19 @@ [[package]] name = "jrsonnet-gcmodule" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f95b976a79e4000bb9e07ff0709dca0ea27bcf1952d4c17d91fb7364d6145683" +checksum = "8a6a63a6e55ba82764e483d7f8a181f25db95a8f25da8ae6520e95a5fe39c6a6" dependencies = [ + "im-rc", "jrsonnet-gcmodule-derive", ] [[package]] name = "jrsonnet-gcmodule-derive" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d928626220a310ff0cec815e80cf7fe104697184352ca21c40534e0b0d72d9" +checksum = "095fe3c4c0acf32de80205a8a479ef63c216b9efb0024dec9eb7fe1c5ef1f1a1" dependencies = [ "proc-macro2", "quote", @@ -1319,7 +1344,7 @@ checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha", - "rand_core", + "rand_core 0.9.5", ] [[package]] @@ -1329,11 +1354,17 @@ checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.9.5", ] [[package]] name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "rand_core" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" @@ -1342,6 +1373,15 @@ ] [[package]] +name = "rand_xoshiro" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] name = "random_color" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1587,6 +1627,16 @@ checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" [[package]] +name = "sized-chunks" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" +dependencies = [ + "bitmaps", + "typenum", +] + +[[package]] name = "smallvec" version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ jrsonnet-cli = { path = "./crates/jrsonnet-cli", version = "0.5.0-pre98" } jrsonnet-types = { path = "./crates/jrsonnet-types", version = "0.5.0-pre98" } jrsonnet-formatter = { path = "./crates/jrsonnet-formatter", version = "0.5.0-pre98" } -jrsonnet-gcmodule = { version = "0.4.2" } +jrsonnet-gcmodule = { version = "0.4.3", features = ["im-rc"] } # Diagnostics. # hi-doc is my library, which handles text formatting very well, but isn't polished enough yet # Previous implementation was based on annotate-snippets, which I don't like for many reasons. --- a/crates/jrsonnet-evaluator/Cargo.toml +++ b/crates/jrsonnet-evaluator/Cargo.toml @@ -76,6 +76,7 @@ "Hash", "PartialEq", ] } +im-rc = "15.1.0" [build-dependencies] rustversion = "1.0.22" --- a/crates/jrsonnet-evaluator/src/evaluate/destructure.rs +++ b/crates/jrsonnet-evaluator/src/evaluate/destructure.rs @@ -144,9 +144,7 @@ Thunk!(move || { let full = full.evaluate()?; let mut builder = ObjValueBuilder::new(); - builder - .reserve_cores(1) - .extend_with_core(full.as_standalone()); + builder.extend_with_core(full.as_standalone()); builder.with_fields_omitted(captured_fields); Ok(Val::Obj(builder.build())) }), --- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs +++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs @@ -410,7 +410,7 @@ let locals = obj.locals.clone(); evaluate_comp(ctx, &obj.compspecs, 0, &mut |ctx, reserve| { let uctx = evaluate_object_locals(ctx.clone(), locals.clone()); - builder.reserve_cores(reserve); + builder.reserve_fields(reserve); evaluate_field_member(&mut builder, ctx, uctx, &obj.field) })?; --- a/crates/jrsonnet-evaluator/src/obj/mod.rs +++ b/crates/jrsonnet-evaluator/src/obj/mod.rs @@ -11,6 +11,7 @@ }; use educe::Educe; +use im_rc::{Vector, vector}; use jrsonnet_gcmodule::{Acyclic, Cc, Trace, Weak, cc_dyn}; use jrsonnet_interner::IStr; use jrsonnet_ir::Span; @@ -235,10 +236,11 @@ CcObjectCore, ObjectCore, pub fn new() {...} ); + #[derive(Trace, Educe)] #[educe(Debug)] struct ObjValueInner { - cores: Vec, + cores: Vector, assertions_ran: Cell, has_assertions: bool, value_cache: RefCell>, @@ -266,7 +268,7 @@ thread_local! { static EMPTY_OBJ: ObjValue = ObjValue(Cc::new(ObjValueInner { - cores: vec![], + cores: vector![], assertions_ran: Cell::new(true), has_assertions: false, value_cache: RefCell::default(), @@ -428,7 +430,7 @@ bail!(NoSuperFound) } let mut out = ObjValue::builder(); - out.reserve_cores(1).extend_with_core(StandaloneSuperCore { + out.extend_with_core(StandaloneSuperCore { sup: self.sup, this: self.this.clone(), }); @@ -484,9 +486,7 @@ #[must_use] pub fn extend_from(&self, sup: Self) -> Self { - let mut cores = Vec::with_capacity(sup.0.cores.len() + self.0.cores.len()); - cores.extend(sup.0.cores.iter().cloned()); - cores.extend(self.0.cores.iter().cloned()); + let cores = sup.0.cores.clone() + self.0.cores.clone(); let has_assertions = sup.0.has_assertions || self.0.has_assertions; ObjValue(Cc::new(ObjValueInner { cores, @@ -521,13 +521,27 @@ }, ) } + + fn iter_cores(&self, idx: CoreIdx) -> impl Iterator { + self.0.cores.iter().take(idx.idx).rev() + } + fn iter_cores_enumerate(&self, idx: CoreIdx) -> impl Iterator { + self.0 + .cores + .iter() + .take(idx.idx) + .enumerate() + .rev() + .map(|(idx, o)| (CoreIdx { idx }, o)) + } + fn enum_fields_idx( &self, super_depth: &mut SuperDepth, handler: &mut EnumFieldsHandler<'_>, idx: CoreIdx, ) -> bool { - for core in self.0.cores[..idx.idx].iter().rev() { + for core in self.iter_cores(idx) { if !core.0.enum_fields_core(super_depth, handler) { return false; } @@ -546,7 +560,7 @@ } fn has_field_include_hidden_idx(&self, name: IStr, core: CoreIdx) -> bool { let mut skip = Saturating(0usize); - for ele in self.0.cores[..core.idx].iter().rev() { + for ele in self.iter_cores(core) { match ele.0.has_field_include_hidden_core(name.clone()) { HasFieldIncludeHidden::Exists => { if skip.0 == 0 { @@ -616,9 +630,9 @@ let mut first_add = None; let mut add_stack: Vec = Vec::new(); let mut skip = Saturating(0); - for (sup, core) in self.0.cores[..core.idx].iter().enumerate().rev() { + for (sup, core) in self.iter_cores_enumerate(core) { let sup_this = SupThis { - sup: CoreIdx { idx: sup }, + sup, this: self.clone(), }; match core.0.get_for_core(key.clone(), sup_this, skip.0 != 0)? { @@ -686,7 +700,7 @@ fn field_visibility_idx(&self, field: IStr, core: CoreIdx) -> Option { let mut exists = false; let mut skip = Saturating(0usize); - for ele in self.0.cores[..core.idx].iter().rev() { + for ele in self.iter_cores(core) { let vis = ele.0.field_visibility_core(field.clone()); match vis { FieldVisibility::Found(vis @ (Visibility::Unhide | Visibility::Hidden)) => { --- a/crates/jrsonnet-evaluator/src/obj/oop.rs +++ b/crates/jrsonnet-evaluator/src/obj/oop.rs @@ -4,6 +4,7 @@ ops::ControlFlow, }; +use im_rc::Vector; use jrsonnet_gcmodule::{Cc, Trace}; use jrsonnet_ir::IStr; use rustc_hash::{FxHashMap, FxHashSet}; @@ -117,7 +118,7 @@ #[allow(clippy::module_name_repetitions)] pub struct ObjValueBuilder { - sup: Vec, + sup: Vector, has_assertions: bool, new: OopObject, @@ -129,7 +130,7 @@ } pub fn with_capacity(capacity: usize) -> Self { Self { - sup: vec![], + sup: Vector::new(), has_assertions: false, new: OopObject::new(FxHashMap::with_capacity(capacity), None), next_field_index: FieldIndex::default(), @@ -137,14 +138,10 @@ } pub fn reserve_fields(&mut self, capacity: usize) { self.new.this_entries.reserve(capacity); - } - pub fn reserve_cores(&mut self, capacity: usize) -> &mut Self { - self.sup.reserve_exact(capacity); - self } pub fn with_super(&mut self, super_obj: ObjValue) -> &mut Self { self.has_assertions |= super_obj.0.has_assertions; - self.sup.clone_from(&super_obj.0.cores); + self.sup = super_obj.0.cores.clone(); self } @@ -181,19 +178,20 @@ pub fn extend_with_core(&mut self, core: impl ObjectCore) { self.commit(); - self.sup.push(CcObjectCore::new(core)); + self.sup.push_back(CcObjectCore::new(core)); } fn commit(&mut self) { if !self.new.is_empty() { - self.sup.push(CcObjectCore::new(mem::take(&mut self.new))); + self.sup + .push_back(CcObjectCore::new(mem::take(&mut self.new))); } self.next_field_index = FieldIndex::default(); } pub fn with_fields_omitted(&mut self, omit: FxHashSet) { self.commit(); - self.sup.push(CcObjectCore::new(OmitFieldsCore { + self.sup.push_back(CcObjectCore::new(OmitFieldsCore { omit, prev_layers: self.sup.len(), }));