difftreelog
feat immutable obj core list
in: master
7 files changed
Cargo.lockdiffbeforeafterboth--- 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"
Cargo.tomldiffbeforeafterboth--- 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.
crates/jrsonnet-evaluator/Cargo.tomldiffbeforeafterboth--- 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"
crates/jrsonnet-evaluator/src/evaluate/destructure.rsdiffbeforeafterboth1use std::{collections::HashMap, hash::BuildHasher};23use jrsonnet_interner::IStr;4use jrsonnet_ir::{BindSpec, Destruct};56#[cfg(feature = "exp-preserve-order")]7use crate::evaluate;8use crate::{9 Context, Pending, Thunk, Val, bail,10 error::{ErrorKind::*, Result},11 evaluate_method, evaluate_named_param,12};1314#[allow(clippy::too_many_lines)]15#[allow(unused_variables)]16pub fn destruct<H: BuildHasher>(17 d: &Destruct,18 parent: Thunk<Val>,19 fctx: Pending<Context>,20 new_bindings: &mut HashMap<IStr, Thunk<Val>, H>,21) -> Result<()> {22 match d {23 Destruct::Full(v) => {24 let old = new_bindings.insert(v.clone(), parent);25 if old.is_some() {26 bail!(DuplicateLocalVar(v.clone()))27 }28 }29 #[cfg(feature = "exp-destruct")]30 Destruct::Skip => {}31 #[cfg(feature = "exp-destruct")]32 Destruct::Array { start, rest, end } => {33 use jrsonnet_ir::DestructRest;3435 let min_len = start.len() + end.len();36 let has_rest = rest.is_some();37 let full = Thunk!(move || {38 let v = parent.evaluate()?;39 let Val::Arr(arr) = v else {40 bail!("expected array");41 };42 if !has_rest {43 if arr.len() != min_len {44 bail!("expected {} elements, got {}", min_len, arr.len())45 }46 } else if arr.len() < min_len {47 bail!(48 "expected at least {} elements, but array was only {}",49 min_len,50 arr.len()51 )52 }53 Ok(arr)54 });5556 {57 for (i, d) in start.iter().enumerate() {58 let full = full.clone();59 destruct(60 d,61 Thunk!(move || Ok(full.evaluate()?.get(i)?.expect("length is checked"))),62 fctx.clone(),63 new_bindings,64 )?;65 }66 }6768 match rest {69 Some(DestructRest::Keep(v)) => {70 let start = start.len();71 let end = end.len();72 let full = full.clone();73 destruct(74 &Destruct::Full(v.clone()),75 Thunk!(move || {76 let full = full.evaluate()?;77 let to = full.len() - end;78 Ok(Val::Arr(full.slice(79 Some(start as i32),80 Some(to as i32),81 None,82 )))83 }),84 fctx.clone(),85 new_bindings,86 )?;87 }88 Some(DestructRest::Drop) | None => {}89 }9091 {92 for (i, d) in end.iter().enumerate() {93 let full = full.clone();94 let end = end.len();95 destruct(96 d,97 Thunk!(move || {98 let full = full.evaluate()?;99 Ok(full.get(full.len() - end + i)?.expect("length is checked"))100 }),101 fctx.clone(),102 new_bindings,103 )?;104 }105 }106 }107 #[cfg(feature = "exp-destruct")]108 Destruct::Object { fields, rest } => {109 use jrsonnet_ir::DestructRest;110 use rustc_hash::FxHashSet;111112 use crate::ObjValueBuilder;113114 let captured_fields: FxHashSet<_> = fields.iter().map(|f| f.0.clone()).collect();115 let field_names: Vec<_> = fields116 .iter()117 .map(|f| (f.0.clone(), f.2.is_some()))118 .collect();119 let has_rest = rest.is_some();120 let full = Thunk!(move || {121 let v = parent.evaluate()?;122 let Val::Obj(obj) = v else {123 bail!("expected object");124 };125 for (field, has_default) in &field_names {126 if !has_default && !obj.has_field_ex(field.clone(), true) {127 bail!("missing field: {field}");128 }129 }130 if !has_rest {131 let len = obj.len();132 if len > field_names.len() {133 bail!("too many fields, and rest not found");134 }135 }136 Ok(obj)137 });138139 match rest {140 Some(DestructRest::Keep(v)) => {141 let full = full.clone();142 destruct(143 &Destruct::Full(v.clone()),144 Thunk!(move || {145 let full = full.evaluate()?;146 let mut builder = ObjValueBuilder::new();147 builder148 .reserve_cores(1)149 .extend_with_core(full.as_standalone());150 builder.with_fields_omitted(captured_fields);151 Ok(Val::Obj(builder.build()))152 }),153 fctx.clone(),154 new_bindings,155 )?;156 }157 Some(DestructRest::Drop) | None => {}158 }159160 for (field, d, default) in fields {161 let default = default.clone().map(|e| (fctx.clone(), e));162 let value = {163 let field = field.clone();164 let full = full.clone();165 Thunk!(move || {166 let full = full.evaluate()?;167 if let Some(field) = full.get(field)? {168 Ok(field)169 } else {170 let (fctx, expr) = default.as_ref().expect("shape is checked");171 Ok(crate::evaluate(fctx.clone().unwrap(), expr)?)172 }173 })174 };175176 if let Some(d) = d {177 destruct(d, value, fctx.clone(), new_bindings)?;178 } else {179 destruct(180 &Destruct::Full(field.clone()),181 value,182 fctx.clone(),183 new_bindings,184 )?;185 }186 }187 }188 }189 Ok(())190}191192pub fn evaluate_dest<H: BuildHasher>(193 d: &BindSpec,194 fctx: Pending<Context>,195 new_bindings: &mut HashMap<IStr, Thunk<Val>, H>,196) -> Result<()> {197 match d {198 BindSpec::Field { into, value } => {199 let name = into.name();200 let value = value.clone();201 let data = {202 let fctx = fctx.clone();203 Thunk!(move || evaluate_named_param(fctx.unwrap(), &value, name))204 };205 destruct(into, data, fctx, new_bindings)?;206 }207 BindSpec::Function {208 name,209 params,210 value,211 } => {212 let params = params.clone();213 let name = name.clone();214 let value = value.clone();215 let old = new_bindings.insert(name.clone(), {216 let name = name.clone();217 Thunk!(move || Ok(evaluate_method(fctx.unwrap(), name, params, value)))218 });219 if old.is_some() {220 bail!(DuplicateLocalVar(name))221 }222 }223 }224 Ok(())225}crates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth--- 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)
})?;
crates/jrsonnet-evaluator/src/obj/mod.rsdiffbeforeafterboth--- 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<CcObjectCore>,
+ cores: Vector<CcObjectCore>,
assertions_ran: Cell<bool>,
has_assertions: bool,
value_cache: RefCell<FxHashMap<(IStr, CoreIdx), CacheValue>>,
@@ -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<Item = &CcObjectCore> {
+ self.0.cores.iter().take(idx.idx).rev()
+ }
+ fn iter_cores_enumerate(&self, idx: CoreIdx) -> impl Iterator<Item = (CoreIdx, &CcObjectCore)> {
+ 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<Val> = 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<Visibility> {
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)) => {
crates/jrsonnet-evaluator/src/obj/oop.rsdiffbeforeafterboth--- 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<CcObjectCore>,
+ sup: Vector<CcObjectCore>,
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<IStr>) {
self.commit();
- self.sup.push(CcObjectCore::new(OmitFieldsCore {
+ self.sup.push_back(CcObjectCore::new(OmitFieldsCore {
omit,
prev_layers: self.sup.len(),
}));