///|
/// Per-call context for serialization: the output sink, the session state
/// (string dedup / reference tracking) and the format options.
///
/// The active output can be swapped by the evolution machinery
/// (`push_output`/`pop_output`) so that a record's fields are captured into
/// per-generation chunk buffers.
pub struct SerializationContext {
priv mut output : &BinaryOutput
priv mut output_stack : Array[&BinaryOutput]
state : SerializerState
options : Options
}
///|
/// Per-call context for deserialization: the input cursor, the session state
/// and the format options. The state table is filled as strings are read.
pub struct DeserializationContext {
input : BinaryInput
priv mut state : SerializerState
options : Options
}
///|
/// Serialization is implemented as a single method taking the context;
/// failures are raised as `DesertFailure`.
pub(open) trait BinarySerializer {
fn serialize(Self, ctx : SerializationContext) -> Unit raise DesertFailure
}
///|
/// Deserialization mirrors `BinarySerializer`: the method returns the
/// decoded value of its own type.
pub(open) trait BinaryDeserializer {
fn deserialize(ctx : DeserializationContext) -> Self raise DesertFailure
}
///|
/// A type that can be both serialized and deserialized. Implement this
/// (together with the two component traits) for your own types, or let
/// `desert-codegen` generate the implementations.
pub(open) trait BinaryCodec {}
///|
/// Write a value of any `BinarySerializer` type into the context.
pub fn[T : BinarySerializer] SerializationContext::write(
self : SerializationContext,
value : T,
) -> Unit raise DesertFailure {
value.serialize(self)
}
///|
/// Read a value of any `BinaryDeserializer` type from the context.
pub fn[T : BinaryDeserializer] DeserializationContext::read(
self : DeserializationContext,
) -> T raise DesertFailure {
T::deserialize(self)
}
///|
/// Construct a serialization context over a custom output sink.
pub fn SerializationContext::new(
output : &BinaryOutput,
state : SerializerState,
options : Options,
) -> SerializationContext {
{ output, output_stack: [], state, options, }
}
///|
/// Construct a deserialization context over a custom input.
pub fn DeserializationContext::new(
input : BinaryInput,
state : SerializerState,
options : Options,
) -> DeserializationContext {
{ input, state, options, }
}
///|
/// Point a deserialization context at new data: resets the input cursor and
/// installs a fresh session state (dedup ids never leak across calls).
/// Lets hot loops reuse the context instead of paying per-call allocation.
pub fn DeserializationContext::reset_input(
self : DeserializationContext,
data : Bytes,
) -> Unit {
self.input.reset_input(data)
self.state = SerializerState::new()
}
///|
/// The per-call format options.
pub fn SerializationContext::options(self : SerializationContext) -> Options {
self.options
}
///|
/// The per-call format options.
pub fn DeserializationContext::options(
self : DeserializationContext,
) -> Options {
self.options
}