code-native 2.18.3

Write native .so modules for the Code programming language in Rust — safe CodeValue builders/readers over the real runtime.c, no reimplementation.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
/* code_abi.h — the native module ABI.
 *
 * A native module is a `.so` compiled from any language that can produce a
 * C-ABI shared library. It must:
 *
 *   1. `#include` this header (or reproduce it exactly — the layout below,
 *      once a module is compiled against it, is a wire format: changing it
 *      silently breaks every module built against the old one).
 *   2. Export `uint32_t code_module_abi_version(void)`, returning
 *      `CODE_ABI_VERSION`.
 *   3. Export `void code_module_dispatch(CodeValue *out, const CodeValue
 *      *particle)`, doing its own `_class`-field dispatch exactly like
 *      `runtime.c`'s `code_core_dispatch` — see that function for the
 *      pattern to copy.
 *   4. Export `void code_release(CodeValue *v)`, so the host can free
 *      whatever `code_module_dispatch` allocated for its result. The
 *      simplest way to get a correct one is to `#include "runtime.c"`
 *      itself (its constructors/refcounting are exactly what a handler
 *      needs to build a result) — see `tests/native_modules/` for an
 *      example.
 *   5. *Optionally* export `const CodeVarList *code_module_vars(void)`,
 *      returning the module's exported values (constants) — see
 *      `CodeVarList` below. A module that does not export it simply has no
 *      exported variables; `link "x.so" as x` then binds `x` to an empty
 *      object. This is optional (not a required symbol) so that a Phase 1
 *      module — handlers only — keeps working unchanged, and so the ABI
 *      version does not have to bump for it.
 *   6. *Optionally* export `void code_module_set_inbound(void *queue,
 *      CodeEmitFn emit)`. The host calls it once at link time to hand the
 *      module a queue and the function that pushes onto it; the module
 *      keeps both and may call `emit(queue, &particle)` to speak *first*,
 *      rather than only answering a dispatch. Optional for the same reason
 *      as `code_module_vars`: a module that never initiates simply doesn't
 *      export it, and the ABI version doesn't move.
 *   7. *Optionally* export `void code_module_inbound_reply(const CodeValue
 *      *particle, const CodeValue *result)`. After the host dispatches a
 *      particle this module pushed, it calls this with the particle it
 *      pushed and whatever the program's handler returned — `CODE_NULL` when
 *      no handler matched. That is how a push gets an *answer*: a module
 *      that asks the program a question (an HTTP request needing a response)
 *      gets one back, without the program having to emit anything.
 *
 *      Both pointers are the host's and are valid only for the duration of
 *      the call: read what you need and copy it out. Optional, and additive,
 *      for the same reason as the two above — a module that only announces
 *      things does not export it, and the ABI version does not move.
 *
 *      Correlation is the module's own business. Nothing identifies *which*
 *      push is being answered beyond the particle handed back, so a module
 *      with more than one outstanding push has to carry its own key in the
 *      particle it pushed and read it back here.
 *
 *   8. *Optionally* export `int code_module_serving(void)`, returning
 *      non-zero while this module still expects to speak — a socket it is
 *      listening on, a timer that has not fired for the last time.
 *
 *      This is what keeps the program alive. A program does not end at its
 *      last statement while any linked module answers non-zero here: the
 *      host parks, wakes on a push, dispatches it, and parks again, exactly
 *      as a JVM stays up for a non-daemon thread. That is why an application
 *      that serves HTTP writes no keep-alive loop of its own.
 *
 *      A module that exports nothing here holds nothing open, which is why
 *      this is safe to add: every program that ended when it used to still
 *      ends then. Optional and additive, for the same reason as the three
 *      above — the ABI version does not move.
 *
 *      The obvious alternative does not work: a module cannot simply block
 *      forever inside `code_module_dispatch` instead. A pushed particle is
 *      dispatched to the *program's* handlers, which run on the host's
 *      thread between statements — a thread parked inside a dispatch is not
 *      between statements, so nothing it queues is ever handled. Measured:
 *      every request times out one frame below the handler that should have
 *      answered it.
 *
 *   9. *Optionally* export `void code_module_release(void)` — the point at
 *      which this module gives up everything it owns.
 *
 *      Every rule above says a module owns its exported values "for the
 *      module's whole lifetime", and until this existed there was no way to
 *      say when that lifetime ended: a module was loaded until the process
 *      exited, so the question never came up. `unlink` (a `link` that ran
 *      inside a handler, see `ast::Stmt::LinkRuntime`) is that question. It
 *      calls this, and then unloads the module.
 *
 *      So the contract is sharp: after this call **nothing in the module may
 *      be touched again** — not a dispatch, not an exported value, not a key
 *      string an exported object borrowed. The caller unloads it
 *      immediately, which is the only reason it is safe to free everything
 *      here rather than merely promising to.
 *
 *      What it must free is what a program frees when it ends: every
 *      top-level value the module holds. A `.code` library compiled with
 *      `--target shared` gets one generated for it, ending in that copy of
 *      the runtime's own `code_check_leaks` — which is what turns "the
 *      module let go of everything" from a claim into a check under
 *      `CODE_CHECK_LEAKS=1`.
 *
 *      A module that exports nothing here is simply never released, and
 *      `unlink` unloads it anyway. That is correct for the hand-written
 *      modules, which keep their state in C statics rather than in
 *      refcounted blocks. Optional and additive, for the same reason as the
 *      four above — the ABI version does not move.
 *
 *  10. *Optionally* be **hosted**: when a program opens this module while it
 *      is running, it may furnish the modules this one links rather than
 *      letting it open them itself. See "Being hosted" further down for the
 *      two structs and the one function, and for why a hosted module's
 *      `link` is not allowed to fall back to the filesystem.
 *
 *      Nothing is exported for this — the runtime every compiled `.so`
 *      carries defines `code_module_set_host` itself, so a module gets it by
 *      existing. A module built before this did not, which is exactly how a
 *      host tells the two apart.
 *
 *  11. *Optionally* export `void code_module_drain(void)` — run this
 *      module's own inbound drain once.
 *
 *      A module that linked something which speaks first has a queue, and
 *      queues are emptied by a *program*'s loop, between its statements and
 *      on waking. A module loaded as a library has no such loop: its stream
 *      ran once and returned. So whoever opened it does the emptying, and
 *      this is where they reach in.
 *
 *      Paired with `CodeHostVtable.wake`, that makes one loop cover both:
 *      the guest's pushes ring the host's bell, the host wakes, drains
 *      itself and its guests, and parks again. The alternative — a host
 *      polling what it holds — is the busy waiting this runtime refuses to
 *      do anywhere else.
 *
 *      Generated for a `--target shared` build that has anything to drain.
 *      Optional and additive: a module without it simply has no queues worth
 *      emptying, and the ABI version does not move.
 *
 *  12. *Optionally* export `int code_module_stateless(void)`, returning
 *      non-zero, to say this module keeps no state: no settings, no
 *      connection, nothing a call leaves behind for the next one.
 *
 *      Every link of a module normally gets its own copy of it (a name is a
 *      module — see `runtime.c` `module_image`), and the whole file is paid
 *      for in memory once per link. A module that keeps nothing has nothing
 *      to keep apart, so every link of its file then shares one instance
 *      (ticket 177). Declare it only when it is true: two links of a module
 *      that does keep something would then change each other's.
 *
 *      Not honoured for a module that also exports `code_module_set_inbound`,
 *      `code_module_serving`, `code_module_release` or `code_module_drain`.
 *      Optional and additive: a module without it is loaded per link as
 *      before, and the ABI version does not move.
 *
 *  13. *Optionally* export `void *code_module_instance_new(void)` and
 *      `void code_module_instance_dispatch(void *instance, CodeValue *out,
 *      const CodeValue *particle)`, to keep state per link without a copy
 *      of the module per link.
 *
 *      The host then opens the file once for every link, asks for a new
 *      instance per link, and sends that link's particles to
 *      `code_module_instance_dispatch` with its instance; settings and
 *      connections live in the instance, not in globals. An instance is
 *      never freed (a module is not unloaded). The module still exports
 *      `code_module_dispatch`, working on an instance of its own, for a
 *      host that predates this — which then copies the module per link as
 *      it always did (ticket 178: mongodb was 16 copies on one host).
 *
 *      Not honoured for a module that exports `code_module_serving`,
 *      `code_module_release` or `code_module_drain`. A module that pushes
 *      (`code_module_set_inbound`) is honoured only when it also exports
 *      `void code_module_instance_set_inbound(void *instance, void *queue,
 *      CodeEmitFn emit)`: each link's queue is then handed to that link's
 *      instance, and what a thread started by a dispatch pushes goes to the
 *      link that asked (ticket 178; `code-native`'s `inbound_here` and
 *      `InboundScope`). `code_module_inbound_reply` stays module-wide.
 *      Optional and additive; the ABI version does not move.
 *
 * Why `emit` is a function *pointer* the host supplies, rather than a
 * `code_emit_inbound` a module could call directly: a `.so` carries its own
 * copy of this runtime (see below), so a direct call would push onto the
 * module's own queue, which the host never reads. The pointer is the host's.
 * A queued particle is deep-copied into the host's heap by that function,
 * the same boundary rule a dispatch result follows, so the module may
 * release its own copy the moment `emit` returns.
 *
 * Queued particles are dispatched to the *program's* handlers — a `.code`
 * `ClassName { ... } => { ... }` — not back into the module. That is what
 * makes an event loop expressible: the module supplies events, the program
 * decides what they mean.
 *
 * Why a module needs its own `code_release`, not the host's: values never
 * cross this boundary by shared ownership. Whatever a module allocates for
 * its result is deep-copied into the host's own heap immediately after the
 * call (see `code_native_dispatch` in runtime.c) using the host's own
 * refcount bookkeeping, and then the module's copy of `code_release` frees
 * what the module itself allocated. Each side's allocator only ever frees
 * blocks it itself allocated — that's what keeps `CODE_CHECK_LEAKS`
 * meaningful on both sides of a dlopen boundary, where two copies of this
 * runtime have entirely separate static state.
 *
 * Loading is dlopen/dlsym-based, in both `code run` and a `code build`
 * binary — never `cc`-time static linking. Every module exports the same
 * three symbol names, and that's fine: dlsym resolves within one module's
 * own handle, so two linked modules never collide, no matter how many
 * handlers each defines internally.
 *
 * A fatal error inside a module (its own `code_runtime_error`, a segfault,
 * anything that isn't a normal return) takes down the *host* process —
 * `code run` included, not just a `code build` binary. Unlike `core`
 * (`code_core_dispatch`), which the interpreter has its own independent
 * Rust implementation of specifically so a bad handler call there is a
 * clean `Result::Err`, a native module is real native code the interpreter
 * runs in-process via dlopen — there is no reimplementation to fall back
 * on, and no sandboxing here (out of scope for Phase 1). This is the same
 * tradeoff any native-extension mechanism makes (a Python C extension can
 * just as easily crash the interpreter that loaded it); it is not
 * considered a bug, and `docs/todo/native-module-linking.md`'s fixture
 * suite works around it by never provoking a module's fatal path in-process.
 */
