use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::atomic::{AtomicU64, Ordering};
use rlx_ir::{Graph, NodeId};
static HANDLE_SEQ: AtomicU64 = AtomicU64::new(1);
#[derive(Debug)]
struct Inner {
id: u64,
graph: Graph,
adopted: HashMap<(u64, u32), NodeId>,
}
#[derive(Clone, Debug)]
pub(crate) struct GraphHandle(Rc<RefCell<Inner>>);
impl GraphHandle {
pub(crate) fn new(graph: Graph) -> Self {
let id = HANDLE_SEQ.fetch_add(1, Ordering::Relaxed);
Self(Rc::new(RefCell::new(Inner {
id,
graph,
adopted: HashMap::new(),
})))
}
pub(crate) fn with_graph<F, R>(&self, f: F) -> R
where
F: FnOnce(&mut Graph) -> R,
{
f(&mut self.0.borrow_mut().graph)
}
pub(crate) fn same(&self, other: &GraphHandle) -> bool {
Rc::ptr_eq(&self.0, &other.0)
}
pub(crate) fn adopt(&self, other: &GraphHandle, other_id: NodeId) -> NodeId {
if self.same(other) {
return other_id;
}
let src_id = other.0.borrow().id;
if let Some(&mapped) = self.0.borrow().adopted.get(&(src_id, other_id.0)) {
return mapped;
}
let snapshot = other.with_graph(|src| {
src.nodes()
.iter()
.map(|n| {
(
n.id,
n.op.clone(),
n.inputs.clone(),
n.shape.clone(),
n.name.clone(),
)
})
.collect::<Vec<_>>()
});
let mut inner = self.0.borrow_mut();
let mut local: HashMap<NodeId, NodeId> = HashMap::with_capacity(snapshot.len());
let mut mapped = other_id;
for (old_id, op, inputs, shape, name) in snapshot {
if let Some(&existing) = inner.adopted.get(&(src_id, old_id.0)) {
local.insert(old_id, existing);
if old_id == other_id {
mapped = existing;
}
continue;
}
let new_inputs: Vec<NodeId> = inputs.iter().map(|i| local[i]).collect();
let new_id = inner.graph.append_node(op, new_inputs, shape, name);
inner.adopted.insert((src_id, old_id.0), new_id);
local.insert(old_id, new_id);
if old_id == other_id {
mapped = new_id;
}
}
mapped
}
}