aboutsummaryrefslogtreecommitdiffstats
path: root/core/module-save.c
diff options
context:
space:
mode:
authoreunhhu <[email protected]>2026-10-19 04:42:05 +0100
committereunhhu <[email protected]>2026-10-19 04:42:05 +0100
commit6596533b0d5fe10f3cab028d7fa69a40e5416ecd (patch)
tree9c5a64858ac749d892e673b7aab04928cd3bbe60 /core/module-save.c
parent5a2292a389989b71b99ea582cf306cf1719d8aae (diff)
downloadpure-6596533b0d5fe10f3cab028d7fa69a40e5416ecd.tar.gz
pure-6596533b0d5fe10f3cab028d7fa69a40e5416ecd.zip
028's bytes alone as a state, made: module state type 6 read as a text state flagged PURE_TEXT_BYTES in state_flags (so serve's same_states compares it for queries and replaces), its TEXT_LOAD giving bytes and its TEXT_SET taking them, a cursor's ops on it refused (anchor in bytes) and an anchor in it refused at load; one store file text-NAME, the values record marking each bytes state (kind 7, its name, 8 zero bytes), a text state's file that is no UTF-8 its initial value when marked and store_error when not (as before); a replace carrying bytes to a text only when its draft is UTF-8, else opening the store's draft anew; pure-run shows a bytes state's hex; unit test bytes_states (seven starts from a store: 0xff and 0x00 kept, bytes to text to bytes to text with no UTF-8 and with it; three replaces; four refused); counts: b47 against b46 BFS with batches +0.12%, the rest within 0.001%; the bank's queries (s45 and s47 in turns, six each, bytes compared among them) in_credit -0.31%, per_branch -0.18%, ranks -0.11%, the rest within 0.01%, the seven answers the same bytes; Pure, Vega and aup checks green; 008, 028
Diffstat (limited to 'core/module-save.c')
-rw-r--r--core/module-save.c55
1 files changed, 43 insertions, 12 deletions
diff --git a/core/module-save.c b/core/module-save.c
index 1055b4f..6e204d1 100644
--- a/core/module-save.c
+++ b/core/module-save.c
@@ -131,25 +131,54 @@ PURE_COLD static bool named(const unsigned char *bytes, size_t size, size_t *at,
return true;
}
-PURE_COLD PureResult pure_save_open_text(PureApp *app, const PureModule *m, uint32_t state, PureDraft **out,
+/* A bytes state's mark among the values (028): its kind past every state type, its name, 8 bytes of 0. A text state's
+ * stored bytes that are no UTF-8 are then a move from bytes (its initial value), not a store gone wrong. */
+enum { SAVED_BYTES = 7 };
+static bool bytes_state(const PureModule *m, uint32_t i) {
+ return m->state_type[i] == PURE_STATE_TEXT && m->state_flags[i] & PURE_TEXT_BYTES;
+}
+
+/* Whether the values record marks the state of that name as bytes (028). */
+PURE_COLD static bool marked_bytes(PureApp *app, const char *name) {
+ if (!app->stored_values && open_state(app, "", "values", &app->stored_values) != PURE_OK) return false;
+ unsigned char *bytes;
+ size_t size;
+ if (!pure_draft_revision(app->stored_values) || read_whole(app->stored_values, &bytes, &size) != PURE_OK) return false;
+ bool found = false, ok = size >= 4 && !memcmp(bytes, values_magic, 4);
+ for (size_t at = 4; ok && !found && at < size; at += 8) {
+ char entry[PURE_MODULE_NAME];
+ uint8_t type;
+ if (!(ok = named(bytes, size, &at, 8, &type, entry))) break;
+ found = type == SAVED_BYTES && !strcmp(entry, name);
+ }
+ free(bytes);
+ return found;
+}
+
+PURE_COLD PureResult pure_save_open_text(PureApp *app, const PureModule *m, uint32_t state, bool anew, PureDraft **out,
PureVersion *saved) {
PureResult result = open_state(app, "text-", m->state_names[state], out);
if (result != PURE_OK) return result;
*saved = pure_draft_version(*out);
- if (!pure_draft_revision(*out)) {
- uint32_t constant = m->state_ref[state];
- PureSpan initial = {m->constant_data + m->constant_offset[constant], m->constant_length[constant]};
- result = pure_draft_splice(*out, 0, pure_draft_size(*out), initial);
- *saved = unsaved;
- } else {
+ bool initial = anew || !pure_draft_revision(*out);
+ if (!initial && !bytes_state(m, state)) { /* a text's bytes are UTF-8, or a bytes state's were (a move: anew) */
unsigned char *bytes;
size_t size;
result = read_whole(*out, &bytes, &size);
if (result == PURE_OK) {
- if (!pure_utf8_valid((PureSpan){bytes, size})) result = PURE_STORE_ERROR;
+ if (!pure_utf8_valid((PureSpan){bytes, size})) {
+ if (marked_bytes(app, m->state_names[state])) initial = true;
+ else result = PURE_STORE_ERROR;
+ }
free(bytes);
}
}
+ if (result == PURE_OK && initial) {
+ uint32_t constant = m->state_ref[state];
+ PureSpan value = {m->constant_data + m->constant_offset[constant], m->constant_length[constant]};
+ result = pure_draft_splice(*out, 0, pure_draft_size(*out), value);
+ *saved = unsaved;
+ }
if (result != PURE_OK) { pure_draft_close(*out); *out = NULL; }
return result;
}
@@ -789,11 +818,11 @@ static size_t encode_values(const PureModule *m, const PureValue *values, unsign
size_t at = 4;
memcpy(out, values_magic, 4);
for (uint32_t i = 0; i < m->states; ++i) {
- if (!scalar(m->state_type[i]) || pure_state_transient(m, i)) continue;
+ if ((!scalar(m->state_type[i]) && !bytes_state(m, i)) || pure_state_transient(m, i)) continue;
size_t length = strlen(m->state_names[i]);
- uint64_t bits;
- memcpy(&bits, &values[i], sizeof(bits));
- out[at++] = m->state_type[i];
+ uint64_t bits = 0;
+ if (!bytes_state(m, i)) memcpy(&bits, &values[i], sizeof(bits));
+ out[at++] = bytes_state(m, i) ? (unsigned char)SAVED_BYTES : m->state_type[i];
out[at++] = (unsigned char)length;
memcpy(out + at, m->state_names[i], length);
at += length;
@@ -813,6 +842,8 @@ PURE_COLD PureResult pure_save_open_values(PureApp *app, const PureModule *m, Pu
if (scalar(m->state_type[i]) && !pure_state_transient(m, i)) {
scalars = true;
fresh = fresh || kept[i] < 0;
+ } else if (bytes_state(m, i) && !pure_state_transient(m, i)) {
+ scalars = true; /* its mark is among the values */
}
if (!scalars) return PURE_OK;
PureResult result = app->stored_values ? PURE_OK : open_state(app, "", "values", &app->stored_values);