use super::fn_bytecode::FnBytecode;
const COMPILER_STAMP: &str = concat!("logos-tiercache-v1-", env!("CARGO_PKG_VERSION"));
pub fn cache_key(source: &str, config_bits: u64, tier: u8) -> String {
format!("{:016x}", key_hash(source, config_bits, tier))
}
fn key_hash(source: &str, config_bits: u64, tier: u8) -> u64 {
let mut h: u64 = 0xcbf2_9ce4_8422_2325;
let mut mix = |bytes: &[u8]| {
for &b in bytes {
h ^= b as u64;
h = h.wrapping_mul(0x0000_0100_0000_01b3);
}
};
mix(COMPILER_STAMP.as_bytes());
mix(source.as_bytes());
mix(&config_bits.to_le_bytes());
mix(&[tier]);
h
}
fn payload_checksum(json: &str) -> u64 {
let mut h: u64 = 0xcbf2_9ce4_8422_2325;
for &b in json.as_bytes() {
h ^= b as u64;
h = h.wrapping_mul(0x0000_0100_0000_01b3);
}
h
}
pub fn encode(fnbc: &FnBytecode) -> String {
let json = serde_json::to_string(fnbc).expect("FnBytecode serializes");
format!("{:016x}\n{json}", payload_checksum(&json))
}
pub fn decode(s: &str) -> Option<FnBytecode> {
let (sum, json) = s.split_once('\n')?;
let expected = u64::from_str_radix(sum.trim(), 16).ok()?;
if payload_checksum(json) != expected {
return None;
}
serde_json::from_str(json).ok()
}
#[cfg(not(target_arch = "wasm32"))]
fn cache_path(dir: &std::path::Path, key: &str) -> std::path::PathBuf {
dir.join(format!("{key}.bc"))
}
#[cfg(not(target_arch = "wasm32"))]
pub fn store(
dir: &std::path::Path,
source: &str,
config_bits: u64,
tier: u8,
fnbc: &FnBytecode,
) -> std::io::Result<()> {
std::fs::create_dir_all(dir)?;
std::fs::write(cache_path(dir, &cache_key(source, config_bits, tier)), encode(fnbc))
}
#[cfg(not(target_arch = "wasm32"))]
pub fn load(
dir: &std::path::Path,
source: &str,
config_bits: u64,
tier: u8,
) -> Option<FnBytecode> {
let s = std::fs::read_to_string(cache_path(dir, &cache_key(source, config_bits, tier))).ok()?;
decode(&s)
}