Skip to content

Commit da4bd2f

Browse files
committed
Add support for edge labels
1 parent c5ded24 commit da4bd2f

3 files changed

Lines changed: 126 additions & 1 deletion

File tree

examples/dot.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@ pub fn main() {
2929
graph.add_edge(&v1, &v4).unwrap();
3030
graph.add_edge(&v5, &v6).unwrap();
3131

32+
#[cfg(feature = "dot")]
33+
{
34+
graph.add_edge_label(&v1, &v2, "V1→V2").unwrap();
35+
graph.add_edge_label(&v3, &v1, "V3→V1").unwrap();
36+
graph.add_edge_label(&v1, &v4, "V1→V4").unwrap();
37+
graph.add_edge_label(&v5, &v6, "V5→V6").unwrap();
38+
}
39+
3240
#[cfg(feature = "dot")]
3341
graph.to_dot("example1", &mut f).unwrap();
3442
}

src/dot.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,13 @@ impl<'a, T> dot::Labeller<'a, Nd, Ed<'a>> for DotGraph<'a, T> {
5353
.unwrap_or_else(|| String::new());
5454
dot::LabelText::label(Cow::Owned(label))
5555
}
56+
57+
fn edge_label<'b>(&'b self, e: &Ed) -> dot::LabelText<'b> {
58+
let label = self.graph.edge_label(e.0, e.1)
59+
.cloned()
60+
.unwrap_or_else(|| String::new());
61+
dot::LabelText::LabelStr(Cow::Owned(label))
62+
}
5663
}
5764

5865

@@ -63,7 +70,9 @@ impl<'a, T> dot::GraphWalk<'a, Nd, Ed<'a>> for DotGraph<'a, T> {
6370
}
6471

6572
fn edges(&'a self) -> dot::Edges<'a, Ed<'a>> {
66-
self.graph.edges().collect()
73+
self.graph.edges()
74+
.map(|e| (e.1, e.0))
75+
.collect()
6776
}
6877

6978
fn source(&self, e: &Ed) -> Nd {

src/graph.rs

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ pub struct Graph<T> {
8585
#[cfg(feature = "dot")]
8686
/// Mapping between vertices and labels
8787
vertex_labels: HashMap<VertexId, String>,
88+
89+
#[cfg(feature = "dot")]
90+
/// Mapping between edges and labels
91+
edge_labels: HashMap<Edge, String>,
8892
}
8993

9094
impl<T> Graph<T> {
@@ -110,6 +114,8 @@ impl<T> Graph<T> {
110114

111115
#[cfg(feature = "dot")]
112116
vertex_labels: HashMap::new(),
117+
#[cfg(feature = "dot")]
118+
edge_labels: HashMap::new(),
113119
}
114120
}
115121

@@ -138,6 +144,8 @@ impl<T> Graph<T> {
138144

139145
#[cfg(feature = "dot")]
140146
vertex_labels: HashMap::with_capacity(capacity),
147+
#[cfg(feature = "dot")]
148+
edge_labels: HashMap::with_capacity(capacity),
141149
}
142150
}
143151

@@ -202,6 +210,8 @@ impl<T> Graph<T> {
202210

203211
#[cfg(feature = "dot")]
204212
self.vertex_labels.reserve(additional);
213+
#[cfg(feature = "dot")]
214+
self.edge_labels.reserve(additional);
205215
}
206216

