Skip to content

Commit

Permalink
perf: move mergePatch to native
Browse files Browse the repository at this point in the history
  • Loading branch information
CertainLach committed May 19, 2024
1 parent c3e02c6 commit ec89bf2
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 27 deletions.
2 changes: 1 addition & 1 deletion crates/jrsonnet-evaluator/src/stdlib/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
1 change: 1 addition & 0 deletions crates/jrsonnet-stdlib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ pub fn stdlib_uncached(settings: Rc<RefCell<Settings>>) -> 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),
Expand Down
34 changes: 32 additions & 2 deletions crates/jrsonnet-stdlib/src/misc.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{cell::RefCell, rc::Rc};
use std::{cell::RefCell, collections::BTreeSet, rc::Rc};

use jrsonnet_evaluator::{
bail,
Expand All @@ -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};
Expand Down Expand Up @@ -152,3 +152,33 @@ pub fn builtin_assert_equal(a: Val, b: Val) -> Result<bool> {
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())
}
24 changes: 0 additions & 24 deletions crates/jrsonnet-stdlib/src/std.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -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]),
Expand Down

0 comments on commit ec89bf2

Please sign in to comment.