WorkerLib (serify v0.1.0)

Copy Markdown View Source

WorkerLib - Elixir implementation of the cross-language serialization test framework.

FieldMap is a plain Elixir map with string keys. Struct fields are nested maps. list<struct> fields are lists of maps.

Worker setup

Build the worker as an escript:

escript: [main_module: MyWorker]

Requires OTP 27 or newer. Older releases read stdin through a device that silently drops control characters, corrupting case data before a worker sees it.

Summary

Functions

Recursively walks a field map and collects a snapshot of every binary value.

Reports which field-map entries alias the input buffer. On the BEAM that is always none, so this always returns [].

Compares two maps and returns the keys whose values differ.

Look one (type, format) up across both registration spellings, returning the field-map-level {serialize, deserialize} the run loop calls, or nil. "*" matches any type/format and backs the single-type run/2 above.

Single-type worker: handles whatever type/format the runner asks for.

Multi-type worker. suite maps a type name to a %WorkerLib.Type{} — which carries the model its format functions speak — or to the older format name -> {serialize, deserialize} map, which still works and is what a type with no natural struct wants. A (type, format) that is not registered is reported to the runner as SKIPPED rather than failing the run.

Functions

collect_bin_snaps(fm, snaps)

Recursively walks a field map and collects a snapshot of every binary value.

decode_field_map(data, schema)

detect_zero_copy(fm, buf)

Reports which field-map entries alias the input buffer. On the BEAM that is always none, so this always returns [].

The other libraries answer this by XOR-flipping the input buffer and seeing which decoded fields change with it. Neither half of that is expressible here: a binary is immutable, so there is nothing to flip, and a decoded value can never alias the buffer it was read from in the first place.

dict_diffs(before, after_fm)

Compares two maps and returns the keys whose values differ.

encode_field_map(fm, schema)

resolve_registered(suite, type, format)

Look one (type, format) up across both registration spellings, returning the field-map-level {serialize, deserialize} the run loop calls, or nil. "*" matches any type/format and backs the single-type run/2 above.

Public, and separate from the run loop, so it can be tested without stdin: an unresolved (type, format) is reported SKIPPED, so a registration shape this silently fails to understand produces a green conformance run made entirely of SKIPs — indistinguishable from a worker that honestly does not implement the type. In Elixir that is not a hypothetical: a struct is a map, so the %Type{} clause below has to come before the is_map one or every model-registered type falls through it into a Map.get(%Type{}, "binary") that answers nil.

run(serialize_fn, deserialize_fn)

Single-type worker: handles whatever type/format the runner asks for.

run_suite(suite)

Multi-type worker. suite maps a type name to a %WorkerLib.Type{} — which carries the model its format functions speak — or to the older format name -> {serialize, deserialize} map, which still works and is what a type with no natural struct wants. A (type, format) that is not registered is reported to the runner as SKIPPED rather than failing the run.