9.3 The OxL wire format
The OxL binary format is protobuf 3 encoding with the following mappings:
| OxL | protobuf |
|---|---|
data | message |
enum without fields | enum (the value 0 is reserved for "unknown") |
enum with fields, union A | B | oneof, one message field per variant or type |
T? | optional field; none is the absence of the field |
i8 i16 i32, u8 u16 u32 | int32 / uint32 (sint32 with @zigzag) |
i64, u64 | int64 / uint64 |
i128, u128 | bytes (16 bytes, little-endian) |
f32, f64 | float / double |
char | uint32 |
str | string |
bytes | bytes |
List<T>, [T; N] | repeated (packed for numbers) |
Map<K, V> | map (K — integers, str, bool); otherwise repeated pairs |
Set<T> | repeated |
| tuple | message with fields 1..n |
distinct T, refined T | as T |
Duration, Time | google.protobuf.Duration, google.protobuf.Timestamp |
Date, LocalDateTime, ZonedTime | message oxl.Date, oxl.LocalDateTime, oxl.ZonedTime |
ActorRef<A> | message oxl.ActorRef |
secret<T> | as T; allowed only in the binary format over TLS and in an encrypted journal; the JSON encoder rejects such fields (a compile error when the format is statically known, otherwise EncodeError) |
JSON is the canonical JSON mapping of protobuf.
MessagePack and CBOR (formats.msgpack, formats.cbor; D-8053; DIV-006; D-7600, D-7601) are self-describing formats; they encode a value according to the schema of the type as follows:
| OxL | MessagePack / CBOR |
|---|---|
data | map; keys are field names (text); a none field is not written, nil on reading is accepted as none |
| integers up to 64 bits | native integer in the shortest form (a non-negative signed value is written as unsigned; CBOR major type 0/1) |
i128, u128 | 16 bytes little-endian (bin / byte string) |
f32, f64 | single / double precision float (the CBOR decoder also reads half precision; an integer is accepted as a floating-point number) |
str, bytes | str (text string, UTF-8 is checked) / bin (byte string) |
List<T>, Set<T>, [T; N], tuple | array |
Map<K, V> | map with keys of any serialisable type (with a duplicate key the last one wins) |
enum without fields | the variant name (an unknown value of an @open enum — its number) |
enum with fields, union of several types | a map of one entry {Variant: {fields}} |
T? | the value or nil |
() | empty map |
Duration, LocalDateTime | an integer number of nanoseconds; Date — an integer number of days |
Time | MessagePack: the timestamp extension (type −1; the 32-, 64- or 96-bit form, the shortest that fits); CBOR: tag 0 with RFC 3339 text (the decoder also accepts tag 1) |
ActorRef<A> | the address text, as in JSON |
distinct, refined, @repr, view | as in the other formats; the checks are run on decoding |
Decoders accept what other implementations write: any integer width, CBOR with indefinite length, bignums (tag 2/3) that fit into 64 bits, other tags (transparently), undefined as nil, unknown keys (skipped). They reject: a truncated document, extra bytes after the value, reserved bytes, invalid UTF-8, an integer out of the range of the type (Invalid), nesting deeper than 128, a declared length greater than the rest of the input. @codec(…) is selected for the formats oxl and json; MessagePack and CBOR use the default representation of the field. secret<T> is rejected in these formats (EncodeError.Secret), as in JSON.
Related diagnostics
See also
Source: docs/spec/oxl-standard.en.md