git.delta.rocks / jrsonnet / refs/commits / 71fb4e2830f5

difftreelog

perf move mergePatch to native

Yaroslav Bolyukin2024-06-18parent: #f009c16.patch.diff
in: master

4 files changed

modifiedcrates/jrsonnet-evaluator/src/stdlib/format.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/stdlib/format.rs
+++ b/crates/jrsonnet-evaluator/src/stdlib/format.rs
@@ -609,7 +609,7 @@
 				tmp_out.push(
 					std::char::from_u32(n as u32)
 						.ok_or_else(|| InvalidUnicodeCodepointGot(n as u32))?,
-				)
+				);
 			}
 			Val::Str(s) => {
 				let s = s.into_flat();
modifiedcrates/jrsonnet-stdlib/src/lib.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/lib.rs
+++ b/crates/jrsonnet-stdlib/src/lib.rs
@@ -215,6 +215,7 @@
 		("startsWith", builtin_starts_with::INST),
 		("endsWith", builtin_ends_with::INST),
 		("assertEqual", builtin_assert_equal::INST),
+		("mergePatch", builtin_merge_patch::INST),
 		// Sets
 		("setMember", builtin_set_member::INST),
 		("setInter", builtin_set_inter::INST),
modifiedcrates/jrsonnet-stdlib/src/misc.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/misc.rs
+++ b/crates/jrsonnet-stdlib/src/misc.rs
@@ -1,4 +1,4 @@
-use std::{cell::RefCell, rc::Rc};
+use std::{cell::RefCell, collections::BTreeSet, rc::Rc};
 
 use jrsonnet_evaluator::{
 	bail,
@@ -7,7 +7,7 @@
 	manifest::JsonFormat,
 	typed::{Either2, Either4},
 	val::{equals, ArrValue},
-	Context, Either, IStr, ObjValue, ResultExt, Thunk, Val,
+	Context, Either, IStr, ObjValue, ObjValueBuilder, ResultExt, Thunk, Val,
 };
 
 use crate::{extvar_source, Settings};
@@ -152,3 +152,33 @@
 	let b = b.manifest(&format).description("<b> manifestification")?;
 	bail!("assertion failed: A != B\nA: {a}\nB: {b}")
 }
+
+#[builtin]
+pub fn builtin_merge_patch(target: Val, patch: Val) -> Result<Val> {
+	let Some(patch) = patch.as_obj() else {
+		return Ok(patch);
+	};
+	let Some(target) = target.as_obj() else {
+		return Ok(Val::Obj(patch));
+	};
+	let target_fields = target.fields().into_iter().collect::<BTreeSet<IStr>>();
+	let patch_fields = patch.fields().into_iter().collect::<BTreeSet<IStr>>();
+
+	let mut out = ObjValueBuilder::new();
+	for field in target_fields.union(&patch_fields) {
+		let Some(field_patch) = patch.get(field.clone())? else {
+			out.field(field.clone()).value(target.get(field.clone())?.expect("we're iterating over fields union, if field is missing in patch - it exists in target"));
+			continue;
+		};
+		if matches!(field_patch, Val::Null) {
+			continue;
+		}
+		let Some(field_target) = target.get(field.clone())? else {
+			out.field(field.clone()).value(field_patch);
+			continue;
+		};
+		out.field(field.clone())
+			.value(builtin_merge_patch(field_target, field_patch)?);
+	}
+	Ok(out.build().into())
+}
modifiedcrates/jrsonnet-stdlib/src/std.jsonnetdiffbeforeafterboth
before · crates/jrsonnet-stdlib/src/std.jsonnet
1{2  local std = self,34  thisFile:: error 'std.thisFile is deprecated, to enable its support in jrsonnet - recompile it with "legacy-this-file" support.\nThis will slow down stdlib caching a bit, though',56  mapWithKey(func, obj)::7    if !std.isFunction(func) then8      error ('std.mapWithKey first param must be function, got ' + std.type(func))9    else if !std.isObject(obj) then10      error ('std.mapWithKey second param must be object, got ' + std.type(obj))11    else12      { [k]: func(k, obj[k]) for k in std.objectFields(obj) },1314  mergePatch(target, patch)::15    if std.isObject(patch) then16      local target_object =17        if std.isObject(target) then target else {};1819      local target_fields =20        if std.isObject(target_object) then std.objectFields(target_object) else [];2122      local null_fields = [k for k in std.objectFields(patch) if patch[k] == null];23      local both_fields = std.setUnion(target_fields, std.objectFields(patch));2425      {26        [k]:27          if !std.objectHas(patch, k) then28            target_object[k]29          else if !std.objectHas(target_object, k) then30            std.mergePatch(null, patch[k]) tailstrict31          else32            std.mergePatch(target_object[k], patch[k]) tailstrict33        for k in std.setDiff(both_fields, null_fields)34      }35    else36      patch,3738  resolvePath(f, r)::39    local arr = std.split(f, '/');40    std.join('/', std.makeArray(std.length(arr) - 1, function(i) arr[i]) + [r]),41}