use crate::module::inner::ModuleInner;
use crate::{Error, Result};
const MAGIC: &[u8; 8] = b"submwc01";
const ARTIFACT_VERSION: u32 = 18;
pub(crate) fn encode(inner: &ModuleInner) -> Result<Vec<u8>> {
let mut out = Vec::new();
out.extend_from_slice(MAGIC);
out.extend_from_slice(&ARTIFACT_VERSION.to_le_bytes());
let body = postcard::to_allocvec(inner)
.map_err(|e| Error::msg(format!("failed to serialize module: {e}")))?;
out.extend_from_slice(&checksum(&body).to_le_bytes());
out.extend_from_slice(&body);
Ok(out)
}
pub(crate) fn decode(bytes: &[u8]) -> Result<ModuleInner> {
let rest = bytes
.strip_prefix(MAGIC)
.ok_or_else(|| Error::msg("not a submilli serialized module"))?;
let (ver, body) = rest
.split_first_chunk::<4>()
.ok_or_else(|| Error::msg("truncated serialized module header"))?;
if u32::from_le_bytes(*ver) != ARTIFACT_VERSION {
return Err(Error::msg(
"incompatible serialized module (version mismatch)",
));
}
let (sum, body) = body
.split_first_chunk::<8>()
.ok_or_else(|| Error::msg("truncated serialized module header"))?;
if u64::from_le_bytes(*sum) != checksum(body) {
return Err(Error::msg(
"corrupted serialized module (checksum mismatch)",
));
}
postcard::from_bytes(body).map_err(|e| Error::msg(format!("failed to deserialize module: {e}")))
}
fn checksum(bytes: &[u8]) -> u64 {
const K: u64 = 0x9E37_79B9_7F4A_7C15;
let mix = |h: u64, word: u64| (h.rotate_left(23) ^ word).wrapping_mul(K);
let (words, rest) = bytes.as_chunks::<8>();
let mut h = mix(0, bytes.len() as u64);
for word in words {
h = mix(h, u64::from_le_bytes(*word));
}
let mut tail = [0u8; 8];
for (t, &b) in tail.iter_mut().zip(rest) {
*t = b;
}
h = mix(h, u64::from_le_bytes(tail));
h ^ (h >> 29)
}