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

difftreelog

feat allow iteration over objects in comprehensions

Yaroslav Bolyukin2022-11-09parent: #1b7795b.patch.diff
in: master
exp-object-iteration feature

3 files changed

modifiedcmds/jrsonnet/Cargo.tomldiffbeforeafterboth
before · cmds/jrsonnet/Cargo.toml
1[package]2name = "jrsonnet"3description = "Rust jsonnet implementation"4version.workspace = true5authors = ["Yaroslav Bolyukin <iam@lach.pw>"]6license = "MIT"7edition = "2021"89[features]10experimental = ["exp-preserve-order", "exp-destruct"]11# Use mimalloc as allocator12mimalloc = ["mimallocator"]13# Experimental feature, which allows to preserve order of object fields14exp-preserve-order = [15    "jrsonnet-evaluator/exp-preserve-order",16    "jrsonnet-cli/exp-preserve-order",17]18# Destructuring of locals19exp-destruct = ["jrsonnet-evaluator/exp-destruct"]20# std.thisFile support21legacy-this-file = ["jrsonnet-cli/legacy-this-file"]2223[dependencies]24jrsonnet-evaluator.workspace = true25jrsonnet-parser.workspace = true26jrsonnet-cli.workspace = true27jrsonnet-gcmodule = { version = "0.3.4" }2829mimallocator = { version = "0.1.3", optional = true }30thiserror = "1.0"31clap = { version = "4.0", features = ["derive"] }32clap_complete = { version = "4.0" }
after · cmds/jrsonnet/Cargo.toml
1[package]2name = "jrsonnet"3description = "Rust jsonnet implementation"4version.workspace = true5authors = ["Yaroslav Bolyukin <iam@lach.pw>"]6license = "MIT"7edition = "2021"89[features]10experimental = ["exp-preserve-order", "exp-destruct"]11# Use mimalloc as allocator12mimalloc = ["mimallocator"]13# Experimental feature, which allows to preserve order of object fields14exp-preserve-order = [15    "jrsonnet-evaluator/exp-preserve-order",16    "jrsonnet-cli/exp-preserve-order",17]18# Destructuring of locals19exp-destruct = ["jrsonnet-evaluator/exp-destruct"]20# Iteration over objects yields [key, value] elements21exp-object-iteration = ["jrsonnet-evaluator/exp-object-iteration"]2223# std.thisFile support24legacy-this-file = ["jrsonnet-cli/legacy-this-file"]2526[dependencies]27jrsonnet-evaluator.workspace = true28jrsonnet-parser.workspace = true29jrsonnet-cli.workspace = true30jrsonnet-gcmodule = { version = "0.3.4" }3132mimallocator = { version = "0.1.3", optional = true }33thiserror = "1.0"34clap = { version = "4.0", features = ["derive"] }35clap_complete = { version = "4.0" }
modifiedcrates/jrsonnet-evaluator/Cargo.tomldiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/Cargo.toml
+++ b/crates/jrsonnet-evaluator/Cargo.toml
@@ -20,6 +20,9 @@
 exp-preserve-order = []
 # Implements field destructuring
 exp-destruct = ["jrsonnet-parser/exp-destruct"]
+# Iteration over objects yields [key, value] elements
+exp-object-iteration = []
+
 # Improves performance, and implements some useful things using nightly-only features
 nightly = []
 
modifiedcrates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs
@@ -66,7 +66,7 @@
 			Val::Arr(list) => {
 				for item in list.iter_lazy() {
 					let fctx = Pending::new();
-					let mut new_bindings = GcHashMap::new();
+					let mut new_bindings = GcHashMap::with_capacity(var.capacity_hint());
 					destruct(var, item, fctx.clone(), &mut new_bindings)?;
 					let ctx = ctx
 						.clone()
@@ -76,6 +76,46 @@
 					evaluate_comp(ctx, &specs[1..], callback)?;
 				}
 			}
+			#[cfg(feature = "exp-object-iteration")]
+			Val::Obj(obj) => {
+				for field in obj.fields(
+					// TODO: Should there be ability to preserve iteration order?
+					#[cfg(feature = "exp-preserve-order")]
+					false,
+				) {
+					#[derive(Trace)]
+					struct ObjectFieldThunk {
+						obj: ObjValue,
+						field: IStr,
+					}
+					impl ThunkValue for ObjectFieldThunk {
+						type Output = Val;
+
+						fn get(self: Box<Self>) -> Result<Self::Output> {
+							self.obj.get(self.field).transpose().expect(
+								"field exists, as field name was obtained from object.fields()",
+							)
+						}
+					}
+
+					let fctx = Pending::new();
+					let mut new_bindings = GcHashMap::with_capacity(var.capacity_hint());
+					let value = Thunk::evaluated(Val::Arr(ArrValue::Lazy(Cc::new(vec![
+						Thunk::evaluated(Val::Str(field.clone())),
+						Thunk::new(tb!(ObjectFieldThunk {
+							field: field.clone(),
+							obj: obj.clone(),
+						})),
+					]))));
+					destruct(var, value, fctx.clone(), &mut new_bindings)?;
+					let ctx = ctx
+						.clone()
+						.extend(new_bindings, None, None, None)
+						.into_future(fctx);
+
+					evaluate_comp(ctx, &specs[1..], callback)?;
+				}
+			}
 			_ => throw!(InComprehensionCanOnlyIterateOverArray),
 		},
 	}
@@ -99,7 +139,8 @@
 
 		fn bind(&self, sup: Option<ObjValue>, this: Option<ObjValue>) -> Result<Context> {
 			let fctx = Context::new_future();
-			let mut new_bindings = GcHashMap::new();
+			let mut new_bindings =
+				GcHashMap::with_capacity(self.locals.iter().map(BindSpec::capacity_hint).sum());
 			for b in self.locals.iter() {
 				evaluate_dest(b, fctx.clone(), &mut new_bindings)?;
 			}
@@ -446,7 +487,7 @@
 		},
 		LocalExpr(bindings, returned) => {
 			let mut new_bindings: GcHashMap<IStr, Thunk<Val>> =
-				GcHashMap::with_capacity(bindings.len());
+				GcHashMap::with_capacity(bindings.iter().map(BindSpec::capacity_hint).sum());
 			let fctx = Context::new_future();
 			for b in bindings {
 				evaluate_dest(b, fctx.clone(), &mut new_bindings)?;