feat(packages): ludic.save - versioned save files generic over their content: a version in the file, the steps a game declares into an open registry, a torn write told from a whole one, a backup of only a whole file, a write read back, a newer file refused and read-only

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-25 08:28:30 +03:00
parent b24c523fa4
commit 47ba3d9028
11 changed files with 450 additions and 0 deletions

View file

@ -0,0 +1,46 @@
# values.ludic - what a migration keeps doing to a parsed file, and a fingerprint of the tables a
# file stores by position (a table that moved without a version bump changes it)
# an object with one key left out - also how a test builds an older file out of a current one
export function save_strip(v: Val, key: string) -> Val {
let r = value_object()
for i in 0 .. value_count(v) {
let k: pointer = value_key_at(v, i)
if k == key { continue }
value_put(r, k, value_at(v, i))
}
return r
}
# a copy of a list of ints with one slot replaced
export function save_list_with(l: Val, slot: int, n: int) -> Val {
let r = value_list()
for i in 0 .. value_count(l) {
var x = value_as_int(value_at(l, i))
if i == slot { x = n }
value_add(r, value_int(x))
}
return r
}
# a copy of a list of ints with one slot taken out (an entry deleted from a table stored by position)
export function save_list_without(l: Val, slot: int) -> Val {
let r = value_list()
for i in 0 .. value_count(l) { if i != slot { value_add(r, value_int(value_as_int(value_at(l, i)))) } }
return r
}
export function save_int(v: Val, key: string, fallback: int) -> int {
if v == null or value_has(v, key) == 0 { return fallback }
return value_as_int(value_get(v, key))
}
# A fold, small and stable: a change anywhere in what is folded moves it. Fold the names of every
# table stored by position, in order, and compare with the number the last release wrote.
export function save_fold(h0: int, s: string) -> int {
var h = h0
for i in 0 .. len(s) { h = (h * 131 + s[i]) % 1000003 }
return h
}
export function save_fold_int(h0: int, n: int) -> int { return (h0 * 131 + n) % 1000003 }