#ifndef CODE_ABI_H
#define CODE_ABI_H

#include <stdint.h>

#define CODE_ABI_VERSION 2


typedef enum { CODE_NUMBER, CODE_STR, CODE_BOOL, CODE_NULL, CODE_ARRAY, CODE_OBJECT } CodeTag;

/* The head of a list's or an object's block: how many elements it has, and
 * (an object's) where its keys are. The elements follow it, one
 * `CODE_VALUE_SLOT_SIZE` slot each — `code_list_items`. An object's key
 * pointers and their characters come after its slots, in the same block.
 * The block's refcount and spare word are just before this head, like every
 * block's (ticket 122 stage C.2: a value is 16 bytes; it was 80 while each
 * one carried its list's fields itself). */
typedef struct CodeList {
    long long len;
    const char **keys; /* CODE_OBJECT only, `len` key pointers */
} CodeList;

/* A value: its kind, whether it holds a counted block, and one payload — the
 * kind says which. An empty list or object has no block (`list` NULL). */
typedef struct CodeValue {
    CodeTag tag;
    int heap;
    union {
        double number;      /* CODE_NUMBER */
        const char *str;    /* CODE_STR */
        int boolean;        /* CODE_BOOL */
        CodeList *list;     /* CODE_ARRAY, CODE_OBJECT */
    };
} CodeValue;

