use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum EdgeDirection {
Directed,
Bidirectional,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Edge<E> {
pub source: Uuid,
pub target: Uuid,
pub edge_type: E,
pub direction: EdgeDirection,
pub weight: Option<f32>,
pub created_at: DateTime<Utc>,
pub archived_at: Option<DateTime<Utc>>,
}
impl<E> Edge<E> {
pub fn new(source: Uuid, target: Uuid, edge_type: E, direction: EdgeDirection) -> Self {
Self {
source,
target,
edge_type,
direction,
weight: None,
created_at: Utc::now(),
archived_at: None,
}
}
pub fn is_archived(&self) -> bool {
self.archived_at.is_some()
}
pub fn is_active(&self) -> bool {
self.archived_at.is_none()
}
pub fn archive(&mut self) {
if self.archived_at.is_none() {
self.archived_at = Some(Utc::now());
}
}
pub fn unarchive(&mut self) {
self.archived_at = None;
}
pub fn involves(&self, node_id: Uuid) -> bool {
self.source == node_id || self.target == node_id
}
pub fn connects(&self, node_a: Uuid, node_b: Uuid) -> bool {
match self.direction {
EdgeDirection::Directed => self.source == node_a && self.target == node_b,
EdgeDirection::Bidirectional => {
(self.source == node_a && self.target == node_b)
|| (self.source == node_b && self.target == node_a)
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
enum TestEdgeType {
TypeA,
TypeB,
}
#[test]
fn test_edge_creation() {
let source = Uuid::new_v4();
let target = Uuid::new_v4();
let edge = Edge::new(source, target, TestEdgeType::TypeA, EdgeDirection::Directed);
assert_eq!(edge.source, source);
assert_eq!(edge.target, target);
assert!(edge.is_active());
assert!(!edge.is_archived());
}
#[test]
fn test_edge_archive() {
let source = Uuid::new_v4();
let target = Uuid::new_v4();
let mut edge = Edge::new(source, target, TestEdgeType::TypeA, EdgeDirection::Directed);
edge.archive();
assert!(edge.is_archived());
assert!(!edge.is_active());
edge.unarchive();
assert!(edge.is_active());
assert!(!edge.is_archived());
}
#[test]
fn test_edge_involves() {
let source = Uuid::new_v4();
let target = Uuid::new_v4();
let other = Uuid::new_v4();
let edge = Edge::new(source, target, TestEdgeType::TypeA, EdgeDirection::Directed);
assert!(edge.involves(source));
assert!(edge.involves(target));
assert!(!edge.involves(other));
}
#[test]
fn test_edge_connects_directed() {
let source = Uuid::new_v4();
let target = Uuid::new_v4();
let edge = Edge::new(source, target, TestEdgeType::TypeA, EdgeDirection::Directed);
assert!(edge.connects(source, target));
assert!(!edge.connects(target, source));
}
#[test]
fn test_edge_connects_bidirectional() {
let node_a = Uuid::new_v4();
let node_b = Uuid::new_v4();
let edge = Edge::new(
node_a,
node_b,
TestEdgeType::TypeA,
EdgeDirection::Bidirectional,
);
assert!(edge.connects(node_a, node_b));
assert!(edge.connects(node_b, node_a));
}
}