use std::ops::Index;
use petgraph::graph::NodeIndex;
use petgraph::visit::EdgeRef;
use petgraph::{
Graph as PetGraph, Outgoing, Incoming, algo,
};
use super::node::*;
#[derive(Debug)]
pub struct Graph {
graph: PetGraph<Node, u32>,
}
impl Default for Graph {
fn default() -> Self {
Graph {
graph: PetGraph::new(),
}
}
}
impl Graph {
pub fn add_node(&mut self, node: Node) -> NodeIndex<u32> {
self.graph.add_node(node)
}
pub fn add_edge(&mut self, from: NodeIndex<u32>, to: NodeIndex<u32>, index: u32) {
self.graph.add_edge(from, to, index);
}
pub fn has_cycle(&self) -> bool {
algo::is_cyclic_directed(&self.graph)
}
#[cfg_attr(feature="clippy", allow(needless_lifetimes))]
pub fn outputs<'a>(&'a self) -> Box<Iterator<Item=NodeIndex<u32>> + 'a> {
Box::new(
self.graph.externals(Outgoing)
.filter(move |index| match self.graph.node_weight(*index) {
Some(&Node::Output(_, _, _)) |
Some(&Node::Return) => true,
_ => false,
})
)
}
#[cfg_attr(feature="clippy", allow(needless_lifetimes))]
pub fn arguments<'a>(&'a self, index: NodeIndex<u32>) -> Box<Iterator<Item=NodeIndex<u32>> + 'a> {
let mut vec: Vec<_> = self.graph.edges_directed(index, Incoming).collect();
vec.sort_by_key(|e| e.weight());
Box::new(
vec.into_iter().map(|e| e.source())
)
}
}
impl Index<NodeIndex<u32>> for Graph {
type Output = Node;
fn index(&self, index: NodeIndex<u32>) -> &Node {
&self.graph[index]
}
}