aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/module.c65
-rw-r--r--core/module.h18
2 files changed, 82 insertions, 1 deletions
diff --git a/core/module.c b/core/module.c
index 97270ef..ea6809e 100644
--- a/core/module.c
+++ b/core/module.c
@@ -1211,6 +1211,71 @@ uint32_t pure_module_shape(const PureModule *m, uint32_t input) {
return h;
}
+size_t pure_module_fields(const PureModule *m, uint32_t input, unsigned char out[PURE_FIELDS_NAMED]) {
+ const PureInputShape *s = &m->input[input];
+ size_t at = 0;
+ out[at++] = (unsigned char)s->field_count;
+ for (uint32_t f = 0; f < s->field_count; ++f) {
+ const PureField *field = &m->field[s->field_start + f];
+ size_t length = strlen(field->name);
+ out[at++] = field->type;
+ out[at++] = (unsigned char)length;
+ memcpy(out + at, field->name, length);
+ at += length;
+ }
+ return at;
+}
+
+/* Fields as a sender names them, laid out: their count, or -1 when they are
+ * not well named (no rows: a sender sends none). */
+static int named_fields(const unsigned char *bytes, size_t size, PureField *fields) {
+ if (!size || bytes[0] > PURE_MODULE_FIELDS) return -1;
+ unsigned count = bytes[0];
+ size_t at = 1;
+ for (unsigned f = 0; f < count; ++f) {
+ size_t length = size - at >= 2 ? bytes[at + 1] : 0;
+ if (size - at < 2 || !length || length >= PURE_MODULE_NAME || size - at < 2 + length || !bytes[at] ||
+ bytes[at] >= PURE_FIELD_ROWS)
+ return -1;
+ fields[f] = (PureField){.type = bytes[at]};
+ memcpy(fields[f].name, bytes + at + 2, length);
+ for (unsigned k = 0; k < f; ++k)
+ if (!strcmp(fields[k].name, fields[f].name)) return -1;
+ at += 2 + length;
+ }
+ if (at != size) return -1;
+ pure_fields_lay_out(fields, count);
+ return (int)count;
+}
+
+bool pure_module_takes(const PureModule *m, uint32_t input, const unsigned char *fields, size_t size) {
+ PureField sent[PURE_MODULE_FIELDS];
+ int count = named_fields(fields, size, sent);
+ if (count < 0) return false;
+ const PureInputShape *s = &m->input[input];
+ for (int k = 0; k < count; ++k) {
+ uint32_t f = 0;
+ while (f < s->field_count && strcmp(m->field[s->field_start + f].name, sent[k].name)) ++f;
+ if (f == s->field_count) return false; /* its value would be dropped */
+ uint8_t type = m->field[s->field_start + f].type, from = sent[k].type;
+ if (type != from && !(type == PURE_FIELD_NUMBER && from == PURE_FIELD_U32) &&
+ !(type == PURE_FIELD_BYTES && from == PURE_FIELD_TEXT))
+ return false;
+ }
+ return true;
+}
+
+PureResult pure_module_recast(const PureModule *m, uint32_t input, const unsigned char *fields, size_t size,
+ PureSpan payload, unsigned char **out, size_t *out_size) {
+ PureField sent[PURE_MODULE_FIELDS];
+ int count = named_fields(fields, size, sent);
+ *out = NULL;
+ *out_size = 0;
+ if (count < 0) return PURE_STORE_ERROR;
+ const PureInputShape *s = &m->input[input];
+ return pure_send_recast(sent, (uint32_t)count, &m->field[s->field_start], s->field_count, payload, out, out_size);
+}
+
int pure_module_view(const PureModule *m, const char *name) {
for (uint32_t i = 0; i < m->views; ++i)
if (!m->view_table[i] && !strcmp(m->view_names[i], name)) return (int)i;
diff --git a/core/module.h b/core/module.h
index ad31821..2cac3b3 100644
--- a/core/module.h
+++ b/core/module.h
@@ -217,8 +217,24 @@ int pure_module_view(const PureModule *, const char *name);
int pure_module_column(const PureModule *, uint32_t table, const char *name);
/* What a message of an input looks like, as 32 bits: its fields' names,
* types and places (FNV-1a). A sender's output and the input it sends to
- * across nodes must agree on it (link/link.h). */
+ * across nodes agree on it, or the input takes the output's fields by name
+ * (link/link.h, docs/design/014-fields-by-name.md). */
uint32_t pure_module_shape(const PureModule *, uint32_t input);
+/* An input's (or output's) fields as a sender names them to a receiver: u8
+ * count, each field's {u8 type, u8 name length, name}. Its size (at most
+ * PURE_FIELDS_NAMED), written to out. */
+enum { PURE_FIELDS_NAMED = 1 + PURE_MODULE_FIELDS * (2 + PURE_MODULE_NAME) };
+size_t pure_module_fields(const PureModule *, uint32_t input, unsigned char out[PURE_FIELDS_NAMED]);
+/* Whether input takes messages laid out with the fields named (as
+ * pure_module_fields names them): it has every one by name, of the same type
+ * or one that holds all its values (a u32 in a number, text in bytes). A
+ * field it has that they lack is 0 or empty; none of theirs is dropped. */
+bool pure_module_takes(const PureModule *, uint32_t input, const unsigned char *fields, size_t size);
+/* A payload laid out with the fields named, laid out anew for input by
+ * name (pure_module_takes says it can be; out is malloc'd). STORE_ERROR
+ * when payload is not laid out with them. */
+PureResult pure_module_recast(const PureModule *, uint32_t input, const unsigned char *fields, size_t size,
+ PureSpan payload, unsigned char **out, size_t *out_size);
/* The index state a number view shows as its position (a view that is just
* `at.position`), or -1: what a host moves with pure_app_point. */
int pure_module_position(const PureModule *, uint32_t view);