Repository: HigherOrderCO/Bend
File: src/lib.rs (Rust)

Code before:
  book.check_ref_to_ref()?;
  book.detach_supercombinators();
  book.prune();
  let (nets, id_map) = book_to_compact_nets(book, main)?;
  let core_book = nets_to_hvm_core(nets, &id_map)?;
  Ok((core_book, id_map))
}

pub fn run_compiled(book: &Book, mem_size: usize) -> (Net, RunStats) {
  let runtime_book = book_to_runtime(book);
  let mut root = hvmc::run::Net::new(mem_size);
  root.boot(name_to_val("main"));

  let start_time = Instant::now();
  root.normal(&runtime_book);
  let elapsed = start_time.elapsed().as_secs_f64();
  let rewrites =
    Rewrites { anni: root.anni, comm: root.comm, eras: root.eras, dref: root.dref, oper: root.oper };
  let net = net_from_runtime(&root);
  let def = root.to_def();
  let stats = RunStats { rewrites, used: def.node.len(), run_time: elapsed };
  (net, stats)
}

pub fn run_book(mut book: DefinitionBook, mem_size: usize) -> anyhow::Result<(Term, DefNames, RunInfo)> {
  let (compiled, id_map) = compile_book(&mut book)?;
  let (res_lnet, stats) = run_compiled(&compiled, mem_size);
  let net = hvmc_to_net(&res_lnet, &|val| *id_map.get_by_right(&val).unwrap())?;
  let (res_term, valid_readback) = net_to_term_non_linear(&net, &book);
  let info = RunInfo { stats, valid_readback, net: res_lnet };
  Ok((res_term, book.def_names, info))
}

pub struct RunInfo {
  pub stats: RunStats,
  pub valid_readback: bool,
  pub net: Net,
}

pub struct RunStats {
  pub rewrites: Rewrites,
  pub used: usize,
  pub run_time: f64,
}

pub struct Rewrites {
  pub anni: usize,
  pub comm: usize,
  pub eras: usize,
  pub dref: usize,
  pub oper: usize,

Review comment (suggestion):
Since inside `compile_book` we only use the left-to-right direction of the bimap and on readback we only use the `right-to-left` direction, I think it would be better to use just a normal HashMap.
Inside `compile_book` it can be just `id_to_hvmc_name` and then before returning you create a new HashMap with keys and values swapped with `let hvmc_name_to_id = id_to_hvmc_name.into_iter().map(|(k, v)| (v, k)).collect::<HashMap<_>>();`

Code after:
  let (nets, id_to_hvmc_name) = book_to_nets(book, main)?;
  let core_book = nets_to_hvm_core(nets, &id_to_hvmc_name)?;
  let hvmc_name_to_id = id_to_hvmc_name.into_iter().map(|(k, v)| (v, k)).collect();
  Ok((core_book, hvmc_name_to_id))
}

pub fn run_compiled(book: &Book, mem_size: usize) -> (Net, RunStats) {
  let runtime_book = book_to_runtime(book);
  let mut root = hvmc::run::Net::new(mem_size);
  root.boot(name_to_val("main"));

  let start_time = Instant::now();
  root.normal(&runtime_book);
  let elapsed = start_time.elapsed().as_secs_f64();
  let rewrites =
    Rewrites { anni: root.anni, comm: root.comm, eras: root.eras, dref: root.dref, oper: root.oper };
  let net = net_from_runtime(&root);
  let def = root.to_def();
  let stats = RunStats { rewrites, used: def.node.len(), run_time: elapsed };
  (net, stats)
}

pub fn run_book(mut book: DefinitionBook, mem_size: usize) -> anyhow::Result<(Term, DefNames, RunInfo)> {
  let (compiled, hvmc_name_to_id) = compile_book(&mut book)?;
  let (res_lnet, stats) = run_compiled(&compiled, mem_size);
  let net = hvmc_to_net(&res_lnet, &|val| hvmc_name_to_id[&val])?;
  let (res_term, valid_readback) = net_to_term_non_linear(&net, &book);
  let info = RunInfo { stats, valid_readback, net: res_lnet };
  Ok((res_term, book.def_names, info))
}

pub struct RunInfo {
  pub stats: RunStats,
  pub valid_readback: bool,
  pub net: Net,
}

pub struct RunStats {
  pub rewrites: Rewrites,
  pub used: usize,
  pub run_time: f64,
}

pub struct Rewrites {
  pub anni: usize,
  pub comm: usize,
  pub eras: usize,
  pub dref: usize,
  pub oper: usize,
}