Binary serialization with schema evolution, wire-compatible with desert (Scala) and desert-rust
// Serialize / deserialize (raises @desert.DesertFailure on errors)
///|
let bytes = @desert.serialize_to_bytes(value)
///|
let back : MyType = @desert.deserialize_exhaustive(bytes)// Derive codecs for your types
///|
#desert(binary_codec, evolution(FieldAdded("extra", "default")))
struct MyRecord {
base : Int32
extra : String
}# from a clone of this repository (a MoonBit workspace):
moon run codegen -- <your-package-directory>moon.mod module metadata (published as vigoo/desert)
moon.pkg the root package — the library itself
error.mbt DesertFailure taxonomy
binary_input.mbt read cursor (BinaryInput)
binary_output.mbt write sink (BinaryOutput + ByteOutput)
codecs_*.mbt primitive/string/collection/tuple codecs
evolution.mbt evolution metadata + wire codes
adt_writer.mbt evolved-record writer engine
adt_reader.mbt evolved-record reader engine
state.mbt per-session dedup state
registry.mbt type registry
compressed.mbt DEFLATE byte blocks
facade.mbt top-level serialize/deserialize
*_test.mbt / *_wbtest.mbt blackbox / whitebox tests
codegen/ desert-codegen generator (executable package)
codegen_demo/ generated-code golden test package
docs/ documentation chaptersmoon check # type check (0 warnings policy)
moon test # byte-exact, evolution, registry, property tests
moon bench # micro benchmarks
moon run codegen -- codegen_demo # regenerate the demo codecs
moon info && moon fmt # refresh interface + formatpub(open) trait BinaryCodec {
}pub(open) trait BinaryDeserializer {
fn deserialize(ctx : DeserializationContext) -> Self raise DesertFailure
}impl BinaryDeserializer for Unitimpl BinaryDeserializer for Boolimpl BinaryDeserializer for Byteimpl BinaryDeserializer for Charimpl BinaryDeserializer for Intimpl BinaryDeserializer for Int16impl BinaryDeserializer for Int64impl BinaryDeserializer for UIntimpl BinaryDeserializer for UInt16impl BinaryDeserializer for UInt64impl BinaryDeserializer for Floatimpl BinaryDeserializer for Doubleimpl BinaryDeserializer for Stringimpl BinaryDeserializer for Option[T]impl BinaryDeserializer for Bytesimpl BinaryDeserializer for Array[T]fn[T : BinaryDeserializer] deserialize(ctx : DeserializationContext) -> Array[T] raise DesertFailureimpl BinaryDeserializer for Map[K, V]fn[K : BinaryDeserializer + Hash + Eq, V : BinaryDeserializer] deserialize(ctx : DeserializationContext) -> Map[K, V] raise DesertFailureimpl BinaryDeserializer for Result[T, E]fn[T : BinaryDeserializer, E : BinaryDeserializer] deserialize(ctx : DeserializationContext) -> Result[T, E] raise DesertFailureimpl BinaryDeserializer for HashMap[K, V]fn[K : BinaryDeserializer + Hash + Eq, V : BinaryDeserializer] deserialize(ctx : DeserializationContext) -> HashMap[K, V] raise DesertFailureimpl BinaryDeserializer for HashSet[T]fn[T : BinaryDeserializer + Hash + Eq] deserialize(ctx : DeserializationContext) -> HashSet[T] raise DesertFailureimpl BinaryDeserializer for Tuple2[A, B]fn[A : BinaryDeserializer, B : BinaryDeserializer] deserialize(ctx : DeserializationContext) -> (A, B) raise DesertFailureimpl BinaryDeserializer for Tuple3[A, B, C]fn[A : BinaryDeserializer, B : BinaryDeserializer, C : BinaryDeserializer] deserialize(ctx : DeserializationContext) -> (A, B, C) raise DesertFailureimpl BinaryDeserializer for Tuple4[A, B, C, D]fn[A : BinaryDeserializer, B : BinaryDeserializer, C : BinaryDeserializer, D : BinaryDeserializer] deserialize(ctx : DeserializationContext) -> (A, B, C, D) raise DesertFailureimpl BinaryDeserializer for Tuple5[A, B, C, D, E]fn[A : BinaryDeserializer, B : BinaryDeserializer, C : BinaryDeserializer, D : BinaryDeserializer, E : BinaryDeserializer] deserialize(ctx : DeserializationContext) -> (A, B, C, D, E) raise DesertFailureimpl BinaryDeserializer for Tuple6[A, B, C, D, E, F]fn[A : BinaryDeserializer, B : BinaryDeserializer, C : BinaryDeserializer, D : BinaryDeserializer, E : BinaryDeserializer, F : BinaryDeserializer] deserialize(ctx : DeserializationContext) -> (A, B, C, D, E, F) raise DesertFailurepub(open) trait BinaryOutput {
fn write_u8(Self, Byte) -> Unit raise DesertFailure
fn write_bytes(Self, BytesView) -> Unit raise DesertFailure
fn write_i8(Self, Int) -> Unit raise DesertFailure = _
fn write_u16(Self, UInt16) -> Unit raise DesertFailure = _
fn write_i16(Self, Int) -> Unit raise DesertFailure = _
fn write_u32(Self, UInt) -> Unit raise DesertFailure = _
fn write_i32(Self, Int) -> Unit raise DesertFailure = _
fn write_u64(Self, UInt64) -> Unit raise DesertFailure = _
fn write_i64(Self, Int64) -> Unit raise DesertFailure = _
fn write_f32(Self, Float) -> Unit raise DesertFailure = _
fn write_f64(Self, Double) -> Unit raise DesertFailure = _
fn write_var_u32(Self, UInt) -> Unit raise DesertFailure = _
fn write_var_i32(Self, Int) -> Unit raise DesertFailure = _
fn write_string_utf8(Self, StringView) -> Unit raise DesertFailure = _
}pub(open) trait BinarySerializer {
fn serialize(Self, ctx : SerializationContext) -> Unit raise DesertFailure
}impl BinarySerializer for Unitimpl BinarySerializer for Boolimpl BinarySerializer for Byteimpl BinarySerializer for Charimpl BinarySerializer for Intimpl BinarySerializer for Int16impl BinarySerializer for Int64impl BinarySerializer for UIntimpl BinarySerializer for UInt16impl BinarySerializer for UInt64impl BinarySerializer for Floatimpl BinarySerializer for Doubleimpl BinarySerializer for Stringimpl BinarySerializer for Option[T]fn[T : BinarySerializer] serialize(self : T?, ctx : SerializationContext) -> Unit raise DesertFailureimpl BinarySerializer for Bytesimpl BinarySerializer for Array[T]fn[T : BinarySerializer] serialize(self : Array[T], ctx : SerializationContext) -> Unit raise DesertFailureimpl BinarySerializer for Map[K, V]fn[K : BinarySerializer, V : BinarySerializer] serialize(self : Map[K, V], ctx : SerializationContext) -> Unit raise DesertFailureimpl BinarySerializer for Result[T, E]fn[T : BinarySerializer, E : BinarySerializer] serialize(self : Result[T, E], ctx : SerializationContext) -> Unit raise DesertFailureimpl BinarySerializer for HashMap[K, V]fn[K : BinarySerializer, V : BinarySerializer] serialize(self : HashMap[K, V], ctx : SerializationContext) -> Unit raise DesertFailureimpl BinarySerializer for HashSet[T]fn[T : BinarySerializer] serialize(self : HashSet[T], ctx : SerializationContext) -> Unit raise DesertFailureimpl BinarySerializer for Tuple2[A, B]fn[A : BinarySerializer, B : BinarySerializer] serialize(self : (A, B), ctx : SerializationContext) -> Unit raise DesertFailureimpl BinarySerializer for Tuple3[A, B, C]fn[A : BinarySerializer, B : BinarySerializer, C : BinarySerializer] serialize(self : (A, B, C), ctx : SerializationContext) -> Unit raise DesertFailureimpl BinarySerializer for Tuple4[A, B, C, D]fn[A : BinarySerializer, B : BinarySerializer, C : BinarySerializer, D : BinarySerializer] serialize(self : (A, B, C, D), ctx : SerializationContext) -> Unit raise DesertFailureimpl BinarySerializer for Tuple5[A, B, C, D, E]fn[A : BinarySerializer, B : BinarySerializer, C : BinarySerializer, D : BinarySerializer, E : BinarySerializer] serialize(self : (A, B, C, D, E), ctx : SerializationContext) -> Unit raise DesertFailureimpl BinarySerializer for Tuple6[A, B, C, D, E, F]fn[A : BinarySerializer, B : BinarySerializer, C : BinarySerializer, D : BinarySerializer, E : BinarySerializer, F : BinarySerializer] serialize(self : (A, B, C, D, E, F), ctx : SerializationContext) -> Unit raise DesertFailurepub(open) trait RegisteredValue {
fn registered_type_name(Self) -> String
fn serialize_registered(Self, SerializationContext) -> Unit raise DesertFailure
}pub(all) suberror DesertFailure {
FailedToReadInput(String)
InputEndedUnexpectedly
FailedToWriteOutput(String)
SerializationFailure(String)
DeserializationFailure(String)
DeserializingNonExistingChunk(Int)
NonOptionalFieldSerializedAsNone(String)
UnknownFieldReferenceInEvolutionStep(String)
UnknownSerializedEvolutionStep(Int)
InvalidStringId(Int)
FieldRemovedInSerializedVersion(String)
FieldWithoutDefaultValueIsMissing(String)
TypeNotRegistered(String)
InvalidTypeId(Int)
SerializationUpcastError(String, String, String)
InvalidConstructorName(String, String)
InvalidConstructorId(Int, String)
InvalidRefId(Int)
SerializingTransientConstructor(String)
UnsupportedCharacter(Char)
FailedToDecodeCharacter(UInt16)
} derive(Debug)impl Show for DesertFailurepub struct AdtMetadata {
// private fields
}pub struct AdtReader {
// private fields
}fn AdtReader::new(metadata : AdtMetadata, ctx : DeserializationContext, stored_version : Int) -> AdtReader raise DesertFailurefn[T : BinaryDeserializer] AdtReader::read_field(self : AdtReader, field_name : String, default : T?) -> T raise DesertFailurefn[T : BinaryDeserializer] AdtReader::read_optional_field(self : AdtReader, field_name : String, default : T??) -> T? raise DesertFailurepub struct AdtWriter {
// private fields
}fn AdtWriter::new(metadata : AdtMetadata, ctx : SerializationContext) -> AdtWriter raise DesertFailurefn AdtWriter::new_v0(metadata : AdtMetadata, ctx : SerializationContext) -> AdtWriter raise DesertFailurefn AdtWriter::write_constructor(self : AdtWriter, constructor_idx : UInt, serialize_case : (SerializationContext) -> Unit raise DesertFailure) -> Unit raise DesertFailurefn[T : BinarySerializer] AdtWriter::write_field(self : AdtWriter, field_name : String, value : T) -> Unit raise DesertFailureimpl BinarySerializer for ArrayOfIntpub struct BinaryInput {
// private fields
}pub struct ByteOutput {
// private fields
}impl BinaryOutput for ByteOutputimpl BinaryDeserializer for DeduplicatedStringimpl BinarySerializer for DeduplicatedStringfn DeduplicatedString::deserialize(ctx : DeserializationContext) -> DeduplicatedString raise DesertFailurefn DeduplicatedString::serialize(self : DeduplicatedString, ctx : SerializationContext) -> Unit raise DesertFailurefn DeserializationContext::new(input : BinaryInput, state : SerializerState, options : Options) -> DeserializationContextfn DeserializationContext::push_region(self : DeserializationContext, start : Int, size : Int) -> Unitfn[T : BinaryDeserializer] DeserializationContext::read(self : DeserializationContext) -> T raise DesertFailurefn DeserializationContext::read_bytes(self : DeserializationContext, count : Int) -> Bytes raise DesertFailurefn DeserializationContext::read_bytes_view(self : DeserializationContext, count : Int) -> BytesView raise DesertFailurefn DeserializationContext::read_compressed(self : DeserializationContext) -> Bytes raise DesertFailurefn[T : BinaryDeserializer] DeserializationContext::read_flexible_array(self : DeserializationContext) -> Array[T] raise DesertFailurefn[T : BinaryDeserializer] DeserializationContext::read_optional_value(self : DeserializationContext) -> T? raise DesertFailurefn DeserializationContext::read_string_payload(self : DeserializationContext) -> String raise DesertFailurefn DeserializationContext::read_unknown(self : DeserializationContext, registry : TypeRegistry) -> RegisteredBox raise DesertFailurefn DeserializationContext::skip(self : DeserializationContext, count : Int) -> Unit raise DesertFailurepub(all) enum Evolution {
InitialVersion
FieldAdded(String)
FieldMadeOptional(String)
FieldRemoved(String)
FieldMadeTransient(String)
}pub struct RegisteredEntry {
id : Int
type_name : String
deserialize : (DeserializationContext) -> &RegisteredValue raise DesertFailure
}fn SerializationContext::new(output : &BinaryOutput, state : SerializerState, options : Options) -> SerializationContextfn[T : BinarySerializer] SerializationContext::write(self : SerializationContext, value : T) -> Unit raise DesertFailurefn SerializationContext::write_bytes(self : SerializationContext, bytes : BytesView) -> Unit raise DesertFailurefn SerializationContext::write_compressed(self : SerializationContext, data : Bytes) -> Unit raise DesertFailurefn SerializationContext::write_f32(self : SerializationContext, value : Float) -> Unit raise DesertFailurefn SerializationContext::write_f64(self : SerializationContext, value : Double) -> Unit raise DesertFailurefn SerializationContext::write_i16(self : SerializationContext, value : Int) -> Unit raise DesertFailurefn SerializationContext::write_i32(self : SerializationContext, value : Int) -> Unit raise DesertFailurefn SerializationContext::write_i64(self : SerializationContext, value : Int64) -> Unit raise DesertFailurefn SerializationContext::write_i8(self : SerializationContext, value : Int) -> Unit raise DesertFailurefn[T : BinarySerializer] SerializationContext::write_iter_unknown_size(self : SerializationContext, iter : Iter[T]) -> Unit raise DesertFailurefn SerializationContext::write_string_payload(self : SerializationContext, s : String) -> Unit raise DesertFailurefn SerializationContext::write_string_utf8(self : SerializationContext, s : StringView) -> Unit raise DesertFailurefn SerializationContext::write_u16(self : SerializationContext, value : UInt16) -> Unit raise DesertFailurefn SerializationContext::write_u32(self : SerializationContext, value : UInt) -> Unit raise DesertFailurefn SerializationContext::write_u64(self : SerializationContext, value : UInt64) -> Unit raise DesertFailurefn SerializationContext::write_u8(self : SerializationContext, byte : Byte) -> Unit raise DesertFailurefn SerializationContext::write_unknown(self : SerializationContext, registry : TypeRegistry, value : &RegisteredValue) -> Unit raise DesertFailurefn SerializationContext::write_var_i32(self : SerializationContext, value : Int) -> Unit raise DesertFailurefn SerializationContext::write_var_u32(self : SerializationContext, value : UInt) -> Unit raise DesertFailurepub struct SerializerState {
// private fields
}pub struct TypeRegistry {
// private fields
}pub struct TypeRegistryBuilder {
// private fields
}let registry = TypeRegistryBuilder::new()
.register::<MyTypeA>(fn(ctx) { MyTypeA::deserialize(ctx) })
.register_placeholder()
.register::<MyTypeB>(fn(ctx) { MyTypeB::deserialize(ctx) })
.freeze()fn TypeRegistryBuilder::register(self : TypeRegistryBuilder, type_name : String, deserialize : (DeserializationContext) -> &RegisteredValue raise DesertFailure) -> TypeRegistryBuilder raise DesertFailurefn[T : BinaryDeserializer] deserialize_exhaustive(data : Bytes, options? : Options) -> T raise DesertFailurefn deserialize_unknown_from_bytes(data : Bytes, registry : TypeRegistry, options? : Options) -> RegisteredBox raise DesertFailurefn[T : BinarySerializer] serialize_to_bytes(value : T, options? : Options) -> Bytes raise DesertFailurefn[T : BinarySerializer] serialize_to_output(value : T, out : ByteOutput, options? : Options) -> Unit raise DesertFailurefn[T : RegisteredValue] serialize_unknown_to_bytes(value : T, registry : TypeRegistry, options? : Options) -> Bytes raise DesertFailurefn utf8_byte_length(s : String) -> Intfn write_utf8(s : String, out : FixedArray[Byte], offset : Int) -> IntInstall
Download zipBinary serialization with schema evolution, wire-compatible with desert (Scala) and desert-rust