use crate::getters;
use std::{
collections::{HashMap, HashSet},
ops::{Add, AddAssign, MulAssign},
};
#[derive(Debug)]
pub enum EdgeType {
DirectedEdge {
departure: String,
arrival: String,
},
UndirectedEdge {
one: String,
two: String,
},
}
impl EdgeType {
#[must_use]
pub fn directed(departure: &str, arrival: &str) -> Self {
Self::DirectedEdge {
departure: departure.to_string(),
arrival: arrival.to_string(),
}
}
#[must_use]
pub fn undirected(one: &str, two: &str) -> Self {
Self::UndirectedEdge {
one: one.to_string(),
two: two.to_string(),
}
}
}
impl Eq for EdgeType {}
impl PartialEq for EdgeType {
fn eq(&self, other: &Self) -> bool {
match self {
Self::DirectedEdge {
departure: a,
arrival: b,
} => match other {
Self::DirectedEdge {
departure: c,
arrival: d,
} => a == c && b == d,
Self::UndirectedEdge { .. } => false,
},
Self::UndirectedEdge { one: a, two: b } => match other {
Self::DirectedEdge { .. } => false,
Self::UndirectedEdge { one: c, two: d } => {
(a == c && b == d) || (a == d && b == c)
}
},
}
}
}
impl std::hash::Hash for EdgeType {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
match self {
Self::DirectedEdge { departure, arrival } => {
departure.hash(state);
arrival.hash(state);
}
Self::UndirectedEdge { one, two } => {
one.hash(state);
two.hash(state);
}
}
}
}
#[derive(Debug)]
pub struct Edges {
edges: HashSet<EdgeType>,
}
impl Edges {
pub fn add_directed_edge(
&mut self,
departure: &str,
arrival: &str,
) -> bool {
self.edges.insert(EdgeType::directed(departure, arrival))
}
pub fn add_undirected_edge(&mut self, one: &str, two: &str) -> bool {
self.edges.insert(EdgeType::undirected(one, two))
}
#[must_use]
pub fn contains(&self, edge: &EdgeType) -> bool {
match edge {
EdgeType::DirectedEdge { departure, arrival } => {
self.edges.contains(&EdgeType::directed(departure, arrival))
}
EdgeType::UndirectedEdge { one, two } => {
self.edges.contains(&EdgeType::undirected(one, two))
|| self.edges.contains(&EdgeType::undirected(two, one))
}
}
}
#[must_use]
pub fn new() -> Self {
Self {
edges: HashSet::new(),
}
}
}
impl Eq for Edges {}
impl Default for Edges {
fn default() -> Self {
Self::new()
}
}
impl PartialEq for Edges {
fn eq(&self, other: &Self) -> bool {
let mut result = self.edges.len() == other.edges.len();
if result {
for edge in &self.edges {
if !other.contains(edge) {
result = false;
break;
}
}
}
result
}
}
#[derive(Debug, Eq, PartialEq)]
pub struct Graph<T>
where
T: Add + AddAssign + Clone + From<u8> + MulAssign,
{
edges: Edges,
vertices: Vertices<T>,
}
impl<T> Graph<T>
where
T: Add + AddAssign + Clone + From<u8> + MulAssign,
{
getters!(@fn @ref edges: Edges, vertices: Vertices<T>);
pub fn connect_a_and_b(&mut self, a: &str, b: &str) {
self.vertices.add_undirected_edge(a, b);
self.edges.add_undirected_edge(a, b);
}
pub fn connect_a_with_b(&mut self, a: &str, b: &str) {
self.vertices.add_directed_edge(a, b);
self.edges.add_directed_edge(a, b);
}
pub fn declare(&mut self, vertex: &str) {
self.vertices.add_vertex(vertex);
}
#[must_use]
pub fn new() -> Self {
Self {
edges: Edges::default(),
vertices: Vertices::default(),
}
}
}
impl<T> Default for Graph<T>
where
T: Add + AddAssign + Clone + From<u8> + MulAssign,
{
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug)]
pub struct VertexData<T>
where
T: Add + AddAssign + Clone + MulAssign,
{
degree: usize,
ingoing: usize,
outgoing: usize,
x: T,
y: T,
z: T,
}
impl<T> VertexData<T>
where
T: Add + AddAssign + Clone + MulAssign,
{
getters!(@fn @cp degree: usize, ingoing: usize, outgoing: usize);
getters!(@fn @ref x: T, y: T, z: T);
pub fn connect_edge(&mut self) {
self.degree += 1;
self.ingoing += 1;
self.outgoing += 1;
}
pub fn move_by(&mut self, x: T, y: T, z: T) {
self.x += x;
self.y += y;
self.z += z;
}
pub fn move_to(&mut self, x: T, y: T, z: T) {
self.x = x;
self.y = y;
self.z = z;
}
#[must_use]
pub const fn new(x: T, y: T, z: T) -> Self {
Self {
degree: 0,
ingoing: 0,
outgoing: 0,
x,
y,
z,
}
}
pub fn receive_edge(&mut self) {
self.degree += 1;
self.ingoing += 1;
}
pub fn scale(&mut self, n: T) {
self.x *= n.clone();
self.y *= n.clone();
self.z *= n;
}
pub fn send_edge(&mut self) {
self.degree += 1;
self.outgoing += 1;
}
}
impl<T> Eq for VertexData<T> where
T: Add + AddAssign + Clone + MulAssign + PartialEq
{
}
impl<T> Default for VertexData<T>
where
T: Add + AddAssign + Clone + From<u8> + MulAssign,
{
fn default() -> Self {
Self::new(0.into(), 0.into(), 0.into())
}
}
impl<T> PartialEq for VertexData<T>
where
T: Add + AddAssign + Clone + MulAssign + PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.x == other.x && self.y == other.y && self.z == other.z
}
}
#[derive(Debug)]
pub struct Vertices<T>
where
T: Add + AddAssign + Clone + MulAssign,
{
vertices: HashMap<String, VertexData<T>>,
}
impl<T> Vertices<T>
where
T: Add + AddAssign + Clone + From<u8> + MulAssign,
{
pub fn add_directed_edge(&mut self, departure: &str, arrival: &str) {
self.add_vertex(departure);
self.add_vertex(arrival);
let mut departure_vertex = self.vertices[departure].clone();
departure_vertex.send_edge();
self.vertices
.insert(departure.to_string(), departure_vertex);
let mut arrival_vertex = self.vertices[arrival].clone();
arrival_vertex.receive_edge();
self.vertices.insert(arrival.to_string(), arrival_vertex);
}
pub fn add_undirected_edge(&mut self, a: &str, b: &str) {
self.add_vertex(a);
self.add_vertex(b);
let mut a_vertex = self.vertices[a].clone();
a_vertex.connect_edge();
self.vertices.insert(a.to_string(), a_vertex);
let mut b_vertex = self.vertices[b].clone();
b_vertex.connect_edge();
self.vertices.insert(b.to_string(), b_vertex);
}
pub fn add_vertex(&mut self, label: &str) -> bool {
if self.vertices.contains_key(label) {
false
} else {
self.vertices
.insert(label.to_string(), VertexData::default());
true
}
}
pub fn move_by(&mut self, x: &T, y: &T, z: &T) {
let mut update = HashMap::new();
for (label, vertex) in &self.vertices {
let mut vertex = vertex.clone();
vertex.move_by(x.clone(), y.clone(), z.clone());
update.insert(label.to_string(), vertex);
}
self.vertices = update;
}
#[must_use]
pub fn new() -> Self {
Self {
vertices: HashMap::new(),
}
}
pub fn scale(&mut self, n: &T) {
let mut update = HashMap::new();
for (label, vertex) in &self.vertices {
let mut vertex = vertex.clone();
vertex.scale(n.clone());
update.insert(label.to_string(), vertex);
}
self.vertices = update;
}
}
impl<T> Eq for Vertices<T> where
T: Add + AddAssign + Clone + From<u8> + MulAssign + PartialEq
{
}
impl<T> Default for Vertices<T>
where
T: Add + AddAssign + Clone + From<u8> + MulAssign,
{
fn default() -> Self {
Self::new()
}
}
impl<T> PartialEq for Vertices<T>
where
T: Add + AddAssign + Clone + From<u8> + MulAssign + PartialEq,
{
fn eq(&self, other: &Self) -> bool {
let mut result = self.vertices.len() == other.vertices.len();
if result {
for (label, vertex) in &self.vertices {
if !other.vertices.contains_key(label) {
result = false;
break;
}
if &other.vertices[label] != vertex {
result = false;
break;
}
}
}
result
}
}