9.5 User-defined serialisers
Level 1 — representation through another type (Repr), acts in all formats and in schemas:
@repr(i64)
data Money { minor: i64 }
impl Repr<i64> for Money {
fn toRepr() -> i64 => minor
static fn fromRepr(v: i64) -> Money | DecodeError => Money{ minor: v }
}Level 2 — a codec per type or field, including for a single format:
@explicit interface Codec<T> {
static fn encode(x: &T, w: &var Encoder) -> () | EncodeError
static fn decode(r: &var Decoder) -> T | DecodeError
static fn schema() -> Schema // for oxl export
}
data Event {
@codec(json: Iso8601) at: Time // in JSON an ISO 8601 string, in binary the default
@codec(Base64Url) token: bytes // in all formats
}
@codec(GeoHashCodec) data Point { lat: f64; lon: f64 }@codec(C)— for all formats;@codec(json: C1, oxl: C2)— per format.CMUST implementCodec<T>for the field type.Encoder/Decoderis the abstract interface of a format:writeI64,writeStr,beginMessage,field(tag, name), etc. (part II,std.ser).- Changing a field's codec is changing the field's type per table 9.2: the compiler compares the
schema()of the old and the new codec.
Encoder and Decoder are interfaces of std.ser; written as a type (w: &var Encoder, -> Decoder) they mean dyn Encoder and dyn Decoder. In Encoder all methods have (empty) default implementations: beginMessage(name), endMessage(), field(tag, name), writeI64, writeU64, writeF64, writeBool, writeStr, writeBytes, writeNull, beginList(len), endList(), beginMap(len), endMap() and finish() -> bytes (the only way to return the accumulated bytes). Decoder contains the reading methods paired with the writing ones; the default implementations report DecodeError.Malformed.
Level 3 — a custom format. A type that implements the interface Format (name() -> str, encoder() -> Encoder, decoder(input: bytes) -> Decoder) is registered by the comptime call std.ser.register(MyFormat) and becomes available as encode<T>(x, MyFormat). The implementation is built on the Encoder/Decoder events and on reflect(T) (§15). The name Format in the argument position of encode/decode denotes both the enumeration of the built-in formats (Format.Json) and the interface Format for implementors; they are distinguished by position: impl Format for T implements the interface (D-8053; DIV-007; D-7620).
Implementation-defined. Decoding with a custom format (D-8053; DIV-007; D-7621).
decode<T>(b, MyFormat)walks the typeTand pulls the values from theDecoderin the orderencodewould have pushed them to theEncoder(D-8344):readI64/readU64/readF64/readBool/readStr/readBytesfor scalars,beginMessage/nextField/endMessagefor messages (a field is found by itstag, by its name whentag == 0),beginList/endListandbeginMap/endMapfor collections,readNullforT?. Limits of this implementation: theDecoderhas no way to skip a value, so an unknown field of a message is an error (Invalid); an unknown number of an openenumis not read. Encoding and decoding with a custom format are supported.
Related diagnostics
See also
Source: docs/spec/oxl-standard.en.md