#define CODE_VALUE_SLOT_SIZE 16

/* Optional synchronous metadata dispatch. A module may export
 * int code_module_dispatch_borrowed_v1(CodeValue *out,
 *     const CodeBorrowedApi *api, const void *particle).
 * A nonzero return means it answered; zero asks the host to call ordinary
 * code_module_dispatch with a fully marshaled particle. Unsupported api->version
 * must return zero. All other exports remain mandatory; old hosts ignore this.
 * ABI 2 value layout is unchanged. The interpreter currently supplies version 1;
 * compiled hosts already supply ordinary borrowed CodeValues and need no view.
 *
 * Opaque values and UTF-8 bytes are read-only and valid only until dispatch
 * returns, on the calling thread. Never retain them, mutate them, send them to
 * another thread, or use them as CodeValues. Callbacks may only be called with
 * the root or a value returned by field. field borrows its UTF-8 key during
 * that callback; it returns the FIRST matching field, or NULL if absent or
 * not an object. A result is an ordinary module-owned CodeValue, copied and
 * released by the host as usual. Even a declined result is released first.
 * inspect exposes metadata only: tag, container element count or string byte
 * length, and a borrowed UTF-8 pointer for strings (NULL allowed when empty).
 * Non-string scalars have length zero and bytes NULL. Hosts preserve their
 * existing transport limitations (e.g. interpreter interior-NUL strings).
 */
