diff options
Diffstat (limited to 'prototypes/connections/module.h')
| -rw-r--r-- | prototypes/connections/module.h | 343 |
1 files changed, 0 insertions, 343 deletions
diff --git a/prototypes/connections/module.h b/prototypes/connections/module.h deleted file mode 100644 index f62326b..0000000 --- a/prototypes/connections/module.h +++ /dev/null @@ -1,343 +0,0 @@ -#ifndef PURE_MODULE_H -#define PURE_MODULE_H -#include "flow.h" -#include "result.h" -#include "module-list.h" -#include "state.h" -#include <stdbool.h> -#include <stddef.h> -#include <stdint.h> - -/* Pure module format v5 (docs/design/008-module-format.md). A toolchain such - * as aup produces it; Pure verifies it completely before anything executes: - * operand types (including which text a cursor and which list an index - * belongs to), stack heights and the stack at every join, forward-only - * branches, names, records, tables, constants and effects. */ -enum { - PURE_MODULE_STATES = 32, PURE_MODULE_INPUTS = 32, PURE_MODULE_VIEWS = 64, - PURE_MODULE_HANDLERS = 64, PURE_MODULE_CODE = 65535, PURE_MODULE_STACK = 64, - PURE_MODULE_NAME = 32, PURE_MODULE_STRINGS = 32768, PURE_MODULE_HEADER = 40, - PURE_MODULE_FIELDS = 64, PURE_MODULE_COLLECTIONS = 1, PURE_MODULE_CONSTANTS = 4096, - PURE_MODULE_CONSTANT_BYTES = 1 << 20, PURE_MODULE_RECORDS = 8, PURE_MODULE_RECORD_FIELDS = 64, - PURE_RECORD_FIELDS = 16, PURE_MODULE_JOINS = 8, PURE_APP_PENDING = 256 -}; - -typedef enum { - PURE_OP_CONST, PURE_OP_LOAD, PURE_OP_DT, PURE_OP_ADD, PURE_OP_SUB, PURE_OP_MUL, - PURE_OP_DIV, PURE_OP_NEG, PURE_OP_LT, PURE_OP_LE, PURE_OP_GT, PURE_OP_GE, - PURE_OP_EQ, PURE_OP_NE, PURE_OP_AND, PURE_OP_OR, PURE_OP_NOT, PURE_OP_MIN, - PURE_OP_MAX, PURE_OP_CLAMP, PURE_OP_STORE, PURE_OP_JZ, PURE_OP_JMP, - PURE_OP_FIELD, PURE_OP_DOC, PURE_OP_DOC_SIZE, PURE_OP_LEN, PURE_OP_REPLACE, - PURE_OP_REPLY, PURE_OP_REQUIRE, - PURE_OP_TEXT_CONST, PURE_OP_TEXT_LOAD, PURE_OP_TEXT_INPUT, PURE_OP_NUM_TEXT, - PURE_OP_CONCAT, PURE_OP_CHARS, PURE_OP_LINES, PURE_OP_TEXT_BYTES, - PURE_OP_CUR_LOAD, PURE_OP_CUR_START, PURE_OP_CUR_END, PURE_OP_CUR_MOVE, - PURE_OP_CUR_STORE, PURE_OP_TEXT_INSERT, PURE_OP_TEXT_REMOVE, PURE_OP_TEXT_LINE, - PURE_OP_TEXT_SET, PURE_OP_TEXT_FROM, PURE_OP_BYTES_FROM, PURE_OP_CUR_COUNT, - PURE_OP_LIST_COUNT, PURE_OP_LIST_APPEND, PURE_OP_LIST_INSERT, PURE_OP_LIST_REMOVE, - PURE_OP_ITEM_GET, PURE_OP_ITEM_SET, PURE_OP_INDEX_LOAD, PURE_OP_INDEX_STORE, - PURE_OP_INDEX_MOVE, PURE_OP_INDEX_FIRST, PURE_OP_INDEX_LAST, PURE_OP_INDEX_NUM, PURE_OP_ROW, - PURE_OP_PICK, PURE_OP_SLIDE, PURE_OP_FOLD, PURE_OP_TEXT_COMPARE, PURE_OP_LIST_FIND, PURE_OP_LIST_HAS, - PURE_OP_NOW, PURE_OP_FLOOR, PURE_OP_MOD, PURE_OP_SEND, - PURE_OP_COUNT -} PureOpcode; -/* FOLD's argument: the kind (bits 0-7), the list state (8-15) and the length - * of the block that follows (16-31), run once per item as a column of that - * list. count counts the items whose block leaves a non-zero number; sum, - * max and min take a value and an include flag from their block; first gives - * the index of the first item whose block leaves a non-zero number. */ -typedef enum { PURE_FOLD_COUNT, PURE_FOLD_SUM, PURE_FOLD_MAX, PURE_FOLD_MIN, PURE_FOLD_FIRST } PureFold; -/* TEXT_COMPARE's argument: the relation, in the order of the number - * comparisons (LT LE GT GE EQ NE); texts order by their bytes. */ -typedef enum { PURE_LESS, PURE_LESS_EQUAL, PURE_GREATER, PURE_GREATER_EQUAL, PURE_EQUAL, PURE_NOT_EQUAL } PureRelation; - -/* A timer ticks every `period` milliseconds while a host runs the app. An - * output is a message the app sends (SEND, in a handler; it has fields as a - * message has and no handler): what receives it is the host's wiring. */ -typedef enum { PURE_KIND_KEY = 1, PURE_KIND_MESSAGE = 2, PURE_KIND_TEXT = 3, PURE_KIND_TIMER = 4, - PURE_KIND_OUTPUT = 5 } PureInputKind; -enum { PURE_TIMER_LONGEST = 86400000, PURE_SOURCE = 64 }; -/* A message field: a u32le or a binary64 (fixed, at its offset in the - * payload's prefix), or bytes or text of any length. The prefix also holds - * each variable field's u32le length but the last one's (its offset is - * PURE_FIELD_REST), which takes what follows the others; the variable - * fields' bytes follow the prefix in declaration order. A text is UTF-8 and - * a number finite, or the message fails. */ -typedef enum { PURE_FIELD_U32 = 1, PURE_FIELD_BYTES = 2, PURE_FIELD_NUMBER = 3, PURE_FIELD_TEXT = 4 } PureFieldType; -enum { PURE_FIELD_REST = UINT32_MAX }; -typedef enum { - PURE_STATE_NUM = 0, PURE_STATE_TEXT = 1, PURE_STATE_CURSOR = 2, PURE_STATE_LIST = 3, PURE_STATE_INDEX = 4 -} PureStateType; -/* A cursor that stays before text inserted at it (a mark); other cursors go - * after it (a caret). */ -enum { PURE_CURSOR_STAYS = 1 }; -/* A table view has one row per item of a list, or per item its filter - * keeps; its columns are number or text views evaluated for one row at a - * time. */ -typedef enum { PURE_VIEW_NUM = 0, PURE_VIEW_TEXT = 1, PURE_VIEW_TABLE = 2 } PureViewType; -typedef enum { PURE_UNIT_CHAR = 0, PURE_UNIT_LINE = 1 } PureUnit; -typedef enum { PURE_EDGE_DOWN, PURE_EDGE_UP } PureEdge; -/* EXISTS: an item with that key is already in the keyed list (the event - * reports PURE_CONFLICT). */ -typedef enum { - PURE_FAULT_NONE, PURE_FAULT_DIVIDE, PURE_FAULT_NON_FINITE, PURE_FAULT_CLAMP, - PURE_FAULT_LIMIT, PURE_FAULT_NOT_FOUND, PURE_FAULT_ENCODING, PURE_FAULT_EXISTS -} PureFault; - -typedef struct { double value; uint32_t arg; uint8_t op; } PureOp; -typedef struct { uint32_t start, length; } PureBlock; -typedef struct { uint32_t event; PureBlock code; } PureHandler; -typedef struct { char name[PURE_MODULE_NAME]; uint8_t type; uint32_t offset; } PureField; -typedef struct { - uint8_t kind; - bool keyed; - uint16_t field_start, field_count; - uint32_t prefix; /* fixed payload bytes before the variable fields */ - uint32_t period; /* a timer's, in milliseconds */ -} PureInputShape; - -/* A record type: fields numbered from first, each a number or text. */ -typedef struct { uint16_t first, count; } PureRecord; - -typedef struct { - uint16_t states, inputs, views, handlers, fields, collections, constants, records, record_fields; - uint32_t code_count; - char state_names[PURE_MODULE_STATES][PURE_MODULE_NAME]; - char input_names[PURE_MODULE_INPUTS][PURE_MODULE_NAME]; - char view_names[PURE_MODULE_VIEWS][PURE_MODULE_NAME]; - char collection_names[PURE_MODULE_COLLECTIONS][PURE_MODULE_NAME]; - char input_keys[PURE_MODULE_INPUTS][PURE_MODULE_NAME]; - uint8_t state_type[PURE_MODULE_STATES]; - uint16_t state_ref[PURE_MODULE_STATES]; /* text: constant; cursor: text; list: record; index: list */ - uint8_t state_flags[PURE_MODULE_STATES]; /* cursor: PURE_CURSOR_STAYS */ - /* A keyed list: its key field + 1 (0: none). Its items stay in key order - * (numbers by value, texts by bytes), each key once, and keys do not change. */ - uint8_t state_key[PURE_MODULE_STATES]; - PureInputShape input[PURE_MODULE_INPUTS]; - PureField field[PURE_MODULE_FIELDS]; - double initial[PURE_MODULE_STATES]; - uint8_t view_type[PURE_MODULE_VIEWS]; - uint16_t view_table[PURE_MODULE_VIEWS]; /* a column's table view + 1, or 0 */ - uint16_t view_list[PURE_MODULE_VIEWS]; /* the list of a table or column */ - PureBlock view_code[PURE_MODULE_VIEWS]; - PureHandler handler[PURE_MODULE_HANDLERS]; - /* The code and the text constants, sized to the module in one block - * (storage) that load takes and pure_module_release gives back. */ - PureOp *code; - uint32_t *constant_offset, *constant_length; - unsigned char *constant_data; - void *storage; - char record_names[PURE_MODULE_RECORDS][PURE_MODULE_NAME]; - PureRecord record[PURE_MODULE_RECORDS]; - char record_field_names[PURE_MODULE_RECORD_FIELDS][PURE_MODULE_NAME]; - uint8_t record_field_text[PURE_MODULE_RECORD_FIELDS]; - double record_field_default[PURE_MODULE_RECORD_FIELDS]; /* number, or text constant index */ -} PureModule; - -/* Decode and verify into out, which must be zeroed (a static one is) or hold - * a loaded module: what it held is given back first. On failure out holds - * nothing and error names the rule. */ -PureResult pure_module_load(const void *bytes, size_t size, PureModule *out, - char *error, size_t error_size); -/* Give back a loaded module's code and constants (no app may still run it). */ -void pure_module_release(PureModule *); -/* Read a module file whole and load it (NOT_FOUND when it cannot be read). */ -PureResult pure_module_read(const char *path, PureModule *out, char *error, size_t error_size); -/* Index of a name, or -1. Views are those outside tables. */ -int pure_module_state(const PureModule *, const char *name); -int pure_module_input(const PureModule *, const char *name); -int pure_module_view(const PureModule *, const char *name); -int pure_module_column(const PureModule *, uint32_t table, const char *name); -/* 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); -/* The text state a text view shows as it is (a view that is just the - * state), or -1: a host may lend its stored extents instead of copying. */ -int pure_module_text_state(const PureModule *, uint32_t view); - -/* Keyed collections live in a data host (for example the tree store). One - * event opens at most one document, the message's key, at its current - * version; edits stay in that working version until the event commits it. - * A version's bytes field is the value's size. */ -typedef struct { - void *context; - PureResult (*open)(void *context, uint32_t collection, const char *key, - void **document, int64_t *revision); - PureVersion (*version)(void *context, void *document); - PureResult (*read)(void *context, void *document, PureVersion, size_t offset, size_t length, - bool (*visit)(void *, PureSpan), void *visit_context); - PureResult (*splice)(void *context, void *document, size_t offset, size_t remove, PureSpan insert); - PureResult (*commit)(void *context, void *document, int64_t *revision); - void (*close)(void *context, void *document); - /* Optional: the host keeps the app's states. state opens a runtime-owned - * value by name as a draft (a missing one is empty at revision 0); save - * publishes the given documents and state drafts together, all or - * nothing, and names each document's new revision. */ - PureResult (*state)(void *context, const char *name, PureDraft **out); - PureResult (*save)(void *context, void *const *documents, size_t document_count, PureDraft *const *states, - size_t count, int64_t *revisions); -} PureData; - -/* A byte or text value inside one event or view: a range of the payload, a - * document or text version, a module constant, a copy or the event's arena. */ -typedef struct { uint8_t source; uint16_t owner; PureVersion version; uint64_t offset, length; } PureBytes; -typedef struct { unsigned char *bytes; size_t used, capacity; } PureArena; - -/* One app instance: its states and at most one open event. Text states are - * runtime-owned drafts; cursors are positions the runtime keeps on character - * boundaries; lists are runtime-owned and an index always names an item - * (or 0 in an empty list). Every event is atomic: on failure nothing changes. - * - * Saving. When the data host keeps states the app starts from the stored - * ones. A save publishes, in one commit, the documents edited by messages and - * the states changed since the last save; if it fails, every event since the - * last save is undone. By default each key, text and message event saves - * before it returns (a frame waits for the next one). Deferred, events apply - * at once and a host saves a burst with one commit: an event is durable once - * a later save succeeds, and each key's document joins a burst once (a second - * message for it, or one past PURE_APP_PENDING keys, saves the burst first). */ -typedef struct { - const PureModule *module; - PureData data; - double values[PURE_MODULE_STATES]; /* numbers, cursor byte positions and list indices */ - PureDraft *texts[PURE_MODULE_STATES]; - PureList *lists[PURE_MODULE_STATES]; - PureUndo undo; /* list changes of the current event */ - PureDraft *list_drafts[PURE_MODULE_STATES]; /* stored lists, when kept */ - PureDraft *stored_values; /* numbers, cursors and indices, when kept */ - PureVersion saved[PURE_MODULE_STATES]; /* text and list versions at the last save */ - /* Events since the last save: what a failed save returns to, and the - * documents messages opened (held until the save). */ - bool deferred, open; - double durable_values[PURE_MODULE_STATES]; - PureVersion durable_texts[PURE_MODULE_STATES], durable_lists[PURE_MODULE_STATES]; - uint64_t durable_ticks, durable_events; - struct PurePending { void *document; char key[65]; bool edited; } *pending; /* grows to PURE_APP_PENDING */ - unsigned pending_count, pending_capacity; - PureFault fault; - uint32_t fault_pc; - uint64_t ticks, events; - /* The time events see as now, in milliseconds since 1970 (UTC). The host - * sets it, so a script can replay any time; views never see it. */ - double now; - uint64_t changes; /* counts every change of states, never back: what a filter's rows are fresh for */ - struct PureRows { uint32_t table; uint64_t changes; size_t *items, count, capacity; } *rows; /* a filtered table's items */ - unsigned row_tables; - /* Current message or text event, kept until pure_app_finish. */ - void *document; - PureSpan payload; - bool has_reply; - PureBytes reply; - unsigned char *copied; - int64_t revision; - PureArena arena, view_arena; - /* Links (runtime-owned, saved with the states): messages sent on outputs - * and not trimmed, in the order sent (the first sent_durable are saved; - * a trimmed one goes at the next save), each output's last number (and - * as saved), those of outputs a module dropped, and the last number - * delivered from each source (and as saved). */ - struct PureSent { uint32_t output; uint64_t seq; unsigned char *payload; size_t size; bool trimmed; } *sent; - size_t sent_count, sent_capacity, sent_durable; - uint64_t last_sent[PURE_MODULE_INPUTS], saved_sent[PURE_MODULE_INPUTS]; - struct PureCarried { char name[PURE_MODULE_NAME]; uint64_t last; } *carried; - unsigned carried_count; - struct PureHeard { char source[PURE_SOURCE + 1]; uint64_t seq, saved; } *heard; - unsigned heard_count, heard_capacity; - PureDraft *stored_links; - bool links_changed; /* since the last save */ - bool duplicate; /* the last delivery was heard before and not applied */ - struct { const char *source; uint64_t seq; bool pending; } delivering; - struct PureSnapshot *snapshot; /* the newest snapshot made, or NULL */ - PureRetired retired; /* list items let go since it was made */ - bool reading; /* a reader: its states are a snapshot's */ -} PureApp; - -PureResult pure_app_start(PureApp *, const PureModule *, PureData data); -/* Publish every change since the last save in one commit, or undo them all. */ -PureResult pure_app_save(PureApp *); -/* Defer saving to pure_app_save (false: save after each event). Needs a data - * host that saves documents together (PureData.save). */ -bool pure_app_defer(PureApp *, bool deferred); -/* Leaves unsaved frame changes unsaved: call pure_app_save first to keep them. */ -void pure_app_stop(PureApp *); -PureResult pure_app_frame(PureApp *); -/* A timer input's tick: an event saved like a key's. */ -PureResult pure_app_tick(PureApp *, uint32_t input); -PureResult pure_app_input(PureApp *, uint32_t input, PureEdge); -/* Point an index state at the item at position (0 first), as a user pointing - * at a row: an event with no handler, saved like a key event. NOT_FOUND past - * the last item, INVALID for a state that is not an index. */ -PureResult pure_app_point(PureApp *, uint32_t state, size_t position); -/* Deliver committed text (for example from an input method). Not UTF-8: invalid. */ -PureResult pure_app_text(PureApp *, uint32_t input, PureSpan text); -/* Deliver a message. base is the revision the sender edited, or -1 for none; - * a handler that edits the document needs one. payload stays alive until - * pure_app_finish. On return app->revision is the document's revision - * (deferred: the revision the next save gives it). */ -PureResult pure_app_message(PureApp *, uint32_t input, const char *key, int64_t base, PureSpan payload); -/* The same, with the variable fields where the host found them: field f - * starts at placed[2f] in payload and has placed[2f + 1] bytes (entries of - * fixed fields are not read, nor are the variable fields' lengths in the - * prefix). A host that parsed a request in place passes the fields' bytes - * where they are. */ -PureResult pure_app_message_fields(PureApp *, uint32_t input, const char *key, int64_t base, PureSpan payload, - const uint32_t *placed); -/* Visit the reply of the last message in order, without copying, until the - * next event (deferred: copy it before a later save too). */ -PureResult pure_app_reply(const PureApp *, bool (*visit)(void *, PureSpan), void *context); -void pure_app_finish(PureApp *); -/* A number view; false for a text view or a failed evaluation. */ -bool pure_app_view(PureApp *, uint32_t view, double *out); -/* A text view, lent in order until the next view evaluation. */ -PureResult pure_app_view_text(PureApp *, uint32_t view, bool (*visit)(void *, PureSpan), void *context); -/* The rows of a table view (its list's items, or those its filter keeps), - * or 0 for another view. A host evaluates only the cells it shows. */ -size_t pure_app_rows(PureApp *, uint32_t table); -/* The item a row of a table shows, and the row that shows an item (false: - * its filter leaves the item out). Without a filter both are the identity. */ -bool pure_app_row_item(PureApp *, uint32_t table, size_t row, size_t *item); -bool pure_app_item_row(PureApp *, uint32_t table, size_t item, size_t *row); -bool pure_app_cell(PureApp *, uint32_t column, size_t row, double *out); -PureResult pure_app_cell_text(PureApp *, uint32_t column, size_t row, bool (*visit)(void *, PureSpan), void *context); -/* Switch to another verified module. States keep their value by name (text - * states keep their content, cursors their position in that text); new states - * start at their initial value. The module must outlive the app. */ -PureResult pure_app_replace(PureApp *, const PureModule *); - -/* Connections between apps (docs/research/078-app-connections.md). A host - * sees only saved sends, delivers each at least once, in order per output, - * and trims what its receiver has saved; a receiver applies each once. */ -typedef bool (*PureSentVisit)(void *context, uint32_t output, uint64_t seq, PureSpan payload); -void pure_app_outbox(const PureApp *, PureSentVisit visit, void *context); -/* The same, newest first (a host looking only for what is new stops early). */ -void pure_app_outbox_newest(const PureApp *, PureSentVisit visit, void *context); -/* Forget output's saved sends numbered up to through (saved with the next save). */ -void pure_app_trim(PureApp *, uint32_t output, uint64_t through); -/* Deliver a message event from source (a sender's name, 1 to 64 printable - * ASCII bytes) numbered seq (from 1, growing per source). A number heard - * before is not applied again: it succeeds with app->duplicate set. The - * number counts as heard with the event's changes, and also when the app - * refuses the message (a fault: it was delivered, and refused); not when a - * save fails. placed is as for pure_app_message_fields, or NULL. */ -PureResult pure_app_deliver(PureApp *, uint32_t input, const char *source, uint64_t seq, PureSpan payload, - const uint32_t *placed); - -/* Readers on other threads. Right after a save an app can make a snapshot of - * its saved states, for evaluating views anywhere while it keeps applying - * events: numbers are copied; text states share their stored versions and - * lists their items (a list unchanged since the last snapshot shares that - * snapshot's copy), so the cost does not grow with the text. NULL when a - * change waits for a save, when a text state is not all stored (for example - * without a data host that keeps states), or when memory runs out. The caller - * gets a reference; the app keeps its own until the next snapshot. */ -typedef struct PureSnapshot PureSnapshot; -PureSnapshot *pure_app_snapshot(PureApp *); -void pure_snapshot_hold(PureSnapshot *); -/* On any thread; the last reference frees it. */ -void pure_snapshot_release(PureSnapshot *); -/* Show a snapshot's states in reader, a zeroed app or a reader before: its - * views read them while the snapshot is held, with the reader's own arena and - * row cache (one thread at a time). It applies no events. pure_app_stop frees - * the reader and leaves the snapshot alone. */ -void pure_app_read(PureApp *reader, const PureSnapshot *); -#endif |
