Switch libgraphviz from type params to associated types for Node/Edge.

This commit is contained in:
Felix S. Klock II 2016-01-26 22:23:05 +01:00
parent 7ec8f5c369
commit baeae780e0
5 changed files with 90 additions and 48 deletions

View File

@ -62,7 +62,9 @@
//! dot::render(&edges, output).unwrap()
//! }
//!
//! impl<'a> dot::Labeller<'a, Nd, Ed> for Edges {
//! impl<'a> dot::Labeller<'a> for Edges {
//! type Node = Nd;
//! type Edge = Ed;
//! fn graph_id(&'a self) -> dot::Id<'a> { dot::Id::new("example1").unwrap() }
//!
//! fn node_id(&'a self, n: &Nd) -> dot::Id<'a> {
@ -70,7 +72,9 @@
//! }
//! }
//!
//! impl<'a> dot::GraphWalk<'a, Nd, Ed> for Edges {
//! impl<'a> dot::GraphWalk<'a> for Edges {
//! type Node = Nd;
//! type Edge = Ed;
//! fn nodes(&self) -> dot::Nodes<'a,Nd> {
//! // (assumes that |N| \approxeq |E|)
//! let &Edges(ref v) = self;
@ -167,7 +171,9 @@
//! dot::render(&graph, output).unwrap()
//! }
//!
//! impl<'a> dot::Labeller<'a, Nd, Ed<'a>> for Graph {
//! impl<'a> dot::Labeller<'a> for Graph {
//! type Node = Nd;
//! type Edge = Ed<'a>;
//! fn graph_id(&'a self) -> dot::Id<'a> { dot::Id::new("example2").unwrap() }
//! fn node_id(&'a self, n: &Nd) -> dot::Id<'a> {
//! dot::Id::new(format!("N{}", n)).unwrap()
@ -180,7 +186,9 @@
//! }
//! }
//!
//! impl<'a> dot::GraphWalk<'a, Nd, Ed<'a>> for Graph {
//! impl<'a> dot::GraphWalk<'a> for Graph {
//! type Node = Nd;
//! type Edge = Ed<'a>;
//! fn nodes(&self) -> dot::Nodes<'a,Nd> { (0..self.nodes.len()).collect() }
//! fn edges(&'a self) -> dot::Edges<'a,Ed<'a>> { self.edges.iter().collect() }
//! fn source(&self, e: &Ed) -> Nd { let & &(s,_) = e; s }
@ -225,7 +233,9 @@
//! dot::render(&graph, output).unwrap()
//! }
//!
//! impl<'a> dot::Labeller<'a, Nd<'a>, Ed<'a>> for Graph {
//! impl<'a> dot::Labeller<'a> for Graph {
//! type Node = Nd<'a>;
//! type Edge = Ed<'a>;
//! fn graph_id(&'a self) -> dot::Id<'a> { dot::Id::new("example3").unwrap() }
//! fn node_id(&'a self, n: &Nd<'a>) -> dot::Id<'a> {
//! dot::Id::new(format!("N{}", n.0)).unwrap()
@ -239,7 +249,9 @@
//! }
//! }
//!
//! impl<'a> dot::GraphWalk<'a, Nd<'a>, Ed<'a>> for Graph {
//! impl<'a> dot::GraphWalk<'a> for Graph {
//! type Node = Nd<'a>;
//! type Edge = Ed<'a>;
//! fn nodes(&'a self) -> dot::Nodes<'a,Nd<'a>> {
//! self.nodes.iter().map(|s| &s[..]).enumerate().collect()
//! }
@ -447,45 +459,48 @@ impl<'a> Id<'a> {
/// The graph instance is responsible for providing the DOT compatible
/// identifiers for the nodes and (optionally) rendered labels for the nodes and
/// edges, as well as an identifier for the graph itself.
pub trait Labeller<'a,N,E> {
pub trait Labeller<'a> {
type Node;
type Edge;
/// Must return a DOT compatible identifier naming the graph.
fn graph_id(&'a self) -> Id<'a>;
/// Maps `n` to a unique identifier with respect to `self`. The
/// implementor is responsible for ensuring that the returned name
/// is a valid DOT identifier.
fn node_id(&'a self, n: &N) -> Id<'a>;
fn node_id(&'a self, n: &Self::Node) -> Id<'a>;
/// Maps `n` to one of the [graphviz `shape` names][1]. If `None`
/// is returned, no `shape` attribute is specified.
///
/// [1]: http://www.graphviz.org/content/node-shapes
fn node_shape(&'a self, _node: &N) -> Option<LabelText<'a>> {
fn node_shape(&'a self, _node: &Self::Node) -> Option<LabelText<'a>> {
None
}
/// Maps `n` to a label that will be used in the rendered output.
/// The label need not be unique, and may be the empty string; the
/// default is just the output from `node_id`.
fn node_label(&'a self, n: &N) -> LabelText<'a> {
fn node_label(&'a self, n: &Self::Node) -> LabelText<'a> {
LabelStr(self.node_id(n).name)
}
/// Maps `e` to a label that will be used in the rendered output.
/// The label need not be unique, and may be the empty string; the
/// default is in fact the empty string.
fn edge_label(&'a self, e: &E) -> LabelText<'a> {
fn edge_label(&'a self, e: &Self::Edge) -> LabelText<'a> {
let _ignored = e;
LabelStr("".into_cow())
}
/// Maps `n` to a style that will be used in the rendered output.
fn node_style(&'a self, _n: &N) -> Style {
fn node_style(&'a self, _n: &Self::Node) -> Style {
Style::None
}
/// Maps `e` to a style that will be used in the rendered output.
fn edge_style(&'a self, _e: &E) -> Style {
fn edge_style(&'a self, _e: &Self::Edge) -> Style {
Style::None
}
}
@ -596,15 +611,18 @@ pub type Edges<'a,E> = Cow<'a,[E]>;
/// `Cow<[T]>` to leave implementors the freedom to create
/// entirely new vectors or to pass back slices into internally owned
/// vectors.
pub trait GraphWalk<'a, N: Clone, E: Clone> {
pub trait GraphWalk<'a> {
type Node: Clone;
type Edge: Clone;
/// Returns all the nodes in this graph.
fn nodes(&'a self) -> Nodes<'a, N>;
fn nodes(&'a self) -> Nodes<'a, Self::Node>;
/// Returns all of the edges in this graph.
fn edges(&'a self) -> Edges<'a, E>;
fn edges(&'a self) -> Edges<'a, Self::Edge>;
/// The source node for `edge`.
fn source(&'a self, edge: &E) -> N;
fn source(&'a self, edge: &Self::Edge) -> Self::Node;
/// The target node for `edge`.
fn target(&'a self, edge: &E) -> N;
fn target(&'a self, edge: &Self::Edge) -> Self::Node;
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
@ -622,28 +640,26 @@ pub fn default_options() -> Vec<RenderOption> {
/// Renders directed graph `g` into the writer `w` in DOT syntax.
/// (Simple wrapper around `render_opts` that passes a default set of options.)
pub fn render<'a,
N: Clone + 'a,
E: Clone + 'a,
G: Labeller<'a, N, E> + GraphWalk<'a, N, E>,
W: Write>
(g: &'a G,
w: &mut W)
-> io::Result<()> {
pub fn render<'a,N,E,G,W>(g: &'a G, w: &mut W) -> io::Result<()>
where N: Clone + 'a,
E: Clone + 'a,
G: Labeller<'a, Node=N, Edge=E> + GraphWalk<'a, Node=N, Edge=E>,
W: Write
{
render_opts(g, w, &[])
}
/// Renders directed graph `g` into the writer `w` in DOT syntax.
/// (Main entry point for the library.)
pub fn render_opts<'a,
N: Clone + 'a,
E: Clone + 'a,
G: Labeller<'a, N, E> + GraphWalk<'a, N, E>,
W: Write>
(g: &'a G,
w: &mut W,
options: &[RenderOption])
-> io::Result<()> {
pub fn render_opts<'a, N, E, G, W>(g: &'a G,
w: &mut W,
options: &[RenderOption])
-> io::Result<()>
where N: Clone + 'a,
E: Clone + 'a,
G: Labeller<'a, Node=N, Edge=E> + GraphWalk<'a, Node=N, Edge=E>,
W: Write
{
fn writeln<W: Write>(w: &mut W, arg: &[&str]) -> io::Result<()> {
for &s in arg {
try!(w.write_all(s.as_bytes()));
@ -858,7 +874,9 @@ mod tests {
Id::new(format!("N{}", *n)).unwrap()
}
impl<'a> Labeller<'a, Node, &'a Edge> for LabelledGraph {
impl<'a> Labeller<'a> for LabelledGraph {
type Node = Node;
type Edge = &'a Edge;
fn graph_id(&'a self) -> Id<'a> {
Id::new(&self.name[..]).unwrap()
}
@ -882,7 +900,9 @@ mod tests {
}
}
impl<'a> Labeller<'a, Node, &'a Edge> for LabelledGraphWithEscStrs {
impl<'a> Labeller<'a> for LabelledGraphWithEscStrs {
type Node = Node;
type Edge = &'a Edge;
fn graph_id(&'a self) -> Id<'a> {
self.graph.graph_id()
}
@ -901,7 +921,9 @@ mod tests {
}
}
impl<'a> GraphWalk<'a, Node, &'a Edge> for LabelledGraph {
impl<'a> GraphWalk<'a> for LabelledGraph {
type Node = Node;
type Edge = &'a Edge;
fn nodes(&'a self) -> Nodes<'a, Node> {
(0..self.node_labels.len()).collect()
}
@ -916,7 +938,9 @@ mod tests {
}
}
impl<'a> GraphWalk<'a, Node, &'a Edge> for LabelledGraphWithEscStrs {
impl<'a> GraphWalk<'a> for LabelledGraphWithEscStrs {
type Node = Node;
type Edge = &'a Edge;
fn nodes(&'a self) -> Nodes<'a, Node> {
self.graph.nodes()
}

View File

@ -52,7 +52,9 @@ fn replace_newline_with_backslash_l(s: String) -> String {
}
}
impl<'a, 'ast> dot::Labeller<'a, Node<'a>, Edge<'a>> for LabelledCFG<'a, 'ast> {
impl<'a, 'ast> dot::Labeller<'a> for LabelledCFG<'a, 'ast> {
type Node = Node<'a>;
type Edge = Edge<'a>;
fn graph_id(&'a self) -> dot::Id<'a> { dot::Id::new(&self.name[..]).unwrap() }
fn node_id(&'a self, &(i,_): &Node<'a>) -> dot::Id<'a> {
@ -97,7 +99,9 @@ impl<'a, 'ast> dot::Labeller<'a, Node<'a>, Edge<'a>> for LabelledCFG<'a, 'ast> {
}
}
impl<'a> dot::GraphWalk<'a, Node<'a>, Edge<'a>> for &'a cfg::CFG {
impl<'a> dot::GraphWalk<'a> for &'a cfg::CFG {
type Node = Node<'a>;
type Edge = Edge<'a>;
fn nodes(&'a self) -> dot::Nodes<'a, Node<'a>> {
let mut v = Vec::new();
self.graph.each_node(|i, nd| { v.push((i, nd)); true });
@ -116,8 +120,10 @@ impl<'a> dot::GraphWalk<'a, Node<'a>, Edge<'a>> for &'a cfg::CFG {
}
}
impl<'a, 'ast> dot::GraphWalk<'a, Node<'a>, Edge<'a>> for LabelledCFG<'a, 'ast>
impl<'a, 'ast> dot::GraphWalk<'a> for LabelledCFG<'a, 'ast>
{
type Node = Node<'a>;
type Edge = Edge<'a>;
fn nodes(&'a self) -> dot::Nodes<'a, Node<'a>> { self.cfg.nodes() }
fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> { self.cfg.edges() }
fn source(&'a self, edge: &Edge<'a>) -> Node<'a> { self.cfg.source(edge) }

View File

@ -173,7 +173,9 @@ impl<'a, 'tcx> ConstraintGraph<'a, 'tcx> {
}
}
impl<'a, 'tcx> dot::Labeller<'a, Node, Edge> for ConstraintGraph<'a, 'tcx> {
impl<'a, 'tcx> dot::Labeller<'a> for ConstraintGraph<'a, 'tcx> {
type Node = Node;
type Edge = Edge;
fn graph_id(&self) -> dot::Id {
dot::Id::new(&*self.graph_name).unwrap()
}
@ -224,7 +226,9 @@ fn edge_to_nodes(e: &Edge) -> (Node, Node) {
}
}
impl<'a, 'tcx> dot::GraphWalk<'a, Node, Edge> for ConstraintGraph<'a, 'tcx> {
impl<'a, 'tcx> dot::GraphWalk<'a> for ConstraintGraph<'a, 'tcx> {
type Node = Node;
type Edge = Edge;
fn nodes(&self) -> dot::Nodes<Node> {
let mut set = FnvHashSet();
for node in self.node_ids.keys() {

View File

@ -129,7 +129,9 @@ impl<'a, 'tcx> DataflowLabeller<'a, 'tcx> {
}
}
impl<'a, 'tcx> dot::Labeller<'a, Node<'a>, Edge<'a>> for DataflowLabeller<'a, 'tcx> {
impl<'a, 'tcx> dot::Labeller<'a> for DataflowLabeller<'a, 'tcx> {
type Node = Node<'a>;
type Edge = Edge<'a>;
fn graph_id(&'a self) -> dot::Id<'a> { self.inner.graph_id() }
fn node_id(&'a self, n: &Node<'a>) -> dot::Id<'a> { self.inner.node_id(n) }
fn node_label(&'a self, n: &Node<'a>) -> dot::LabelText<'a> {
@ -143,7 +145,9 @@ impl<'a, 'tcx> dot::Labeller<'a, Node<'a>, Edge<'a>> for DataflowLabeller<'a, 't
fn edge_label(&'a self, e: &Edge<'a>) -> dot::LabelText<'a> { self.inner.edge_label(e) }
}
impl<'a, 'tcx> dot::GraphWalk<'a, Node<'a>, Edge<'a>> for DataflowLabeller<'a, 'tcx> {
impl<'a, 'tcx> dot::GraphWalk<'a> for DataflowLabeller<'a, 'tcx> {
type Node = Node<'a>;
type Edge = Edge<'a>;
fn nodes(&'a self) -> dot::Nodes<'a, Node<'a>> { self.inner.nodes() }
fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> { self.inner.edges() }
fn source(&'a self, edge: &Edge<'a>) -> Node<'a> { self.inner.source(edge) }

View File

@ -253,7 +253,9 @@ fn dump_graph(tcx: &TyCtxt) {
pub struct GraphvizDepGraph(FnvHashSet<DepNode>, Vec<(DepNode, DepNode)>);
impl<'a, 'tcx> dot::GraphWalk<'a, DepNode, (DepNode, DepNode)> for GraphvizDepGraph {
impl<'a, 'tcx> dot::GraphWalk<'a> for GraphvizDepGraph {
type Node = DepNode;
type Edge = (DepNode, DepNode);
fn nodes(&self) -> dot::Nodes<DepNode> {
let nodes: Vec<_> = self.0.iter().cloned().collect();
nodes.into_cow()
@ -269,7 +271,9 @@ impl<'a, 'tcx> dot::GraphWalk<'a, DepNode, (DepNode, DepNode)> for GraphvizDepGr
}
}
impl<'a, 'tcx> dot::Labeller<'a, DepNode, (DepNode, DepNode)> for GraphvizDepGraph {
impl<'a, 'tcx> dot::Labeller<'a> for GraphvizDepGraph {
type Node = DepNode;
type Edge = (DepNode, DepNode);
fn graph_id(&self) -> dot::Id {
dot::Id::new("DependencyGraph").unwrap()
}