typedef struct CodeValueInfo {
    int32_t tag;
    uint64_t length;
    const uint8_t *bytes;
} CodeValueInfo;
typedef struct CodeBorrowedApi {
    uint32_t version;
    CodeValueInfo (*inspect)(const void *value);
    const void *(*field)(const void *value, const uint8_t *key, uint64_t length);
} CodeBorrowedApi;

/* A list's or an object's element count, slots and keys — 0/NULL for an
 * empty one, and for a value of any other kind. */
static inline CodeList *code_list_of(const CodeValue *v) {
    return (v->tag == CODE_ARRAY || v->tag == CODE_OBJECT) ? v->list : (CodeList *)0;
}
static inline long long code_list_len(const CodeValue *v) {
    CodeList *list = code_list_of(v);
    return list ? list->len : 0;
}
static inline void *code_list_items(const CodeValue *v) {
    CodeList *list = code_list_of(v);
    return list ? (void *)(list + 1) : (void *)0;
}
static inline const char **code_list_keys(const CodeValue *v) {
    CodeList *list = code_list_of(v);
    return list ? list->keys : (const char **)0;
}

/* What `code_module_set_inbound` hands a module: the host's own pusher.
 * `queue` is opaque to the module — it only ever passes it straight back. */
typedef void (*CodeEmitFn)(void *queue, const CodeValue *value);

/* `code_module_inbound_reply` — see the numbered list above. Declared as a
 * type here because the host stores one per module; a module writes the
 * function itself. */
typedef void (*CodeInboundReplyFn)(const CodeValue *particle, const CodeValue *result);

/* How many pushed particles a module may have outstanding before the oldest
 * starts being dropped. Bounded on purpose: a module that pushes faster than
 * the program drains must cost bounded memory, not unbounded. */
#define CODE_INBOUND_CAPACITY 256

/* A module's exported variables (constants) — what `code_module_vars`
 * returns. `names` and `values` are parallel arrays of `count` entries:
 * `values[i]` is the value exported under `names[i]`. `values` is strided at
 * `CODE_VALUE_SLOT_SIZE` bytes (address it through a `slot_at`-style helper,
 * never `[]`), exactly like a `CodeValue`'s own `items` buffer.
 *
 * The module owns all of this memory — the names, the value buffer, and
 * everything the values point into — and it must stay valid for the module's
 * whole lifetime (the host reads it once at `link` time and deep-copies each
 * value out, the same way it treats a `code_module_dispatch` result). The
 * host never frees any of it; it only ever calls the module's own
 * `code_release` on a *copy* it made. */
