use std::collections::HashMap;
use std::hash::Hash;
pub mod gui;
mod graph;
pub use graph::Graph;
pub struct GraphBuilder<V = usize>
where
V: Eq + Hash + Clone,
{
num_vertices: usize,
directed: bool,
vertex_map: HashMap<V, usize>, edges: Vec<(usize, usize)>,
next_index: usize,
}
impl GraphBuilder<usize> {
pub fn new() -> Self {
Self {
num_vertices: 0,
directed: false,
vertex_map: HashMap::new(),
edges: Vec::new(),
next_index: 0,
}
}
pub fn vertices(mut self, n: usize) -> Self {
self.num_vertices = n;
for i in 0..n {
self.vertex_map.insert(i, i);
}
self.next_index = n;
self
}
}
impl<V> GraphBuilder<V>
where
V: Eq + Hash + Clone + std::fmt::Display,
{
pub fn directed(mut self, directed: bool) -> Self {
self.directed = directed;
self
}
pub fn vertex(mut self, v: V) -> Self {
if !self.vertex_map.contains_key(&v) {
self.vertex_map.insert(v, self.next_index);
self.next_index += 1;
self.num_vertices += 1;
}
self
}
pub fn vertices_from(mut self, vertices: impl IntoIterator<Item = V>) -> Self {
for v in vertices {
if !self.vertex_map.contains_key(&v) {
self.vertex_map.insert(v, self.next_index);
self.next_index += 1;
self.num_vertices += 1;
}
}
self
}
pub fn edge(mut self, from: V, to: V) -> Self {
if !self.vertex_map.contains_key(&from) {
self.vertex_map.insert(from.clone(), self.next_index);
self.next_index += 1;
self.num_vertices += 1;
}
if !self.vertex_map.contains_key(&to) {
self.vertex_map.insert(to.clone(), self.next_index);
self.next_index += 1;
self.num_vertices += 1;
}
let from_idx = *self.vertex_map.get(&from).unwrap();
let to_idx = *self.vertex_map.get(&to).unwrap();
self.edges.push((from_idx, to_idx));
self
}
pub fn edges(mut self, edges: impl IntoIterator<Item = (V, V)>) -> Self {
for (from, to) in edges {
self = self.edge(from, to);
}
self
}
pub fn build(self) -> Graph {
let mut graph = Graph::new(self.num_vertices, self.directed);
let mut labels = vec![String::new(); self.num_vertices];
for (vertex, index) in &self.vertex_map {
labels[*index] = vertex.to_string();
}
graph.set_labels(labels);
for (from, to) in self.edges {
graph.add_edge(from, to);
}
graph
}
pub fn show(self) -> Result<(), anyhow::Error> {
let graph = self.build();
crate::gui::show(&graph)
}
}
impl Default for GraphBuilder<usize> {
fn default() -> Self {
Self::new()
}
}
pub fn graph() -> GraphBuilder<usize> {
GraphBuilder::new()
}
pub fn graph_with<V>() -> GraphBuilder<V>
where
V: Eq + Hash + Clone + std::fmt::Display,
{
GraphBuilder {
num_vertices: 0,
directed: false,
vertex_map: HashMap::new(),
edges: Vec::new(),
next_index: 0,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_simple_directed_graph() {
let g = graph()
.directed(true)
.vertices(3)
.edge(0, 1)
.edge(0, 2)
.edge(1, 2)
.build();
assert_eq!(g.num_vertices(), 3);
assert!(g.is_directed());
}
#[test]
fn test_string_vertex_graph() {
let g = graph_with::<&str>()
.directed(false)
.vertex("A")
.vertex("B")
.vertex("C")
.edge("A", "B")
.edge("B", "C")
.build();
assert_eq!(g.num_vertices(), 3);
}
#[test]
fn test_convenience_function() {
let g = graph()
.vertices(4)
.directed(true)
.edges(vec![(0, 1), (1, 2), (2, 3)])
.build();
assert_eq!(g.num_vertices(), 4);
}
#[test]
fn test_vertex_labels() {
let g = graph_with::<&str>()
.edge("Alice", "Bob")
.edge("Bob", "Charlie")
.build();
assert_eq!(g.num_vertices(), 3);
}
}