use std::{collections::HashSet, hash::Hash, marker::PhantomData};
use crate::set::Collection;
mod sealed {
pub trait Sealed {}
}
pub trait DirectedType: sealed::Sealed {}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Undirected;
impl sealed::Sealed for Undirected {}
impl DirectedType for Undirected {}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Directed;
impl sealed::Sealed for Directed {}
impl DirectedType for Directed {}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum VertexOrEdge<V> {
Vertex(V),
Edge(V, V),
}
#[derive(Debug, Clone)]
pub struct Graph<V, D: DirectedType> {
vertices: HashSet<V>,
edges: HashSet<(V, V)>,
d: PhantomData<D>,
}
impl<V: PartialOrd + Eq + Hash> Graph<V, Undirected> {
pub fn new(vertices: HashSet<V>, edges: HashSet<(V, V)>) -> Self {
let edges =
edges.into_iter().map(|(a, b)| if a <= b { (a, b) } else { (b, a) }).collect::<HashSet<_>>();
assert!(
edges.iter().all(|(a, b)| vertices.contains(a) && vertices.contains(b)),
"All edges must be between vertices",
);
Self { vertices, edges, d: PhantomData }
}
}
impl<V: PartialOrd + Eq + Hash> Graph<V, Directed> {
pub fn new(vertices: HashSet<V>, edges: HashSet<(V, V)>) -> Self {
assert!(
edges.iter().all(|(a, b)| vertices.contains(a) && vertices.contains(b)),
"All edges must be between vertices",
);
Self { vertices, edges, d: PhantomData }
}
}
impl<V: PartialOrd + Eq + Hash + Clone> Collection for Graph<V, Directed> {
type Item = VertexOrEdge<V>;
fn is_empty(&self) -> bool { self.vertices.is_empty() }
fn contains(&self, point: &Self::Item) -> bool {
match point {
VertexOrEdge::Vertex(v) => self.vertices.contains(v),
VertexOrEdge::Edge(u, v) => self.edges.contains(&(u.clone(), v.clone())),
}
}
}
impl<V: PartialOrd + Eq + Hash + Clone> Collection for Graph<V, Undirected> {
type Item = VertexOrEdge<V>;
fn is_empty(&self) -> bool { self.vertices.is_empty() }
fn contains(&self, point: &Self::Item) -> bool {
match point {
VertexOrEdge::Vertex(v) => self.vertices.contains(v),
VertexOrEdge::Edge(u, v) =>
self.edges.contains(&(u.clone(), v.clone())) | self.edges.contains(&(v.clone(), u.clone())),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn create_graph_undirected() -> Graph<usize, Undirected> {
let mut vertices = HashSet::new();
vertices.insert(1);
vertices.insert(2);
vertices.insert(3);
vertices.insert(4);
vertices.insert(5);
let mut edges = HashSet::new();
edges.insert((1, 2));
edges.insert((2, 3));
edges.insert((3, 4));
Graph::<usize, Undirected>::new(vertices, edges)
}
fn create_graph_directed() -> Graph<usize, Directed> {
let mut vertices = HashSet::new();
vertices.insert(1);
vertices.insert(2);
vertices.insert(3);
vertices.insert(4);
vertices.insert(5);
let mut edges = HashSet::new();
edges.insert((1, 2));
edges.insert((2, 3));
edges.insert((3, 4));
edges.insert((4, 5));
Graph::<usize, Directed>::new(vertices, edges)
}
#[test]
fn graph_builds_undirected() {
let graph = create_graph_undirected();
assert_eq!(graph.vertices.len(), 5);
assert_eq!(graph.edges.len(), 3);
}
#[test]
fn graph_builds_directed() {
let graph = create_graph_directed();
assert_eq!(graph.vertices.len(), 5);
assert_eq!(graph.edges.len(), 4);
}
#[test]
fn graph_contains_vertex() {
let graph = create_graph_undirected();
assert!(graph.contains(&VertexOrEdge::Vertex(1)));
assert!(!graph.contains(&VertexOrEdge::Vertex(6)));
}
#[test]
fn graph_contains_edge() {
let graph = create_graph_undirected();
assert!(graph.contains(&VertexOrEdge::Edge(1, 2)));
}
#[test]
fn graph_contains_edge_undirected() {
let graph = create_graph_undirected();
assert!(graph.contains(&VertexOrEdge::Edge(1, 2)));
assert!(graph.contains(&VertexOrEdge::Edge(2, 1)));
}
#[test]
fn graph_contains_edge_directed() {
let graph = create_graph_directed();
assert!(graph.contains(&VertexOrEdge::Edge(1, 2)));
assert!(!graph.contains(&VertexOrEdge::Edge(2, 1)));
}
}