typedef struct CodeVarList {
    long long count;
    const char **names;
    CodeValue *values; /* CODE_VALUE_SLOT_SIZE stride, `count` slots */
} CodeVarList;

/* ---- Being hosted: item 10 -----------------------------------------------
 *
 * A module normally finds its own modules: a `link` inside it opens the
 * file it names. When a *program* opens a module while it is running
 * (`ast::Stmt::LinkRuntime`), that is the wrong answer — the guest would
 * bind its own port and hold its own connections, and the host it is running
 * inside would have no way to know what it took or to take it back.
 *
 * So the opener may furnish the guest's world instead. It installs the pair
 * below, and from then on every `link` inside that guest asks the host
 * rather than the filesystem.
 *
 * **A host furnishes only what it says it furnishes.** `resolve` may decline,
 * and then the module opens the file itself — its own copy, its own
 * settings, isolated, exactly as it would with no host at all. That is the
 * ordinary case: what an application links is its own business, and a
 * host that wants no say has to write nothing to get none. A host that does
 * answer is taking that say, and what it hands back is what the guest gets.
 *
 * A module with no host installed is unaffected in every case, which is what
 * keeps an application runnable on its own.
 *
 * **The two `ctx` values below are handles, not addresses.** Nothing here
 * may be a pointer into the host's own bookkeeping: a guest outlives
 * individual decisions the host makes about it, and a host that hands out
 * addresses has to get every one of those lifetimes exactly right. A handle
 * the host looks up can name something that is gone, and the host answers
 * cleanly instead of touching freed memory. Treat these as opaque tokens:
 * store them, hand them back, never dereference them.
 */

/* One module, as the host supplies it.
 *
 * The mirror of the `code_module_*` exports, with a `ctx` threaded through
 * every one — because the host is answering on behalf of a *particular*
 * guest, and the same host answers for several. A plain function pointer
 * could not tell them apart; this is what carries "which guest is asking".
 *
 * `vars` and `serving` may be NULL, meaning the same as a module that
 * exports neither: no exported values, and nothing held open. `dispatch` and
 * `release` may not. */
typedef struct CodeHostModule {
    void (*dispatch)(void *ctx, CodeValue *out, const CodeValue *particle);
    void (*release)(void *ctx, CodeValue *v);
    const CodeVarList *(*vars)(void *ctx);
    int (*serving)(void *ctx);
    void *ctx;
} CodeHostModule;

/* What the host answers `link` with.
 *
 * `resolve` is asked once per `link`, with `ref` spelled the way the guest
 * wrote it. Non-zero and `out` filled means "here it is"; zero means the
 * host does not offer it, and the guest's `link` fails.
 *
 * `host_ctx` is whatever was handed to `code_module_set_host` — a handle,
 * see above. */
typedef struct CodeHostVtable {
    int (*resolve)(void *host_ctx, const char *ref, CodeHostModule *out);
    /* "Something arrived for me." Called after a module this guest opened
       pushes a particle, so the host wakes and drains the guest along with
       its own queues.
    
       Without it a hosted guest's pushes are never heard: the drain loop
       belongs to a *program*, and a guest is a library whose stream ran once
       and returned. The alternative — the host polling its guests — is the
       busy waiting this runtime refuses to do anywhere else. One wakeup, one
       drain, shared. May be NULL, in which case the guest's pushes wait for
       whatever else wakes the host. */
    void (*wake)(void *host_ctx);
} CodeHostVtable;

/* Installs the host for this module. Defined by the runtime every compiled
 * `.so` carries, so every one of them exports it without doing anything —
 * which is what lets a host tell a module built before this existed (no such
 * symbol, and it cannot be hosted) from one that can.
 *
 * Called immediately after opening the module and before anything else. A
 * `.code` library runs its top level lazily, on the first dispatch or the
 * first read of its values, and its `link`s run with it — so installing the
 * host afterwards would be too late for exactly the statements this exists
 * to intercept. */
void code_module_set_host(const CodeHostVtable *host, void *host_ctx);

