1pub mod canonical;
6pub mod canonicalize;
7pub mod canon_json;
8pub mod canon_print;
9pub mod canonical_format;
10pub mod dead_branch;
11pub mod ids;
12pub mod patch;
13pub mod transforms;
14
15pub use canonical::*;
16pub use canonicalize::{canonicalize_program, canonicalize_item};
17pub use canon_print::{print_example, print_stages};
18pub use ids::{collect_ids, expr_ids, NodeId, NodeRef};
19pub use patch::{apply_patch, Patch, PatchError};
20pub use transforms::{
21 extract_function, inline_let, rename_local, replace_match_arm,
22 ExtractFnSpec, TransformError,
23};
24
25pub fn stage_canonical_hash(stage: &Stage) -> [u8; 32] {
28 let v = serde_json::to_value(stage).expect("stage is always serializable");
29 canon_json::hash_canonical(&v)
30}
31
32pub fn stage_canonical_hash_hex(stage: &Stage) -> String {
33 canon_json::hex(&stage_canonical_hash(stage))
34}
35
36pub fn sig_id(stage: &Stage) -> Option<String> {
38 Some(canon_json::hex(&sig_hash(stage, true)?))
39}
40
41fn structural_sig_hash(stage: &Stage) -> Option<[u8; 32]> {
45 sig_hash(stage, false)
46}
47
48fn sig_hash(stage: &Stage, include_name: bool) -> Option<[u8; 32]> {
49 let value = match stage {
50 Stage::FnDecl(fd) => {
51 let mut v = serde_json::Map::new();
52 v.insert("effects".into(), serde_json::to_value(&fd.effects).unwrap());
53 v.insert("input_types".into(), serde_json::to_value(
54 fd.params.iter().map(|p| &p.ty).collect::<Vec<_>>()
55 ).unwrap());
56 v.insert("output_type".into(), serde_json::to_value(&fd.return_type).unwrap());
57 if !fd.examples.is_empty() {
62 v.insert("examples".into(), serde_json::to_value(&fd.examples).unwrap());
63 }
64 if include_name { v.insert("name".into(), serde_json::Value::String(fd.name.clone())); }
65 serde_json::Value::Object(v)
66 }
67 Stage::TypeDecl(td) => {
68 let mut v = serde_json::Map::new();
69 v.insert("kind".into(), serde_json::Value::String("type".into()));
70 v.insert("params".into(), serde_json::to_value(&td.params).unwrap());
71 if include_name { v.insert("name".into(), serde_json::Value::String(td.name.clone())); }
72 serde_json::Value::Object(v)
73 }
74 Stage::Import(_) => return None,
75 };
76 Some(canon_json::hash_canonical(&value))
77}
78
79pub fn stage_id(stage: &Stage) -> Option<String> {
88 let sig = canon_json::hex(&structural_sig_hash(stage)?);
89 let impl_h = canon_json::hex(&implementation_hash(stage));
90 use sha2::{Digest, Sha256};
91 let mut h = Sha256::new();
92 h.update(sig.as_bytes());
93 h.update(impl_h.as_bytes());
94 let r = h.finalize();
95 Some(canon_json::hex(&r))
96}
97
98pub fn implementation_hash(stage: &Stage) -> [u8; 32] {
103 let stripped = strip_names(stage);
104 let v = serde_json::to_value(&stripped).expect("stage is always serializable");
105 canon_json::hash_canonical(&v)
106}
107
108fn strip_names(stage: &Stage) -> Stage {
109 match stage.clone() {
110 Stage::FnDecl(mut fd) => { fd.name = String::new(); Stage::FnDecl(fd) }
111 Stage::TypeDecl(mut td) => { td.name = String::new(); Stage::TypeDecl(td) }
112 s @ Stage::Import(_) => s,
113 }
114}