use crate::edge::{EdgeIndex, EdgeRef};
use crate::errors::{GraphError, GraphResult};
use crate::node::{NodeIndex, NodeRef};
pub trait GraphBase {
type NodeData;
type EdgeData;
fn node_count(&self) -> usize;
fn edge_count(&self) -> usize;
fn is_empty(&self) -> bool {
self.node_count() == 0
}
fn contains_node(&self, index: NodeIndex) -> bool;
fn contains_edge(&self, index: EdgeIndex) -> bool;
}
pub trait GraphQuery: GraphBase {
fn get_node(&self, index: NodeIndex) -> GraphResult<&Self::NodeData>;
fn get_edge(&self, index: EdgeIndex) -> GraphResult<&Self::EdgeData>;
fn edge_endpoints(&self, index: EdgeIndex) -> GraphResult<(NodeIndex, NodeIndex)>;
fn neighbors(&self, node: NodeIndex) -> impl Iterator<Item = NodeIndex>;
fn incident_edges(&self, node: NodeIndex) -> impl Iterator<Item = EdgeIndex>;
fn has_edge(&self, from: NodeIndex, to: NodeIndex) -> bool;
fn out_degree(&self, node: NodeIndex) -> GraphResult<usize>;
fn in_degree(&self, node: NodeIndex) -> GraphResult<usize> {
self.out_degree(node)
}
fn degree(&self, node: NodeIndex) -> GraphResult<usize> {
self.out_degree(node)
}
fn nodes(&self) -> impl Iterator<Item = NodeRef<'_, Self::NodeData>>;
fn edges(&self) -> impl Iterator<Item = EdgeRef<'_, Self::EdgeData>>;
}
pub trait GraphOps: GraphBase {
fn add_node(&mut self, data: Self::NodeData) -> GraphResult<NodeIndex>;
fn remove_node(&mut self, index: NodeIndex) -> GraphResult<Self::NodeData>;
fn add_edge(
&mut self,
from: NodeIndex,
to: NodeIndex,
data: Self::EdgeData,
) -> GraphResult<EdgeIndex>;
fn remove_edge(&mut self, index: EdgeIndex) -> GraphResult<Self::EdgeData>;
fn update_node(
&mut self,
index: NodeIndex,
data: Self::NodeData,
) -> GraphResult<Self::NodeData>;
fn update_edge(
&mut self,
index: EdgeIndex,
data: Self::EdgeData,
) -> GraphResult<Self::EdgeData>;
fn clear(&mut self);
fn reserve(&mut self, additional_nodes: usize, additional_edges: usize);
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Direction {
Outgoing,
Incoming,
}
impl Direction {
#[inline]
pub fn opposite(self) -> Self {
match self {
Direction::Outgoing => Direction::Incoming,
Direction::Incoming => Direction::Outgoing,
}
}
#[inline]
pub fn is_outgoing(self) -> bool {
matches!(self, Direction::Outgoing)
}
#[inline]
pub fn is_incoming(self) -> bool {
matches!(self, Direction::Incoming)
}
}
#[inline]
pub fn validate_node_index(provided: NodeIndex, current_generation: u32) -> GraphResult<()> {
if provided.generation() == current_generation {
Ok(())
} else {
Err(GraphError::NodeDeleted {
index: provided.index(),
provided: provided.generation(),
current: current_generation,
})
}
}
#[inline]
pub fn validate_edge_index(provided: EdgeIndex, current_generation: u32) -> GraphResult<()> {
if provided.generation() == current_generation {
Ok(())
} else {
Err(GraphError::EdgeDeleted {
index: provided.index(),
provided: provided.generation(),
current: current_generation,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_direction() {
assert_eq!(Direction::Outgoing.opposite(), Direction::Incoming);
assert_eq!(Direction::Incoming.opposite(), Direction::Outgoing);
assert!(Direction::Outgoing.is_outgoing());
assert!(Direction::Incoming.is_incoming());
}
}