use std::any::type_name;
use std::collections::HashSet;
use std::error::Error;
use std::fmt::{Debug, Display};
use std::hash::Hash;
pub trait Identifier: Eq + Ord + Hash + Clone + Debug {}
impl<T> Identifier for T where T: Eq + Ord + Hash + Clone + Debug {}
#[derive(Debug)]
pub struct RemainingConnectedEdgesError<EdgeIdentifier>(pub HashSet<EdgeIdentifier>)
where
EdgeIdentifier: Identifier;
impl<EdgeIdentifier> Display for RemainingConnectedEdgesError<EdgeIdentifier>
where
EdgeIdentifier: Identifier,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
return write!(
f,
"the node still has {} remaining edges connected",
self.0.len()
);
}
}
impl<EdgeIdentifier> Error for RemainingConnectedEdgesError<EdgeIdentifier> where
EdgeIdentifier: Identifier
{
}
#[derive(Debug)]
pub struct InvalidEdgeEndError<NodeIdentifier>(pub [Option<NodeIdentifier>; 2])
where
NodeIdentifier: Identifier;
impl<NodeIdentifier> Display for InvalidEdgeEndError<NodeIdentifier>
where
NodeIdentifier: Identifier,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
return write!(
f,
"the edge has {} ends tied to non-existent nodes",
&self.0.iter().filter_map(|n| n.as_ref()).count()
);
}
}
impl<NodeIdentifier> Error for InvalidEdgeEndError<NodeIdentifier> where NodeIdentifier: Identifier {}
pub trait Node {
type Identifier: Identifier;
fn identifier(&self) -> &Self::Identifier;
}
pub trait Edge<N>
where
N: Node,
{
type Identifier: Identifier;
fn identifier(&self) -> &Self::Identifier;
fn ends(&self) -> [N::Identifier; 2];
}
pub trait Graph<N, E>
where
N: Node,
E: Edge<N>,
{
fn insert_edge(&mut self, edge: E) -> Result<Option<E>, InvalidEdgeEndError<N::Identifier>>;
fn remove_edge(&mut self, identifier: &E::Identifier) -> Option<E>;
fn insert_node(&mut self, node: N) -> Option<N>;
fn remove_node(
&mut self,
identifier: &N::Identifier,
) -> Result<Option<N>, RemainingConnectedEdgesError<E::Identifier>>;
fn remove_node_with_edges(&mut self, identifier: &N::Identifier) -> Option<(N, Vec<E>)> {
let removed_edges = match self.remove_node(identifier) {
Ok(ret) => return ret.map(|ret| (ret, Vec::new())),
Err(RemainingConnectedEdgesError(edges)) => {
edges.iter().filter_map(|e| self.remove_edge(e)).collect()
}
};
return self.remove_node(identifier)
.expect(&format!(
"The implementation of either Graph::remove_node or Graph::remove_edge for {} does not behave as expected",
type_name::<Self>()
)).map(|ret| (ret, removed_edges));
}
}