Serialization
Serialization
A value describes itself through Serialize and Deserialize without naming a
format. A format implements Serializer and Deserializer once, and the two
sides meet in the middle.
[public] trait Serialize {
fn serialize(serializer: Serializer);
}
[public] trait Deserialize {
[static] fn deserialize(deserializer: Deserializer) => Self?;
}deserialize is [static], so it is called on the type rather than an instance,
and it returns Self? because decoding can fail.
The format side:
[public] trait Serializer {
fn begin_object(); fn end_object(); fn field(name: string);
fn begin_array(); fn end_array();
fn put_number(value: number); fn put_string(value: string);
fn put_bool(value: bool); fn put_null();
}
[public] trait Deserializer {
fn enter_field(name: string) => bool; fn exit_field();
fn length() => number?;
fn enter_index(index: number) => bool; fn exit_index();
fn get_number() => number?; fn get_string() => string?;
fn get_bool() => bool?; fn is_null() => bool;
fn get_identifier() => string?;
}Every read returns an optional: None means the value was absent or had the
wrong shape.
number, bool, and string implement both traits already. char does not.
The [serial] derive
Writing both methods by hand is mechanical, so [serial] generates them:
[serial] class Settings {
theme: string
width: number
tags: Array<string>
nickname: string?
}The generated code handles each field by its declared type:
- An optional is written only when present, and on read starts at
Noneand is filled in only if the field exists. A missing key is not an error. - An array writes a field, an array body, and each element; on read it requires the field, reads the length, and decodes each index.
- Everything else, including nested
[serial]classes and enums, delegates to that type's ownserialize/deserialize. A missing required field produces an error carrying the field name.
Enums have no methods of their own, so the compiler routes them through generated helpers. A variant serializes as its identifier string, and an unknown string on read is an error.
With JSON
let text: string = json::stringify(settings)
let restored: Settings? = deserialize<Settings>(json::read(text))json::stringify and json::serialize take any Serialize. json::read and
json::reader produce a Deserializer. The deserialize<T>(source) built-in
lowers to T::deserialize(source) and yields T?.
Worth knowing
This machinery is complete but is not yet exercised anywhere in the shipped
toolkit: no shipped type uses [serial], and real code builds JSON by
interpolation and escapes leaf strings with new json::JsonString(x).to_string().
Both approaches work; the derive is the better one for a type with more than a
couple of fields.