uce/docs/wasm-phase1-dvalue-abi.md

4.1 KiB

WASM Phase 1: DValue C ABI and UCEB1

Phase 1 freezes the native DValue ABI that the future WASM core and units use as their shared structured-value contract. The implementation is in src/lib/dvalue.{h,cpp} and is available in the native runtime before any WASM backend is enabled.

Opaque handle

typedef struct DValue uce_dvalue;

uce_dvalue* is a borrowed pointer owned by the active request/workspace. It must not be freed by ABI callers and it must not be retained beyond that workspace lifetime.

Accessors

uce_dvalue* uce_dv_root(void);
uce_dvalue* uce_dv_get(uce_dvalue* value, const char* key, size_t key_len);
uce_dvalue* uce_dv_find(uce_dvalue* value, const char* key, size_t key_len);
const char* uce_dv_value(uce_dvalue* value, size_t* len_out);
void uce_dv_set_value(uce_dvalue* value, const char* bytes, size_t len);
size_t uce_dv_count(uce_dvalue* value);
int uce_dv_is_list(uce_dvalue* value);
  • uce_dv_root() returns the current native request's context.call root. The WASM core will later map this to the decoded request context root.
  • uce_dv_get() creates the child if absent. uce_dv_find() returns NULL if absent.
  • String inputs and outputs are length-delimited and binary-safe.
  • uce_dv_value() returns a borrowed pointer valid until the next ABI value call on the same thread.
  • Bad NULL inputs return NULL, zero, or no-op rather than trapping.

Iteration

typedef struct uce_dv_iter { size_t position; size_t reserved[3]; } uce_dv_iter;

uce_dv_iter uce_dv_iter_begin(uce_dvalue* value);
int uce_dv_iter_next(uce_dvalue* value, uce_dv_iter* iter,
                     const char** key_out, size_t* key_len_out,
                     uce_dvalue** child_out);

Map iteration follows DValue's native order. List-shaped maps iterate in numeric index order (0, 1, ...), matching DValue::each(), dv_values(), and the serializers. The reserved iterator fields are caller-opaque and must be zero-preserved by callers that copy the iterator; they provide ABI headroom for future non-linear keyed-map iteration without changing the struct size.

UCEB1 wire format

UCEB1 is the membrane/cross-instance binary DValue encoding.

document := "UCEB" version node
version  := 0x01
node     := flags scalar children
flags    := u8 bitset; bit0 = list-shaped map
scalar   := varuint length, bytes
children := varuint count, count * (key, node)
key      := varuint length, bytes

Varuint is unsigned LEB128. Strings are byte sequences; the codec does not assume NUL termination and preserves embedded NUL bytes. The Phase 1 layout stores scalar values as their native string representation plus child nodes and the list-shape flag. Floating-point values use max_digits10 precision so numeric scalars can round-trip through the string form. Pointer/reference identity is intentionally not part of the wire contract; pointer nodes encode as an empty scalar rather than leaking process addresses. An empty non-list map has no wire distinction from an empty scalar in UCEB1 v1. Documents that contain both scalar bytes and child nodes are reserved for future use; the v1 decoder accepts the children and ignores the scalar.

Codec APIs

C++/UCE-visible helpers:

String ucb_encode(const DValue& value);
DValue ucb_decode(const String& encoded);
bool ucb_decode(const String& encoded, DValue& out, String* error_out = 0);

C ABI helpers:

size_t uce_dv_encode(uce_dvalue* value, char* buf, size_t cap);
uce_dvalue* uce_dv_decode(const char* buf, size_t len);
const char* uce_dv_last_error(void);

uce_dv_encode() returns the required byte length even when buf is NULL or cap is zero. uce_dv_decode() returns a thread-local decoded root, or NULL with uce_dv_last_error() populated. The returned decoded root is valid until the next uce_dv_decode() call on the same thread. Decoding rejects documents deeper than 1024 nested nodes so malformed input cannot recurse without bound.

Test coverage

site/tests/core.uce covers:

  • UCEB1 round-trip for maps, nested values, lists, empty lists, and embedded NUL scalar bytes.
  • C ABI get/find/value/count/list/iteration/encode/decode behavior.