pub mod canonical;
pub mod canonicalize;
pub mod canon_json;
pub mod canon_print;
pub mod canonical_format;
pub mod dead_branch;
pub mod ids;
pub mod patch;
pub mod transforms;
pub use canonical::*;
pub use canonicalize::{canonicalize_program, canonicalize_item};
pub use canon_print::{print_example, print_stages};
pub use ids::{collect_ids, expr_ids, NodeId, NodeRef};
pub use patch::{apply_patch, Patch, PatchError};
pub use transforms::{
extract_function, inline_let, rename_local, replace_match_arm,
ExtractFnSpec, TransformError,
};
pub fn stage_canonical_hash(stage: &Stage) -> [u8; 32] {
let v = serde_json::to_value(stage).expect("stage is always serializable");
canon_json::hash_canonical(&v)
}
pub fn stage_canonical_hash_hex(stage: &Stage) -> String {
canon_json::hex(&stage_canonical_hash(stage))
}
pub fn sig_id(stage: &Stage) -> Option<String> {
Some(canon_json::hex(&sig_hash(stage, true)?))
}
fn structural_sig_hash(stage: &Stage) -> Option<[u8; 32]> {
sig_hash(stage, false)
}
fn sig_hash(stage: &Stage, include_name: bool) -> Option<[u8; 32]> {
let value = match stage {
Stage::FnDecl(fd) => {
let mut v = serde_json::Map::new();
v.insert("effects".into(), serde_json::to_value(&fd.effects).unwrap());
v.insert("input_types".into(), serde_json::to_value(
fd.params.iter().map(|p| &p.ty).collect::<Vec<_>>()
).unwrap());
v.insert("output_type".into(), serde_json::to_value(&fd.return_type).unwrap());
if !fd.examples.is_empty() {
v.insert("examples".into(), serde_json::to_value(&fd.examples).unwrap());
}
if include_name { v.insert("name".into(), serde_json::Value::String(fd.name.clone())); }
serde_json::Value::Object(v)
}
Stage::TypeDecl(td) => {
let mut v = serde_json::Map::new();
v.insert("kind".into(), serde_json::Value::String("type".into()));
v.insert("params".into(), serde_json::to_value(&td.params).unwrap());
if include_name { v.insert("name".into(), serde_json::Value::String(td.name.clone())); }
serde_json::Value::Object(v)
}
Stage::Import(_) => return None,
};
Some(canon_json::hash_canonical(&value))
}
pub fn stage_id(stage: &Stage) -> Option<String> {
let sig = canon_json::hex(&structural_sig_hash(stage)?);
let impl_h = canon_json::hex(&implementation_hash(stage));
use sha2::{Digest, Sha256};
let mut h = Sha256::new();
h.update(sig.as_bytes());
h.update(impl_h.as_bytes());
let r = h.finalize();
Some(canon_json::hex(&r))
}
pub fn implementation_hash(stage: &Stage) -> [u8; 32] {
let stripped = strip_names(stage);
let v = serde_json::to_value(&stripped).expect("stage is always serializable");
canon_json::hash_canonical(&v)
}
fn strip_names(stage: &Stage) -> Stage {
match stage.clone() {
Stage::FnDecl(mut fd) => { fd.name = String::new(); Stage::FnDecl(fd) }
Stage::TypeDecl(mut td) => { td.name = String::new(); Stage::TypeDecl(td) }
s @ Stage::Import(_) => s,
}
}