difftreelog
feat allow iteration over objects in comprehensions
in: master
exp-object-iteration feature
3 files changed
cmds/jrsonnet/Cargo.tomldiffbeforeafterboth--- a/cmds/jrsonnet/Cargo.toml
+++ b/cmds/jrsonnet/Cargo.toml
@@ -17,6 +17,9 @@
]
# Destructuring of locals
exp-destruct = ["jrsonnet-evaluator/exp-destruct"]
+# Iteration over objects yields [key, value] elements
+exp-object-iteration = ["jrsonnet-evaluator/exp-object-iteration"]
+
# std.thisFile support
legacy-this-file = ["jrsonnet-cli/legacy-this-file"]
crates/jrsonnet-evaluator/Cargo.tomldiffbeforeafterboth20exp-preserve-order = []20exp-preserve-order = []21# Implements field destructuring21# Implements field destructuring22exp-destruct = ["jrsonnet-parser/exp-destruct"]22exp-destruct = ["jrsonnet-parser/exp-destruct"]23# Iteration over objects yields [key, value] elements24exp-object-iteration = []2523# Improves performance, and implements some useful things using nightly-only features26# Improves performance, and implements some useful things using nightly-only features24nightly = []27nightly = []crates/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)?;