207217
/// Shrinks the capacity of the graph as much as possible.
@@ -229,6 +239,8 @@ impl<T> Graph<T> {
229239

230240
#[cfg(feature = "dot")]
231241
self.vertex_labels.shrink_to_fit();
242+
#[cfg(feature = "dot")]
243+
self.edge_labels.shrink_to_fit();
232244

233245
// Calculate additional value for edges vector
234246
// such that it is always n^2 where n is the
@@ -774,6 +786,7 @@ impl<T> Graph<T> {
774786
#[cfg(feature = "dot")]
775787
{
776788
graph.vertex_labels = self.vertex_labels.clone();
789+
graph.edge_labels = self.edge_labels.clone();
777790
}
778791

779792
graph
@@ -1382,6 +1395,42 @@ impl<T> Graph<T> {
13821395
Ok(old_label)
13831396
}
13841397

1398+
#[cfg(feature = "dot")]
1399+
/// Labels the edge with between the given vertices. Returns the old label if successful.
1400+
///
1401+
/// This method requires the `dot` crate feature.
1402+
///
1403+
/// ## Example
1404+
/// ```rust
1405+
/// use graphlib::{Graph, VertexId};
1406+
///
1407+
/// let mut graph: Graph<usize> = Graph::new();
1408+
/// let random_id = VertexId::random();
1409+
///
1410+
/// let v1 = graph.add_vertex(0);
1411+
/// let v2 = graph.add_vertex(1);
1412+
/// let v3 = graph.add_vertex(2);
1413+
///
1414+
/// graph.add_edge(&v1, &v2).unwrap();
1415+
/// graph.add_edge(&v3, &v1).unwrap();
1416+
///
1417+
/// assert!(graph.add_edge_label(&v1, &v2, "V1->V2").is_ok());
1418+
/// assert!(graph.add_edge_label(&v3, &v1, "V3->V1").is_ok());
1419+
/// assert!(graph.add_edge_label(&v2, &v3, "V2->V3").is_err());
1420+
/// assert!(graph.add_edge_label(&v1, &v3, "V1->V3").is_err());
1421+
/// ```
1422+
pub fn add_edge_label(&mut self, a: &VertexId, b: &VertexId, label: &str)
1423+
-> Result<Option<String>, GraphErr>
1424+
{
1425+
if !self.has_edge(a, b) {
1426+
return Err(GraphErr::NoSuchEdge);
1427+
}
1428+
1429+
let edge = Edge::new(a.clone(), b.clone());
1430+
let old_label = self.edge_labels.insert(edge, label.to_owned());
1431+
Ok(old_label)
1432+
}
1433+
13851434
#[cfg(feature = "dot")]
13861435
/// Retrieves the label of the vertex with the given id.
13871436
///
@@ -1392,6 +1441,16 @@ impl<T> Graph<T> {
13921441
self.vertex_labels.get(vertex_id)
13931442
}
13941443

1444+
#[cfg(feature = "dot")]
1445+
/// Retrieves the label of the edge with the given vertices.
1446+
///
1447+
/// This method requires the `dot` crate feature.
1448+
///
1449+
/// Returns `None` if there is no edge associated with the given vertices in the graph.
1450+
pub fn edge_label(&self, a: &VertexId, b: &VertexId) -> Option<&String> {
1451+
self.edge_labels.get(&Edge::new(*a, *b))
1452+
}
1453+
13951454
#[cfg(feature = "dot")]
13961455
/// Maps each label that is placed on a vertex to a new label.
13971456
///
@@ -1447,6 +1506,55 @@ impl<T> Graph<T> {
14471506
}
14481507
}
14491508

1509+
#[cfg(feature = "dot")]
1510+
/// Maps each label that is placed on an edge to a new label.
1511+
///
1512+
/// This method requires the `dot` crate feature.
1513+
///
1514+
/// ```rust
1515+
/// use std::collections::HashMap;
1516+
/// use graphlib::{Graph, VertexId};
1517+
///
1518+
/// let mut graph: Graph<usize> = Graph::new();
1519+
/// let random_id = VertexId::random();
1520+
/// let mut vertex_id: usize = 1;
1521+
///
1522+
/// let v1 = graph.add_vertex(0);
1523+
/// let v2 = graph.add_vertex(1);
1524+
/// let v3 = graph.add_vertex(2);
1525+
/// let v4 = graph.add_vertex(3);
1526+
///
1527+
/// graph.add_edge(&v1, &v2).unwrap();
1528+
/// graph.add_edge(&v2, &v3).unwrap();
1529+
/// graph.add_edge(&v1, &v4).unwrap();
1530+
/// graph.add_edge(&v4, &v3).unwrap();
1531+
///
1532+
/// assert!(graph.add_edge_label(&v1, &v2, &"V1->V2").is_ok());
1533+
/// assert!(graph.add_edge_label(&v2, &v3, &"V2->V3").is_ok());
1534+
/// assert!(graph.add_edge_label(&v1, &v4, &"V1->V4").is_ok());
1535+
/// assert!(graph.add_edge_label(&v4, &v3, &"V4->V3").is_ok());
1536+
/// assert!(graph.add_edge_label(&v1, &v3, &"V1->V3").is_err());
1537+
///
1538+
/// assert_eq!(graph.edge_label(&v1, &v2).unwrap(), "V1->V2");
1539+
/// assert_eq!(graph.edge_label(&v2, &v3).unwrap(), "V2->V3");
1540+
/// assert_eq!(graph.edge_label(&v1, &v4).unwrap(), "V1->V4");
1541+
/// assert_eq!(graph.edge_label(&v4, &v3).unwrap(), "V4->V3");
1542+
///
1543+
/// graph.map_edge_labels(|edge, old_label| format!("*{}*", old_label.unwrap()));
1544+
///
1545+
/// assert_eq!(graph.edge_label(&v1, &v2).unwrap(), "*V1->V2*");
1546+
/// assert_eq!(graph.edge_label(&v2, &v3).unwrap(), "*V2->V3*");
1547+
/// assert_eq!(graph.edge_label(&v1, &v4).unwrap(), "*V1->V4*");
1548+
/// assert_eq!(graph.edge_label(&v4, &v3).unwrap(), "*V4->V3*");
1549+
/// ```
1550+
pub fn map_edge_labels(&mut self, mut fun: impl FnMut(&Edge, Option<&str>) -> String) {
1551+
for (edge, _) in self.edges.iter() {
1552+
self.edge_labels.entry(Edge::new(*edge.outbound(), *edge.inbound()))
1553+
.and_modify(|e| { *e = fun(edge, Some(e)); })
1554+
.or_insert_with(|| fun(edge, None));
1555+
}
1556+
}
1557+
14501558
fn do_add_edge(
14511559
&mut self,
14521560
a: &VertexId,

0 commit comments

Comments
 (0)