use crate::{node_traits::DynComputedNode, utils::is_value_pointer_equal};
struct CyclicCheckVisitor {
path_visitor: PathVisitor,
}
impl CyclicCheckVisitor {
fn new() -> Self {
Self {
path_visitor: PathVisitor::new(),
}
}
fn pre(&mut self, node: &'_ DynComputedNode) {
if self.path_visitor.has_node(node) {
panic!("Cyclic dependency");
}
self.path_visitor.pre(node);
}
fn post(&mut self) {
self.path_visitor.post();
}
}
struct PathVisitor {
path: Vec<DynComputedNode>,
}
impl PathVisitor {
fn new() -> Self {
Self { path: Vec::new() }
}
fn has_node(&self, node: &'_ DynComputedNode) -> bool {
self.path
.iter()
.any(|path_node| is_value_pointer_equal(path_node.as_ptr(), node.as_ptr()))
}
fn pre(&mut self, node: &'_ DynComputedNode) {
self.path.push(node.clone());
}
fn post(&mut self) {
self.path.pop();
}
}
struct VisitedNodesVisitor {
visited: Vec<DynComputedNode>,
}
impl VisitedNodesVisitor {
fn new() -> Self {
Self {
visited: Vec::new(),
}
}
fn should_enter(&self, node: &'_ DynComputedNode) -> bool {
!self.visited.iter().any(|visited_node| {
is_value_pointer_equal(visited_node.as_ptr(), node.as_ptr())
})
}
fn post(&mut self, node: &'_ DynComputedNode) {
self.visited.push(node.clone());
}
}
pub(crate) struct ResolutionVisitor {
cyclic_visitor: CyclicCheckVisitor,
visited_nodes_visitor: VisitedNodesVisitor,
resolved: Vec<DynComputedNode>,
}
impl ResolutionVisitor {
pub(crate) fn new() -> Self {
Self {
cyclic_visitor: CyclicCheckVisitor::new(),
visited_nodes_visitor: VisitedNodesVisitor::new(),
resolved: Vec::new(),
}
}
pub(crate) fn should_enter(&self, node: &'_ DynComputedNode) -> bool {
self.visited_nodes_visitor.should_enter(node)
}
pub(crate) fn pre(&mut self, node: &'_ DynComputedNode) {
self.cyclic_visitor.pre(node);
}
pub(crate) fn post(&mut self, node: &'_ DynComputedNode) {
self.cyclic_visitor.post();
self.visited_nodes_visitor.post(node);
self.resolved.push(node.clone());
}
pub(crate) fn get_resolved(mut self) -> Vec<DynComputedNode> {
self.resolved.reverse();
self.resolved
}
}