/* ---- `.a` static modules — a different, simpler contract -----------------
 *
 * Everything above is the `.so` contract: a module `dlopen`s in as a
 * self-contained unit with its own copy of the runtime, so values crossing
 * the boundary need a deep copy and the module needs its own `code_release`.
 *
 * A `.a` module is linked straight into the same binary as the host by `cc`
 * (`code build` only — there is no `dlopen` for a static archive, so `code
 * run` refuses to link one at all). That means there is only ever one copy
 * of the runtime in the final program — the host's — so a `.a` module does
 * NOT bring its own copy of it. It builds its results by calling the host's
 * own constructors directly, declared `extern` below, and needs no
 * `code_release` of its own: nothing it builds is ever a separate
 * allocation to free.
 *
 * The only names a `.a` module must still choose carefully are the ones it
 * defines itself — `code_module_dispatch` and `code_module_abi_version`
 * (required), `code_module_vars` (optional) — because unlike `.so` handles,
 * every `.a` linked into one program shares a single flat symbol table.
 * Convention: pick a prefix unique among every `.a` your program will ever
 * link alongside, and name them `<prefix>_code_module_dispatch`,
 * `<prefix>_code_module_abi_version`, `<prefix>_code_module_vars`. `code
 * build` finds them by running `nm` on the archive at link time (see
 * `loader.rs`), so `link "libfoo.a" as m` needs no syntax to name the
 * prefix — it just has to be unique.
 *
 * The optional entry points take the prefix the same way:
 * `<prefix>_code_module_set_inbound`, `_inbound_reply`, `_serving` (which
 * holds the program open, as a `.so`'s does), `_stateless` (item 12) and
 * `_instance_new` / `_instance_dispatch` (item 13). With instances, every
 * alias linking the archive gets one of its own where its `link` runs; a
 * module that keeps state and offers none is refused under a second alias
 * in a native build, since both names would share its statics.
 *
 * A first-party module is not written twice for this. It exports its
 * `code_module_*` names once, for its `.so`; `scripts/build-module-static.sh`
 * builds it as a `staticlib` with no runtime (`code-native/static-module`),
 * renames those exports to `<module>_code_module_*` and makes every other
 * symbol it defines local — each Rust module carries its own standard
 * library, and two in one program would otherwise collide. The system
 * libraries the archive needs at the final link are written beside it,
 * `<archive>.libs`, one linker flag per line, and `code build` adds them
 * (ticket 141). */

/* ---- Events: a whole particle, from where the event happens --------------
 *
 * For a module whose world calls *in* — a page, above all. While it is
 * drawing, the program says what an event should *mean*: a click on this
 * button is a `Remove { id = 7 }`, a keystroke in this box is a `Typed`. When
 * it happens the host sends that back, with whatever it learned in the
 * meantime, and the program's own handlers answer it. Nothing is held between
 * the drawing and the firing.
 *
 * It arrives as JSON, because the host is a page and that is the page's own
 * way of writing a value down: fill the buffer, then fire with the length.
 * The result must be an object with a `_class` string; anything else is
 * refused, and a refused event is one the program never hears about. A
 * handler is written for a particle, and half of one is not it.
 *
 * The buffer is the runtime's rather than an address of the host's, so that
 * nothing here trusts an address or a length that came from outside. That is
 * containment, not protection: a page and the module it loaded share one
 * linear memory and there is no boundary between them. It keeps an honest
 * host's mistake from becoming a corrupt value the program works with.
 *
 * One event at a time, since `code_event_fire` has returned before the next
 * can be sent.
 *
 * Not `code_module_set_inbound`, which is for a module speaking on its own
 * initiative into a program running a loop. This is the host calling in,
 * already inside a call. */
char *code_event_text(void);
long long code_event_text_capacity(void);
void code_event_fire(long long len);
/* The same, for a host that needs the answer: the handler's own particle is
 * written back over the buffer as JSON and its length returned, zero when
 * nothing answered. An event is told; this is asked, and the caller cannot
 * proceed without what comes back. It is what lets a page put a program in
 * the middle of something — a shell hosting another application answering,
 * in the language, whether the guest may do what it just asked to do. */
long long code_event_ask(long long len);

