From 6596533b0d5fe10f3cab028d7fa69a40e5416ecd Mon Sep 17 00:00:00 2001 From: eunhhu Date: Mon, 19 Oct 2026 04:42:05 +0100 Subject: 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 --- core/test-module.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) (limited to 'core/test-module.c') diff --git a/core/test-module.c b/core/test-module.c index 8795bf8..9762c48 100644 --- a/core/test-module.c +++ b/core/test-module.c @@ -102,7 +102,9 @@ static unsigned char *put_double(unsigned char *p, double value) { * module has their anchor (027's 4c), its type 2, and its instructions, which name the text or list (bits 0-15 of a * MOVE's and a COUNT's argument: IN), so a test gives that where a step does not name it. */ #define IN(target, unit) ((uint32_t)(target) | (uint32_t)(unit) << PURE_ANCHOR_UNIT) +#define T_BYTES_STATE 64 /* in a T's type: a bytes state (028), ref its constant as a text's */ static uint32_t module_type(uint32_t type) { + if (type == T_BYTES_STATE) return PURE_MODULE_BYTES; static const uint8_t types[] = {[PURE_STATE_NUM] = PURE_MODULE_NUM, [PURE_STATE_TEXT] = PURE_MODULE_TEXT, [PURE_STATE_CURSOR] = PURE_MODULE_ANCHOR, [PURE_STATE_LIST] = PURE_MODULE_LIST, [PURE_STATE_INDEX] = PURE_MODULE_ANCHOR, [PURE_STATE_BOOL] = PURE_MODULE_BOOL, @@ -6164,6 +6166,109 @@ static void bits_and_bytes(void) { printf("{\"bits_and_bytes\":{\"bits\":%zu,\"reads\":%zu,\"refused\":%zu}}\n", LEN(cases), LEN(reads), LEN(refused)); } +/* ---- Bytes alone as a state (docs/design/028) ---------------------------- + * A bytes state is held as a text is (one draft) and read and set whole as + * bytes, UTF-8 asked of none of it: 0xff and 0x00 kept across a restart. + * Text and bytes of a name carry over each other when exact, on a replace + * and on a start from a store: a text always, bytes when UTF-8, else the + * initial value (the values record marks a bytes state, so a text's bytes + * that are no UTF-8 are a move, not a store gone wrong). Refused: an anchor + * in it, a cursor's op on it, a text set into it, its bytes into a text. */ +typedef struct { unsigned char *at; size_t used; } Gathered64; +static bool gathered64(void *context, PureSpan span) { + Gathered64 *g = context; + if (g->used + span.size > 64) return false; + if (span.size) memcpy(g->at + g->used, span.data, span.size); + g->used += span.size; + return true; +} +static size_t draft_bytes(const PureApp *app, uint32_t state, unsigned char *out) { + Gathered64 g = {out, 0}; + return pure_draft_read(app->texts[state], 0, pure_draft_size(app->texts[state]), gathered64, &g) == PURE_OK ? g.used + : (size_t)-1; +} + +static void bytes_states(void) { + enum { TS = PURE_OP_TEXT_SET, CAT_ = PURE_OP_CONCAT, BYTE_ = PURE_OP_BYTE, LEN_ = PURE_OP_LEN, CH = PURE_OP_CHARS }; + static const S nums[] = {{"n", 0}}; + static const char *const constants[] = {"Az\xc3\xa9", ""}; + static const I inputs[] = {KEY("go", "KeyG"), KEY("set", "KeyS")}; + static const H handlers[] = {{1, 0, 11}, {3, 11, 6}}, text_handlers[] = {{1, 0, 3}, {3, 3, 5}}; + /* As bytes: go appends ff 00 (n its length), set gives it "Az\xc3\xa9"'s bytes. */ + const O as_bytes[] = {{TL, 1, 0}, IC(0xFF), {BYTE_, 0, 0}, {CAT_, 1, 0}, IC(0), {BYTE_, 0, 0}, {CAT_, 1, 0}, {TS, 1, 0}, + {TL, 1, 0}, {LEN_, 0, 0}, {ST, 0, 0}, + {TK, 0, 0}, {PURE_OP_BYTES_FROM, 0, 0}, {TS, 1, 0}, {TL, 1, 0}, {LEN_, 0, 0}, {ST, 0, 0}}; + /* As a text: go counts its characters, set gives it "Az\xc3\xa9". */ + static const O as_text[] = {{TL, 1, 0}, {CH, 0, 0}, {ST, 0, 0}, {TK, 0, 0}, {TS, 1, 0}, {TL, 1, 0}, {CH, 0, 0}, {ST, 0, 0}}; + static const T bytes_state[] = {{"data", T_BYTES_STATE, 1}}, text_state[] = {{"data", 1, 1}}; + Spec bytes_spec = {nums, 1, inputs, 2, NULL, 0, handlers, 2, as_bytes, LEN(as_bytes), NULL, 0, bytes_state, 1, constants, + 2, NULL, 0, NULL, 0, NULL, 0}; + Spec text_spec = {nums, 1, inputs, 2, NULL, 0, text_handlers, 2, as_text, LEN(as_text), NULL, 0, text_state, 1, constants, + 2, NULL, 0, NULL, 0, NULL, 0}; + static PureModule bytes_module, text_module; + if (load(bytes_spec, &bytes_module) != PURE_OK) { fprintf(stderr, "%s\n", error); abort(); } + if (load(text_spec, &text_module) != PURE_OK) { fprintf(stderr, "%s\n", error); abort(); } + CHECK(bytes_module.state_type[1] == PURE_STATE_TEXT && bytes_module.state_flags[1] & PURE_TEXT_BYTES && + !(text_module.state_flags[1] & PURE_TEXT_BYTES)); + unsigned char got[64]; + static const unsigned char twice[] = {0xFF, 0, 0xFF, 0}, word[] = {'A', 'z', 0xC3, 0xA9}; + /* Stored: 0xff and 0x00 kept across a restart. */ + char *path = new_store(); + PureApp app; + CHECK(pure_app_start(&app, &bytes_module, pure_tree_data(path)) == PURE_OK); + CHECK(press(&app, 0) == PURE_OK && press(&app, 0) == PURE_OK && app.values[0].num == 4); + pure_app_stop(&app); + CHECK(pure_app_start(&app, &bytes_module, pure_tree_data(path)) == PURE_OK); + CHECK(draft_bytes(&app, 1, got) == 4 && !memcmp(got, twice, 4)); + pure_app_stop(&app); + /* Bytes to a text across a start: no UTF-8, the record says bytes: its initial value (not a store gone wrong). */ + CHECK(pure_app_start(&app, &text_module, pure_tree_data(path)) == PURE_OK); + CHECK(pure_draft_size(app.texts[1]) == 0 && press(&app, 1) == PURE_OK && app.values[0].num == 3); + pure_app_stop(&app); + /* Back to bytes: the text's bytes; then ff 00 after them; then to a text again: no UTF-8 now, initial again. */ + CHECK(pure_app_start(&app, &bytes_module, pure_tree_data(path)) == PURE_OK); + CHECK(draft_bytes(&app, 1, got) == 4 && !memcmp(got, word, 4) && press(&app, 0) == PURE_OK && app.values[0].num == 6); + pure_app_stop(&app); + CHECK(pure_app_start(&app, &text_module, pure_tree_data(path)) == PURE_OK && pure_draft_size(app.texts[1]) == 0); + pure_app_stop(&app); + /* Bytes that are UTF-8 become the text. */ + CHECK(pure_app_start(&app, &bytes_module, pure_tree_data(path)) == PURE_OK && press(&app, 1) == PURE_OK); + pure_app_stop(&app); + CHECK(pure_app_start(&app, &text_module, pure_tree_data(path)) == PURE_OK); + CHECK(!strcmp(state_text(&app, 1), "Az\xc3\xa9") && press(&app, 0) == PURE_OK && app.values[0].num == 3); + pure_app_stop(&app); + remove_store(path); + /* In memory, by replace: bytes that are no UTF-8 become a new text; UTF-8 ones the text; a text the bytes. */ + CHECK(pure_app_start(&app, &bytes_module, (PureData){0}) == PURE_OK && press(&app, 0) == PURE_OK); + CHECK(pure_app_replace(&app, &text_module) == PURE_OK && pure_draft_size(app.texts[1]) == 0); + CHECK(press(&app, 1) == PURE_OK && pure_app_replace(&app, &bytes_module) == PURE_OK); + CHECK(draft_bytes(&app, 1, got) == 4 && !memcmp(got, word, 4) && press(&app, 1) == PURE_OK); + CHECK(pure_app_replace(&app, &text_module) == PURE_OK && !strcmp(state_text(&app, 1), "Az\xc3\xa9")); + pure_app_stop(&app); + /* Refused: a text set into it, its bytes into a text, a cursor's op on it, an anchor in it. */ + const O refused[][2] = { + {{TK, 0, 0}, {TS, 1, 0}}, /* a text into the bytes state */ + {{PURE_OP_CUR_START, 1, 0}, {PURE_OP_TEXT_LINE, 1, 0}}, /* a cursor of it */ + }; + for (size_t k = 0; k < LEN(refused); ++k) { + H handler = {1, 0, 2}; + Spec spec = {nums, 1, inputs, 1, NULL, 0, &handler, 1, refused[k], 2, NULL, 0, bytes_state, 1, constants, 2, NULL, 0, + NULL, 0, NULL, 0}; + if (load(spec, &module_b) == PURE_OK) { fprintf(stderr, "bytes states: refused %zu loaded\n", k); abort(); } + } + static const O into_text[] = {{TL, 1, 0}, {TS, 2, 0}, {C, 0, 0}}; /* the bytes state's bytes into a text */ + static const T both[] = {{"data", T_BYTES_STATE, 1}, {"note", 1, 1}}; + H handler = {1, 0, 2}; + Spec spec = {nums, 1, inputs, 1, NULL, 0, &handler, 1, into_text, 2, NULL, 0, both, 2, constants, 2, NULL, 0, NULL, 0, NULL, 0}; + CHECK(load(spec, &module_b) != PURE_OK); + static const T anchored[] = {{"data", T_BYTES_STATE, 1}, {"at", PURE_STATE_CURSOR, 1}}; + static const O nothing[] = {{C, 0, 0}, {ST, 0, 0}}; + Spec with_anchor = {nums, 1, inputs, 1, NULL, 0, &handler, 1, nothing, 2, NULL, 0, anchored, 2, constants, 2, NULL, 0, NULL, 0, + NULL, 0}; + CHECK(load(with_anchor, &module_b) != PURE_OK); + printf("{\"bytes_states\":{\"starts\":7,\"replaces\":3,\"refused\":%zu}}\n", LEN(refused) + 2); +} + /* ---- Bytes compared (after research 140's DNS and HTTP) -------------------- * TEXT_COMPARE with PURE_COMPARE_BYTES relates two bytes by their bytes, as * it relates texts (a shorter before a longer it begins), UTF-8 asked of @@ -7391,6 +7496,7 @@ int main(void) { integers(); bits_and_bytes(); bytes_compared(); + bytes_states(); formats_and_held(); lists_in_records(); functions_and_characters(); -- cgit v1.2.3