use crate::prelude::*;
use super::*;
use crate::util::maybe_grow;
impl Host {
pub fn readback_tree(&self, wire: &run::Wire) -> Tree {
ReadbackState { host: self, vars: Default::default(), var_id: 0 .. }.read_wire(wire.clone())
}
pub fn readback<M: Mode>(&self, rt_net: &run::Net<M>) -> Net {
let mut state = ReadbackState { host: self, vars: Default::default(), var_id: 0 .. };
let mut net = Net::default();
net.root = state.read_wire(rt_net.root.clone());
for (a, b) in rt_net.redexes.iter() {
net.redexes.push((state.read_port(a.clone(), None), state.read_port(b.clone(), None)))
}
net
}
}
struct ReadbackState<'a> {
host: &'a Host,
vars: Map<Addr, usize>,
var_id: RangeFrom<usize>,
}
impl<'a> ReadbackState<'a> {
fn read_wire(&mut self, wire: Wire) -> Tree {
let port = wire.load_target();
self.read_port(port, Some(wire))
}
fn read_port(&mut self, port: Port, wire: Option<Wire>) -> Tree {
maybe_grow(move || match port.tag() {
Tag::Var | Tag::Red => {
let key = wire.unwrap().addr().min(port.addr());
Tree::Var {
nam: create_var(match self.vars.entry(key) {
Entry::Occupied(e) => e.remove(),
Entry::Vacant(e) => *e.insert(self.var_id.next().unwrap()),
}),
}
}
Tag::Ref if port == Port::ERA => Tree::Era,
Tag::Ref => Tree::Ref { nam: self.host.back[&port.addr()].clone() },
Tag::Int => Tree::Int { val: port.int() },
Tag::F32 => Tree::F32 { val: port.float().into() },
Tag::Op => {
let op = port.op();
let node = port.traverse_node();
Tree::Op { op, rhs: Box::new(self.read_wire(node.p1)), out: Box::new(self.read_wire(node.p2)) }
}
Tag::Ctr => {
let node = port.traverse_node();
Tree::Ctr { lab: node.lab, ports: vec![self.read_wire(node.p1), self.read_wire(node.p2)] }
}
Tag::Mat => {
let node = port.traverse_node();
let arms = self.read_wire(node.p1);
let out = self.read_wire(node.p2);
Tree::legacy_mat(arms, out).expect("invalid mat node")
}
})
}
}