From ec89bf24a63fa89d1203979b7f10810b270f210d Mon Sep 17 00:00:00 2001 From: Yaroslav Bolyukin Date: Sun, 19 May 2024 21:29:01 +0200 Subject: [PATCH] perf: move mergePatch to native --- .../jrsonnet-evaluator/src/stdlib/format.rs | 2 +- crates/jrsonnet-stdlib/src/lib.rs | 1 + crates/jrsonnet-stdlib/src/misc.rs | 34 +++++++++++++++++-- crates/jrsonnet-stdlib/src/std.jsonnet | 24 ------------- 4 files changed, 34 insertions(+), 27 deletions(-) diff --git a/crates/jrsonnet-evaluator/src/stdlib/format.rs b/crates/jrsonnet-evaluator/src/stdlib/format.rs index a9e49f07..fb50fa1c 100644 --- a/crates/jrsonnet-evaluator/src/stdlib/format.rs +++ b/crates/jrsonnet-evaluator/src/stdlib/format.rs @@ -609,7 +609,7 @@ pub fn format_code( 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(); diff --git a/crates/jrsonnet-stdlib/src/lib.rs b/crates/jrsonnet-stdlib/src/lib.rs index c6ba5545..6adedc25 100644 --- a/crates/jrsonnet-stdlib/src/lib.rs +++ b/crates/jrsonnet-stdlib/src/lib.rs @@ -215,6 +215,7 @@ pub fn stdlib_uncached(settings: Rc>) -> ObjValue { ("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), diff --git a/crates/jrsonnet-stdlib/src/misc.rs b/crates/jrsonnet-stdlib/src/misc.rs index b4cea85a..d9a0051e 100644 --- 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 @@ use jrsonnet_evaluator::{ 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 @@ pub fn builtin_assert_equal(a: Val, b: Val) -> Result { let b = b.manifest(&format).description(" manifestification")?; bail!("assertion failed: A != B\nA: {a}\nB: {b}") } + +#[builtin] +pub fn builtin_merge_patch(target: Val, patch: Val) -> Result { + 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::>(); + let patch_fields = patch.fields().into_iter().collect::>(); + + 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()) +} diff --git a/crates/jrsonnet-stdlib/src/std.jsonnet b/crates/jrsonnet-stdlib/src/std.jsonnet index 5245b48f..bc970ed4 100644 --- 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]),