pub trait NodeIndex: PartialEq + PartialOrd + Copy {}
impl<T> NodeIndex for T where T: PartialEq + PartialOrd + Copy {}
#[derive(PartialEq, Debug, Clone, Copy)]
pub enum GraphError<NI: NodeIndex> {
EdgeHasInvalidNode(NI),
NodeNotFound(NI),
EdgeNotFound(NI, NI),
IndexOutOfBounds(usize, NI),
InvalidMatrixSize,
OutOfCapacity,
DuplicateNode(NI),
NodeHasIncomingEdges(NI),
NodeHasOutgoingEdges(NI),
Unexpected,
}
pub trait Graph<NI: NodeIndex> {
type Error: From<GraphError<NI>>;
fn iter_nodes(&self) -> Result<impl Iterator<Item = NI>, Self::Error>;
fn iter_edges(&self) -> Result<impl Iterator<Item = (NI, NI)>, Self::Error>;
fn outgoing_edges(&self, node: NI) -> Result<impl Iterator<Item = NI>, Self::Error> {
Ok(self
.iter_edges()?
.filter(move |(src, _dst)| *src == node)
.map(|(_src, dst)| dst))
}
fn incoming_edges(&self, node: NI) -> Result<impl Iterator<Item = NI>, Self::Error> {
Ok(self
.iter_edges()?
.filter(move |(_src, dst)| *dst == node)
.map(|(src, _dst)| src))
}
fn contains_node(&self, node: NI) -> Result<bool, Self::Error> {
Ok(self.iter_nodes()?.any(|x| x == node))
}
}
pub trait GraphWithNodeValues<NI, NV>: Graph<NI>
where
NI: NodeIndex,
{
fn node_value(&self, node: NI) -> Result<Option<&NV>, Self::Error>;
fn iter_node_values<'a>(
&'a self,
) -> Result<impl Iterator<Item = (NI, Option<&'a NV>)>, Self::Error>
where
NV: 'a;
}
pub trait GraphWithEdgeValues<NI, EV>: Graph<NI>
where
NI: NodeIndex,
{
fn iter_edge_values<'a>(
&'a self,
) -> Result<impl Iterator<Item = (NI, NI, Option<&'a EV>)>, Self::Error>
where
EV: 'a;
fn outgoing_edge_values<'a>(
&'a self,
node: NI,
) -> Result<impl Iterator<Item = (NI, Option<&'a EV>)>, Self::Error>
where
EV: 'a,
{
Ok(self
.iter_edge_values()?
.filter(move |(src, _dst, _weight)| *src == node)
.map(|(_src, dst, weight)| (dst, weight)))
}
fn incoming_edge_values<'a>(
&'a self,
node: NI,
) -> Result<impl Iterator<Item = (NI, Option<&'a EV>)>, Self::Error>
where
EV: 'a,
{
Ok(self
.iter_edge_values()?
.filter(move |(_src, dst, _weight)| *dst == node)
.map(|(src, _dst, weight)| (src, weight)))
}
}
pub trait GraphWithMutableNodes<NI: NodeIndex>: Graph<NI> {
fn add_node(&mut self, node: NI) -> Result<(), Self::Error>;
fn remove_node(&mut self, node: NI) -> Result<(), Self::Error>;
}
pub trait GraphWithMutableNodeValues<NI, NV>: Graph<NI> + GraphWithNodeValues<NI, NV>
where
NI: NodeIndex,
{
fn add_node_value(&mut self, node: NI, value: NV) -> Result<(), Self::Error>;
fn remove_node_value(&mut self, node: NI) -> Result<(), Self::Error>;
}
pub trait GraphWithMutableEdges<NI: NodeIndex>: Graph<NI> {
fn add_edge(&mut self, source: NI, destination: NI) -> Result<(), Self::Error>;
fn remove_edge(&mut self, source: NI, destination: NI) -> Result<(), Self::Error>;
}
pub(crate) fn integrity_check<NI, G>(graph: &G) -> Result<(), G::Error>
where
NI: NodeIndex,
G: Graph<NI>,
{
for (src, dst) in graph.iter_edges()? {
if !graph.contains_node(src)? {
return Err(GraphError::EdgeHasInvalidNode(src).into());
}
if !graph.contains_node(dst)? {
return Err(GraphError::EdgeHasInvalidNode(dst).into());
}
}
Ok(())
}