aboutsummaryrefslogtreecommitdiffstats
path: root/serve/message-json.c
diff options
context:
space:
mode:
authoreunhhu <[email protected]>2026-09-30 16:16:08 +0100
committereunhhu <[email protected]>2026-09-30 16:16:08 +0100
commit46c303a41e9dd9cd0e6bd50511e8d7253a0ef438 (patch)
tree7564bf80ac43ff0964c64acd6a15f7299fa48997 /serve/message-json.c
parente02bfc916743a0327d76144b32b6ec6381e5907f (diff)
downloadpure-46c303a41e9dd9cd0e6bd50511e8d7253a0ef438.tar.gz
pure-46c303a41e9dd9cd0e6bd50511e8d7253a0ef438.zip
Give i64 its own type in modules, lists, stores and the host (016 stage 2)
An i64 is an int64_t in a value's 8 bytes, its own stack type: CONST and NUM_TEXT take argument 2 for one, eleven opcodes are appended (ADD, SUB and MUL fail as overflow past its range, DIV and MOD floor and fail as divide by zero, NEG, COMPARE with a relation, MIN, MAX, and I64_FROM and NUM_FROM, which convert only where the value fits and else fail as limit), and moves (LOAD, STORE, locals, items, FIELD, SEND) copy it as they copy a number. Type codes: state 6, record field 3, message field 7 (8 bytes), view 4, local 3. v6 stays: all of it is added. - Folds with PURE_FOLD_INTEGER sum (overflow fails), keep the most or least of, or count the different i64s; distinct's set keeps an i64's -1 apart from its free mark. Blocks with an i64 run item by item. - A list's kinds are its stored header's (number, text, bytes, bool, integer): integer columns are int64_t, ordered as integers as keys (found without guide keys for now), stored in 8 bytes and logged as zigzag varints of any size. Records name their fields' type in one array (record_field_type) in place of text and bool flags. - A number, a bool and an i64 carry over each other by one rule, pure_cell_as, wherever one becomes another: a module replaced, a stored value or item read by another module, a waiting send recast. A u32 field delivers to an i64 one. - The host reads i64 fields from JSON, rows and queries as integer digits in range and nothing else, and shows every digit in views, tables, deliveries and pure-run. Faults are named by one function, pure_fault_name, in place of three tables; overflow is new. test-module: 28 arithmetic cases at the range's ends, relations, conversions both ways, 14 refusals, a keyed i64 list app (order, a sum that overflows, a failed add undone, messages and sends of 8 bytes, every digit as text), recasts, replacement between numbers, bools and i64s, and three stored runs against memory with restarts (46 images written).
Diffstat (limited to 'serve/message-json.c')
-rw-r--r--serve/message-json.c42
1 files changed, 32 insertions, 10 deletions
diff --git a/serve/message-json.c b/serve/message-json.c
index afbd541..0905b34 100644
--- a/serve/message-json.c
+++ b/serve/message-json.c
@@ -83,6 +83,20 @@ static bool json_double(const unsigned char *text, size_t size, double *value) {
return isfinite(*value);
}
+/* A JSON integer in an i64's range (no point, no exponent), exactly: false for any other text. */
+static bool json_integer(const unsigned char *text, size_t size, int64_t *value) {
+ bool integer, negative = size && text[0] == '-';
+ if (!size || json_number(text, size, &integer) != size || !integer) return false;
+ uint64_t n = 0, most = negative ? (uint64_t)INT64_MAX + 1 : (uint64_t)INT64_MAX;
+ for (size_t i = negative; i < size; ++i) {
+ unsigned digit = (unsigned)(text[i] - '0');
+ if (n > (most - digit) / 10) return false;
+ n = n * 10 + digit;
+ }
+ *value = !negative ? (int64_t)n : n ? -(int64_t)(n - 1) - 1 : 0; /* -2^63 is; -0 is 0 */
+ return true;
+}
+
/* A JSON true or false at text: its length (4 or 5), or 0. */
static size_t json_bool(const unsigned char *text, size_t size, bool *value) {
if (size >= 4 && !memcmp(text, "true", 4)) return *value = true, 4;
@@ -91,7 +105,8 @@ static size_t json_bool(const unsigned char *text, size_t size, bool *value) {
}
/* A fixed field's value from its text (a query value or a JSON value) into
- * the prefix: a u32 in range, a finite number, or true or false for a bool. */
+ * the prefix: a u32 in range, a finite number, true or false for a bool, an
+ * integer in range for an i64. */
bool pure_json_fixed(const PureField *field, const unsigned char *text, size_t size, unsigned char *prefix) {
if (field->type == PURE_FIELD_BOOL) { /* true or false, as a JSON value says it */
bool value;
@@ -99,6 +114,12 @@ bool pure_json_fixed(const PureField *field, const unsigned char *text, size_t s
prefix[field->offset] = value;
return true;
}
+ if (field->type == PURE_FIELD_I64) {
+ int64_t value;
+ if (!json_integer(text, size, &value)) return false;
+ for (unsigned i = 0; i < 8; ++i) prefix[field->offset + i] = (unsigned char)((uint64_t)value >> (8 * i));
+ return true;
+ }
bool integer;
if (!size || json_number(text, size, &integer) != size || size > 40) return false;
if (field->type == PURE_FIELD_U32) {
@@ -289,7 +310,7 @@ static const char *rows_of(PureJsonMessage *b, unsigned char *json, size_t size,
*at = pure_json_space(json, *at, size);
}
if (*at == size || json[(*at)++] != '{') return "json_type";
- double numbers[PURE_RECORD_FIELDS];
+ PureValue numbers[PURE_RECORD_FIELDS]; /* a number's, a bool's or an i64's */
PureSpan texts[PURE_RECORD_FIELDS];
bool given[PURE_RECORD_FIELDS] = {false};
*at = pure_json_space(json, *at, size);
@@ -317,11 +338,12 @@ static const char *rows_of(PureJsonMessage *b, unsigned char *json, size_t size,
}
if (given[k]) return "json_field";
given[k] = true;
- bool text = m->record_field_text[record->first + k], truth;
- if (m->record_field_bool[record->first + k]) { /* true or false, nothing else */
+ uint8_t type = m->record_field_type[record->first + k];
+ bool text = type == PURE_RECORD_TEXT, truth;
+ if (type == PURE_RECORD_BOOL) { /* true or false, nothing else */
size_t word = json_bool(json + *at, size - *at, &truth);
if (!word) return "json_type";
- numbers[k] = truth;
+ numbers[k].num = truth;
*at = pure_json_space(json, *at + word, size);
continue;
}
@@ -341,14 +363,16 @@ static const char *rows_of(PureJsonMessage *b, unsigned char *json, size_t size,
size_t length = json_number(json + *at, size - *at, &integer);
if (!length) return *at < size && (json[*at] == '[' || json[*at] == '{' || json[*at] == 't' || json[*at] == 'f' ||
json[*at] == 'n') ? "json_type" : "json";
- if (text || !json_double(json + *at, length, &numbers[k])) return "json_type";
+ if (text || !(type == PURE_RECORD_I64 ? json_integer(json + *at, length, &numbers[k].i64)
+ : json_double(json + *at, length, &numbers[k].num)))
+ return "json_type";
*at = pure_json_space(json, *at + length, size);
}
if (*at == size) return "json";
++*at;
for (unsigned k = 0; k < record->count; ++k) {
uint32_t at_field = record->first + k;
- if (m->record_field_text[at_field]) {
+ if (m->record_field_type[at_field] == PURE_RECORD_TEXT) {
uint32_t constant = (uint32_t)m->record_field_default[at_field].num;
PureSpan text = given[k] ? texts[k]
: (PureSpan){m->constant_data + m->constant_offset[constant], m->constant_length[constant]};
@@ -357,9 +381,7 @@ static const char *rows_of(PureJsonMessage *b, unsigned char *json, size_t size,
if (text.size) memcpy(b->rows + b->rows_size + 4, text.data, text.size);
b->rows_size += 4 + text.size;
} else {
- double value = given[k] ? numbers[k] : m->record_field_default[at_field].num;
- uint64_t bits;
- memcpy(&bits, &value, 8);
+ uint64_t bits = (uint64_t)(given[k] ? numbers[k] : m->record_field_default[at_field]).i64; /* its bits */
if (!rows_room(b, 8)) return "memory";
for (unsigned i = 0; i < 8; ++i) b->rows[b->rows_size + i] = (unsigned char)(bits >> (8 * i));
b->rows_size += 8;