OxL Справочник OxL
РусскийEnglish

9.5 Пользовательские сериализаторы

Уровень 1 — представление через другой тип (Repr), действует во всех форматах и в схемах:

oxl
@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 }
}

Уровень 2 — кодек на тип или поле, в том числе для отдельного формата:

oxl
@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               // для oxl export
}

data Event {
  @codec(json: Iso8601) at: Time            // в JSON — строка ISO 8601, в бинарном — по умолчанию
  @codec(Base64Url) token: bytes             // во всех форматах
}

@codec(GeoHashCodec) data Point { lat: f64; lon: f64 }
  • @codec(C) — для всех форматов; @codec(json: C1, oxl: C2) — по форматам. C ДОЛЖЕН реализовывать Codec<T> для типа поля.
  • Encoder/Decoder — абстрактный интерфейс формата: writeI64, writeStr, beginMessage, field(tag, name) и т. д. (часть II, std.ser).
  • Изменение кодека поля — изменение типа поля по таблице 9.2: компилятор сравнивает schema() старого и нового кодека.

Encoder и Decoder — интерфейсы std.ser; написанные как тип (w: &var Encoder, -> Decoder), означают dyn Encoder и dyn Decoder. В Encoder все методы имеют реализации по умолчанию (пустые): beginMessage(name), endMessage(), field(tag, name), writeI64, writeU64, writeF64, writeBool, writeStr, writeBytes, writeNull, beginList(len), endList(), beginMap(len), endMap() и finish() -> bytes (единственный способ вернуть накопленные байты). Decoder содержит методы чтения, парные к записи; реализации по умолчанию сообщают DecodeError.Malformed.

Уровень 3 — собственный формат. Тип, реализующий интерфейс Format (name() -> str, encoder() -> Encoder, decoder(input: bytes) -> Decoder), регистрируется comptime-вызовом std.ser.register(MyFormat) и становится доступен как encode<T>(x, MyFormat). Реализация строится на событиях Encoder/Decoder и reflect(T) (§15). Имя Format в позиции аргумента encode/decode обозначает и перечисление встроенных форматов (Format.Json), и интерфейс Format для реализаций; различаются по позиции: impl Format for T реализует интерфейс (D-8053; DIV-007; D-7620).

Определяется реализацией. Декодирование собственным форматом (D-8053; DIV-007; D-7621). decode<T>(b, MyFormat) обходит тип T и запрашивает значения у Decoder в том порядке, в котором encode передал бы их Encoder (D-8344): readI64/readU64/readF64/readBool/readStr/readBytes для скаляров, beginMessage/nextField/endMessage для сообщений (поле находится по tag, при tag == 0 — по имени), beginList/endList и beginMap/endMap для коллекций, readNull для T?. Ограничения этой реализации: у Decoder нет пропуска значения, поэтому неизвестное поле сообщения — ошибка (Invalid); неизвестное число открытого enum не читается. Кодирование и декодирование собственным форматом поддерживаются.

schema-attr

См. также

Исходник: docs/spec/oxl-standard.md