use std::fmt::Debug;
use std::hash::Hash;
use crate::TwoPTwoPGraphError;
pub trait TwoPTwoPId<Id> {
fn id(&self) -> &Id;
}
pub trait TwoPTwoPAddVertex<Id>: TwoPTwoPId<Id> {}
pub trait TwoPTwoPRemoveVertex<Id>: TwoPTwoPId<Id> {
fn add_vertex_id(&self) -> &Id;
}
pub trait TwoPTwoPAddEdge<Id>: TwoPTwoPId<Id> {
fn source(&self) -> &Id;
fn target(&self) -> &Id;
}
pub trait TwoPTwoPRemoveEdge<Id>: TwoPTwoPId<Id> {
fn add_edge_id(&self) -> &Id;
}
pub enum UpdateType {
AtSource,
Downstream,
}
#[derive(Clone, Debug)]
pub enum UpdateOperation<VA, VR, EA, ER> {
AddVertex(VA),
RemoveVertex(VR),
AddEdge(EA),
RemoveEdge(ER),
}
#[derive(Clone, Debug)]
pub struct TwoPTwoPGraph<VA, VR, EA, ER, I>
where
VA: Clone + TwoPTwoPAddVertex<I>,
VR: Clone + TwoPTwoPRemoveVertex<I>,
EA: Clone + TwoPTwoPAddEdge<I>,
ER: Clone + TwoPTwoPRemoveEdge<I>,
I: Eq + Hash + Debug + Clone,
{
vertices_added: Vec<VA>,
vertices_removed: Vec<VR>,
edges_added: Vec<EA>,
edges_removed: Vec<ER>,
_phantom: std::marker::PhantomData<I>,
}
impl<VA, VR, EA, ER, I> TwoPTwoPGraph<VA, VR, EA, ER, I>
where
VA: Clone + TwoPTwoPAddVertex<I>,
VR: Clone + TwoPTwoPRemoveVertex<I>,
EA: Clone + TwoPTwoPAddEdge<I>,
ER: Clone + TwoPTwoPRemoveEdge<I>,
I: Eq + Hash + Debug + Clone,
{
pub fn new() -> Self {
TwoPTwoPGraph {
vertices_added: Vec::new(),
vertices_removed: Vec::new(),
edges_added: Vec::new(),
edges_removed: Vec::new(),
_phantom: std::marker::PhantomData,
}
}
pub fn lookup_vertex(&self, vertex_id: &I) -> bool {
self.vertices_added.iter().any(|va| va.id() == vertex_id)
&& !self
.vertices_removed
.iter()
.any(|vr| vr.add_vertex_id() == vertex_id)
}
pub fn get_edge_added_from_remove_edge(&self, remove_edge: &ER) -> Option<&EA> {
self.edges_added
.iter()
.find(|ea| ea.id() == remove_edge.add_edge_id())
}
pub fn lookup_from_remove_edge(&self, remove_edge: &ER) -> bool {
self.get_edge_added_from_remove_edge(remove_edge)
.is_some_and(|edge_added| {
self.lookup_vertex(edge_added.source())
&& self.lookup_vertex(edge_added.target())
&& !self
.edges_removed
.iter()
.any(|er| er.add_edge_id() == remove_edge.add_edge_id())
})
}
pub fn update_operation(
&mut self,
update_operation: UpdateOperation<VA, VR, EA, ER>,
) -> Result<(), TwoPTwoPGraphError<I>> {
self.prepare(update_operation).map(|_| ())
}
pub fn prepare(
&mut self,
op: UpdateOperation<VA, VR, EA, ER>,
) -> Result<UpdateOperation<VA, VR, EA, ER>, TwoPTwoPGraphError<I>> {
let broadcast = op.clone();
match op {
UpdateOperation::AddVertex(vertex) => self.add_vertex(vertex, UpdateType::AtSource)?,
UpdateOperation::AddEdge(edge) => self.add_edge(edge, UpdateType::AtSource)?,
UpdateOperation::RemoveVertex(vertex) => {
self.remove_vertex(vertex, UpdateType::AtSource)?
}
UpdateOperation::RemoveEdge(edge) => self.remove_edge(edge, UpdateType::AtSource)?,
}
Ok(broadcast)
}
pub fn apply_downstream(
&mut self,
op: UpdateOperation<VA, VR, EA, ER>,
) -> Result<(), TwoPTwoPGraphError<I>> {
match op {
UpdateOperation::AddVertex(vertex) => self.add_vertex(vertex, UpdateType::Downstream),
UpdateOperation::AddEdge(edge) => self.add_edge(edge, UpdateType::Downstream),
UpdateOperation::RemoveVertex(vertex) => {
self.remove_vertex(vertex, UpdateType::Downstream)
}
UpdateOperation::RemoveEdge(edge) => self.remove_edge(edge, UpdateType::Downstream),
}
}
pub fn add_vertex(
&mut self,
vertex: VA,
_update_type: UpdateType,
) -> Result<(), TwoPTwoPGraphError<I>> {
if self.vertices_added.iter().any(|va| va.id() == vertex.id()) {
return Err(TwoPTwoPGraphError::VertexAlreadyExists(vertex.id().clone()));
}
self.vertices_added.push(vertex);
Ok(())
}
pub fn add_edge(
&mut self,
edge: EA,
update_type: UpdateType,
) -> Result<(), TwoPTwoPGraphError<I>> {
if matches!(update_type, UpdateType::AtSource) {
if !self.lookup_vertex(&edge.source()) {
return Err(TwoPTwoPGraphError::VertexDoesNotExists(
edge.source().clone(),
));
}
if !self.lookup_vertex(&edge.target()) {
return Err(TwoPTwoPGraphError::VertexDoesNotExists(
edge.target().clone(),
));
}
}
if self.edges_added.iter().any(|ea| ea.id() == edge.id()) {
return Err(TwoPTwoPGraphError::EdgeAlreadyExists(edge.id().clone()));
}
self.edges_added.push(edge);
Ok(())
}
pub fn remove_vertex(
&mut self,
vertex: VR,
update_type: UpdateType,
) -> Result<(), TwoPTwoPGraphError<I>> {
if matches!(update_type, UpdateType::AtSource) {
if !self.lookup_vertex(vertex.add_vertex_id()) {
return Err(TwoPTwoPGraphError::VertexDoesNotExists(
vertex.add_vertex_id().clone(),
));
}
for ea in self.edges_added.iter() {
let is_removed = self
.edges_removed
.iter()
.any(|er| ea.id() == er.add_edge_id());
if !is_removed
&& (ea.source() == vertex.add_vertex_id()
|| ea.target() == vertex.add_vertex_id())
{
return Err(TwoPTwoPGraphError::VertexHasEdge(
vertex.add_vertex_id().clone(),
ea.id().clone(),
));
}
}
}
if matches!(update_type, UpdateType::Downstream) {
if !self
.vertices_added
.iter()
.any(|va| va.id() == vertex.add_vertex_id())
{
return Err(TwoPTwoPGraphError::AddVertexNotDelivered(
vertex.add_vertex_id().clone(),
));
}
}
if self
.vertices_removed
.iter()
.any(|vr| vr.id() == vertex.id())
{
return Err(TwoPTwoPGraphError::VertexAlreadyExists(vertex.id().clone()));
}
self.vertices_removed.push(vertex);
Ok(())
}
pub fn remove_edge(
&mut self,
remove_edge: ER,
update_type: UpdateType,
) -> Result<(), TwoPTwoPGraphError<I>> {
if matches!(update_type, UpdateType::AtSource) {
if !self.lookup_from_remove_edge(&remove_edge) {
return Err(TwoPTwoPGraphError::EdgeDoesNotExists(
remove_edge.add_edge_id().clone(),
));
}
}
if matches!(update_type, UpdateType::Downstream) {
if !self
.edges_added
.iter()
.any(|ea| ea.id() == remove_edge.add_edge_id())
{
return Err(TwoPTwoPGraphError::AddEdgeNotDelivered(
remove_edge.add_edge_id().clone(),
));
}
}
if self
.edges_removed
.iter()
.any(|er| er.id() == remove_edge.id())
{
return Err(TwoPTwoPGraphError::EdgeAlreadyExists(
remove_edge.id().clone(),
));
}
self.edges_removed.push(remove_edge);
Ok(())
}
pub fn generate_petgraph(&self) -> petgraph::graph::DiGraph<VA, EA> {
let mut graph = petgraph::graph::DiGraph::new();
let mut vertex_map = std::collections::HashMap::new();
for va in self.vertices_added.iter() {
let is_removed = self
.vertices_removed
.iter()
.any(|vr| va.id() == vr.add_vertex_id());
if !is_removed {
let vertex = graph.add_node(va.clone());
vertex_map.insert(va.id().clone(), vertex);
}
}
for ea in self.edges_added.iter() {
let is_removed = self
.edges_removed
.iter()
.any(|er| ea.id() == er.add_edge_id());
if !is_removed {
if let (Some(&source), Some(&target)) =
(vertex_map.get(ea.source()), vertex_map.get(ea.target()))
{
graph.add_edge(source, target, ea.clone());
}
}
}
graph
}
}