#![allow(
clippy::indexing_slicing,
clippy::arithmetic_side_effects,
clippy::shadow_unrelated,
clippy::as_conversions
)]
use crate::rvm::program::{binaries_to_values, BinaryValue, Program};
use alloc::format;
use alloc::string::String;
use alloc::vec::Vec;
use bincode::config::standard;
use bincode::serde::decode_from_slice;
pub fn test_round_trip_serialization(program: &Program) -> Result<(), String> {
let serialized1 = program.serialize_binary()?;
if serialized1.len() >= 8 && serialized1.starts_with(&Program::MAGIC) {
let version = u32::from_le_bytes([
serialized1[4],
serialized1[5],
serialized1[6],
serialized1[7],
]);
if version == 2 && serialized1.len() >= 25 {
let entry_points_len = u32::from_le_bytes([
serialized1[8],
serialized1[9],
serialized1[10],
serialized1[11],
]) as usize;
let sources_len = u32::from_le_bytes([
serialized1[12],
serialized1[13],
serialized1[14],
serialized1[15],
]) as usize;
let literals_len = u32::from_le_bytes([
serialized1[16],
serialized1[17],
serialized1[18],
serialized1[19],
]) as usize;
let entry_points_start = 25;
let sources_start = entry_points_start + entry_points_len;
let literals_start = sources_start + sources_len;
let rule_tree_start = literals_start + literals_len;
if literals_len > 0 && serialized1.len() >= rule_tree_start {
match decode_from_slice::<Vec<BinaryValue>, _>(
&serialized1[literals_start..rule_tree_start],
standard(),
) {
Ok((decoded_literals, _)) => {
if binaries_to_values(decoded_literals).is_err() {
return Err(
"Failed to convert literal table from binary representation".into(),
);
}
}
Err(err) => {
return Err(format!(
"Failed to decode literal table with bincode: {}",
err
));
}
}
}
}
}
let deserialized = match Program::deserialize_binary(&serialized1)? {
crate::rvm::program::DeserializationResult::Complete(program) => program,
crate::rvm::program::DeserializationResult::Partial(program) => {
let info = format!(
"Deserialization resulted in partial program during round-trip test \
(instructions={}, literals={}, needs_recompilation={})",
program.instructions.len(),
program.literals.len(),
program.needs_recompilation()
);
return Err(info);
}
};
let serialized2 = deserialized.serialize_binary()?;
if serialized1 == serialized2 {
Ok(())
} else {
Err(format!(
"Round-trip serialization failed: serialized data differs. \
First serialization: {} bytes, Second: {} bytes",
serialized1.len(),
serialized2.len()
))
}
}