///|
/// Compressed byte blocks, matching desert-rust's `write_compressed`/
/// `read_compressed`: `var_u32(uncompressed_length)`,
/// `var_u32(compressed_length)`, then raw DEFLATE data.
///
/// Note that the original Scala implementation writes only the uncompressed
/// length for empty arrays; desert-rust (followed here) always writes both
/// lengths. Decompression failures surface as `DeserializationFailure`.
///|
/// Write `data` DEFLATE-compressed into the output.
pub fn SerializationContext::write_compressed(
self : SerializationContext,
data : Bytes,
) -> Unit raise DesertFailure {
let len = data.length()
self.write_var_u32(len.reinterpret_as_uint())
let compressed = @flate.deflate_all(data.exact_view())
self.write_var_u32(compressed.length().reinterpret_as_uint())
if compressed.length() > 0 {
self.write_bytes(compressed.exact_view())
}
}
///|
/// Read a DEFLATE-compressed byte block.
pub fn DeserializationContext::read_compressed(
self : DeserializationContext,
) -> Bytes raise DesertFailure {
let uncompressed_len = self.read_var_u32().reinterpret_as_int()
let compressed_len = self.read_var_u32().reinterpret_as_int()
if compressed_len < 0 || uncompressed_len < 0 {
raise DeserializationFailure("Negative compressed block length")
}
if compressed_len == 0 {
if uncompressed_len != 0 {
raise DeserializationFailure(
"Empty compressed block with non-zero uncompressed length",
)
}
return Bytes::new(0)
}
let compressed = self.input.read_bytes(compressed_len)
let res : Result[Bytes, @flate.InflateError] = Ok(
@flate.inflate_exact(compressed.exact_view(), max_output=uncompressed_len),
) catch {
e => Err(e)
}
match res {
Ok(data) =>
if data.length() != uncompressed_len {
raise DeserializationFailure(
"Compressed block length mismatch: expected \{uncompressed_len}, got \{data.length()}",
)
} else {
data
}
Err(_) => raise DeserializationFailure("Failed to decompress data block")
}
}
///|
/// Round-trip helpers for testing and ad-hoc use.
pub fn compress_bytes(data : Bytes) -> Bytes raise DesertFailure {
let out = ByteOutput::new()
let ctx = SerializationContext::new(
out,
SerializerState::new(),
Options::default(),
)
ctx.write_compressed(data)
out.to_bytes()
}
///|
pub fn decompress_bytes(data : Bytes) -> Bytes raise DesertFailure {
let ctx = DeserializationContext::new(
BinaryInput::new(data),
SerializerState::new(),
Options::default(),
)
ctx.read_compressed()
}