difftreelog
perf move mergePatch to native
in: master
4 files changed
crates/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();
crates/jrsonnet-stdlib/src/lib.rsdiffbeforeafterboth215 ("startsWith", builtin_starts_with::INST),215 ("startsWith", builtin_starts_with::INST),216 ("endsWith", builtin_ends_with::INST),216 ("endsWith", builtin_ends_with::INST),217 ("assertEqual", builtin_assert_equal::INST),217 ("assertEqual", builtin_assert_equal::INST),218 ("mergePatch", builtin_merge_patch::INST),218 // Sets219 // Sets219 ("setMember", builtin_set_member::INST),220 ("setMember", builtin_set_member::INST),220 ("setInter", builtin_set_inter::INST),221 ("setInter", builtin_set_inter::INST),crates/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())
+}
crates/jrsonnet-stdlib/src/std.jsonnetdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/std.jsonnet
+++ b/crates/jrsonnet-stdlib/src/std.jsonnet
@@ -11,30 +11,6 @@
else
{ [k]: func(k, obj[k]) for k in std.objectFields(obj) },
- mergePatch(target, patch)::
- if std.isObject(patch) then
- local target_object =
- if std.isObject(target) then target else {};
-
- local target_fields =
- if std.isObject(target_object) then std.objectFields(target_object) else [];
-
- local null_fields = [k for k in std.objectFields(patch) if patch[k] == null];
- local both_fields = std.setUnion(target_fields, std.objectFields(patch));
-
- {
- [k]:
- if !std.objectHas(patch, k) then
- target_object[k]
- else if !std.objectHas(target_object, k) then
- std.mergePatch(null, patch[k]) tailstrict
- else
- std.mergePatch(target_object[k], patch[k]) tailstrict
- for k in std.setDiff(both_fields, null_fields)
- }
- else
- patch,
-
resolvePath(f, r)::
local arr = std.split(f, '/');
std.join('/', std.makeArray(std.length(arr) - 1, function(i) arr[i]) + [r]),