///|
pub(all) enum PatchKind {
Set
Append
Remove
} derive(Debug, Eq)
///|
pub struct Patch {
kind : PatchKind
path : String
value_json : String
estimated_bytes : Int
} derive(Debug, Eq)
///|
pub struct PatchBudget {
max_patches : Int
max_patch_bytes : Int
} derive(Debug, Eq)
///|
pub struct PatchPlan {
patches : Array[Patch]
total_estimated_bytes : Int
diagnostics : Array[String]
summary : String
} derive(Debug, Eq)
///|
pub fn patch_budget(max_patches~ : Int, max_patch_bytes~ : Int) -> PatchBudget {
{ max_patches, max_patch_bytes }
}
///|
pub fn default_patch_budget() -> PatchBudget {
{ max_patches: 64, max_patch_bytes: 8192 }
}
///|
pub fn set_json(path : String, value_json : String) -> Patch {
patch(kind=Set, path~, value_json~)
}
///|
pub fn set_string(path : String, value : String) -> Patch {
set_json(path, "\"\{escape_json(value)}\"")
}
///|
pub fn append_json(path : String, value_json : String) -> Patch {
patch(kind=Append, path~, value_json~)
}
///|
pub fn remove_path(path : String) -> Patch {
patch(kind=Remove, path~, value_json="null")
}
///|
pub fn plan_patches(patches : Array[Patch]) -> PatchPlan {
plan_patches_with_budget(patches, default_patch_budget())
}
///|
pub fn plan_patches_with_budget(
patches : Array[Patch],
budget : PatchBudget,
) -> PatchPlan {
let diagnostics : Array[String] = []
let mut total = 0
for item in patches {
total += item.estimated_bytes
}
if patches.length() > budget.max_patches {
diagnostics.push(
"patch-count-over-budget:\{patches.length()}/\{budget.max_patches}",
)
}
if total > budget.max_patch_bytes {
diagnostics.push(
"patch-bytes-over-budget:\{total}/\{budget.max_patch_bytes}",
)
}
{
patches,
total_estimated_bytes: total,
diagnostics,
summary: "Bunnia patch plan: patches=\{patches.length()} bytes=\{total} diagnostics=\{diagnostics.length()}",
}
}
///|
fn patch(kind~ : PatchKind, path~ : String, value_json~ : String) -> Patch {
{
kind,
path,
value_json,
estimated_bytes: path.length() + value_json.length(),
}
}
///|
fn escape_json(value : String) -> String {
value
.replace(old="\\", new="\\\\")
.replace(old="\"", new="\\\"")
.replace(old="\n", new="\\n")
.to_string()
}