/* ---- JSON, for a module with a world on the other side of a wire ---------
 *
 * A module speaks particles, in both directions — that is its whole contract
 * with the language. A module whose world is a page or a socket has to put a
 * particle into bytes and read one back out, and every module doing that for
 * itself is the same code many times over, each with its own ideas about what
 * a fraction looks like.
 *
 * `code_json_write` answers how many bytes it wrote, or a negative number
 * when it would not fit (`cap` includes the terminating zero it writes).
 * `code_json_read` answers non-zero when the text was JSON; when it was not,
 * `out` is untouched, because half a value is worse than none. Both spell
 * numbers the way the language does, so one written by a page and one written
 * here agree.
 *
 * A module that never leaves the machine has no use for either. */
long long code_json_write(const CodeValue *v, char *out, long long cap);
int code_json_read(const char *text, long long len, CodeValue *out);

void code_number(CodeValue *out, double n);
/* Borrows `s` — the value keeps the pointer rather than the bytes, so `s`
 * must outlive it. Correct for a string literal, wrong for anything built at
 * runtime; use `code_str_owned` for those. */
void code_str(CodeValue *out, const char *s);
/* Copies `s`'s bytes into a heap-owned string. What a handler returning a
 * message built into a stack buffer must use — handing that buffer to
 * `code_str` leaves a dangling read the moment the handler returns. */
void code_str_owned(CodeValue *out, const char *s);
void code_bool(CodeValue *out, int b);
void code_null(CodeValue *out);
void code_array(CodeValue *out, void *items, long long len);
void code_object(CodeValue *out, const char **keys, void *values, long long len);
void code_copy(CodeValue *out, const CodeValue *src);
void code_move(CodeValue *out, CodeValue *src);
void code_retain(const CodeValue *v);
void code_release(CodeValue *v);
int code_values_equal(const CodeValue *a, const CodeValue *b);
int code_is_particle(const CodeValue *a, const char *name);
/* Builds `Exception { source, message, innerException }` — how a module
 * reports that it could not do the work. `inner` may be NULL. A module may
 * never end the application, so this replaces `code_runtime_error` for
 * everything a module can encounter; see docs/todo/errors-as-particles.md.
 * `source` and `message` are both copied. */
void code_make_exception(CodeValue *out, const char *source, const char *message,
                         const CodeValue *inner);
_Noreturn void code_runtime_error(const char *message);

/* ---- The invariant this list holds -------------------------------------
 *
 * **Nothing declared above can fail.** No function here sets `code_failed`,
 * runtime.c's failure flag, and that is a property of the list rather than a
 * coincidence: the flag is read only by the *host's* generated code, and a
 * `.so` module carries its own copy of this runtime, so a failure raised
 * inside a module would set the module's flag and go nowhere. Silently. A
 * fallible entry in this header is therefore not a sharp edge to document,
 * it is a hole. `tests/module_abi_cannot_fail.rs` enforces it.
 *
 * Four functions were removed for exactly that reason, none of them renamed
 * and none replaced:
 *
 * - `code_bool_value`, `code_assert` (2026-08-28, phase 3) — the compiler's
 *   own: one checks an `and`/`or` operand, the other is the `assert`
 *   statement. Neither was ever called by a module.
 * - `code_field`, `code_index` (2026-08-28) — these looked module-facing,
 *   and the language needs them to fail: `"abc".length` is an error, which
 *   the README states as a rule. A module needs the opposite, a total
 *   accessor, and one function cannot be both. Modules read fields by
 *   walking `keys`/`items`, which are right there in `CodeValue`;
 *   `code-native` does exactly that in `find_field`/`field`/`index`, in
 *   plain Rust with no call back into this ABI.
 *
 * What a module does when it cannot do its work is return
 * `code_make_exception`. It may never end the application. */

/* Addresses slot `index` of a `CODE_VALUE_SLOT_SIZE`-strided buffer — the
 * same convention `items`/`values` buffers use throughout this header.
 * `static inline` rather than declared `extern`: it's pure pointer
 * arithmetic with no state, so a header-only copy in each translation unit
 * that includes this file (host and every `.a` module alike) is simpler
 * than giving it one more externally-linked name to keep unique. */
static inline CodeValue *code_slot_at(void *base, long long index) {
    return (CodeValue *)((char *)base + index * CODE_VALUE_SLOT_SIZE);
}

#endif