use crate::conversions::FromGraph;
use crate::edges::EdgeNodeError;
use crate::graph::{Graph, GraphError, GraphWithMutableEdges, NodeIndex};
#[derive(Debug)]
pub enum EdgeListError<NI: NodeIndex> {
EdgeNodeError(EdgeNodeError),
GraphError(GraphError<NI>),
}
impl<NI: NodeIndex> From<EdgeNodeError> for EdgeListError<NI> {
fn from(e: EdgeNodeError) -> Self {
EdgeListError::EdgeNodeError(e)
}
}
impl<NI: NodeIndex> From<GraphError<NI>> for EdgeListError<NI> {
fn from(e: GraphError<NI>) -> Self {
EdgeListError::GraphError(e)
}
}
impl<NI: NodeIndex> From<EdgeListError<NI>> for GraphError<NI> {
fn from(e: EdgeListError<NI>) -> Self {
match e {
EdgeListError::EdgeNodeError(_) => GraphError::OutOfCapacity,
EdgeListError::GraphError(ge) => ge,
}
}
}
pub struct EdgeList<const N: usize, NI, E> {
edges: E,
_phantom: core::marker::PhantomData<NI>,
}
impl<const N: usize, NI, E> EdgeList<N, NI, E> {
pub fn new(edges: E) -> Self {
Self {
edges,
_phantom: Default::default(),
}
}
}
impl<const N: usize, NI, E> FromGraph<NI, EdgeListError<NI>> for EdgeList<N, NI, E>
where
NI: NodeIndex + Ord + PartialEq,
E: crate::edges::EdgesIterable<Node = NI> + crate::edges::MutableEdges<NI> + Default,
{
fn from_graph<G>(source_graph: &G) -> Result<Self, EdgeListError<NI>>
where
G: Graph<NI>,
EdgeListError<NI>: From<G::Error>,
{
let mut edges = E::default();
for (source, destination) in source_graph.iter_edges()? {
if edges.add_edge((source, destination)).is_none() {
return Err(EdgeListError::GraphError(GraphError::OutOfCapacity));
}
}
Ok(Self {
edges,
_phantom: Default::default(),
})
}
}
impl<const N: usize, NI, E> Graph<NI> for EdgeList<N, NI, E>
where
E: crate::edges::EdgesIterable<Node = NI>,
NI: NodeIndex + Ord,
{
type Error = EdgeListError<NI>;
fn iter_edges(&self) -> Result<impl Iterator<Item = (NI, NI)>, Self::Error> {
Ok(self.edges.iter_edges().map(|(a, b)| (*a, *b)))
}
fn iter_nodes(&self) -> Result<impl Iterator<Item = NI>, Self::Error> {
Ok(crate::edges::EdgesToNodesIterator::<N, NI>::new(&self.edges)?.copied())
}
}
impl<const N: usize, NI, E, V> crate::graph::GraphWithEdgeValues<NI, V> for EdgeList<N, NI, E>
where
E: crate::edges::EdgeValuesIterable<V, Node = NI>,
NI: NodeIndex + Ord,
{
fn iter_edge_values<'a>(
&'a self,
) -> Result<impl Iterator<Item = (NI, NI, Option<&'a V>)>, Self::Error>
where
V: 'a,
{
Ok(self.edges.iter_edges_values().map(|(a, b, v)| (*a, *b, v)))
}
}
impl<const N: usize, NI, E> GraphWithMutableEdges<NI> for EdgeList<N, NI, E>
where
E: crate::edges::EdgesIterable<Node = NI> + crate::edges::MutableEdges<NI>,
NI: NodeIndex + Ord + PartialEq,
{
fn add_edge(&mut self, source: NI, destination: NI) -> Result<(), Self::Error> {
self.edges
.add_edge((source, destination))
.ok_or(GraphError::OutOfCapacity)?;
Ok(())
}
fn remove_edge(&mut self, source: NI, destination: NI) -> Result<(), Self::Error> {
self.edges
.remove_edge((source, destination))
.ok_or(GraphError::EdgeNotFound(source, destination))?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::adjacency_list::map_adjacency_list::MapAdjacencyList;
use crate::containers::maps::staticdict::Dictionary;
use crate::containers::maps::MapTrait;
use crate::edges::EdgeNodeError;
use crate::edges::EdgeStructOption;
use crate::graph::{GraphError, GraphWithEdgeValues, GraphWithMutableEdges};
use crate::tests::{collect, collect_sorted};
#[test]
fn test_edge_list_new() {
let edges = [(0, 1), (1, 2), (2, 0)];
let edge_list = EdgeList::<10, usize, _>::new(edges);
assert_eq!(
core::mem::size_of_val(&edge_list.edges),
core::mem::size_of_val(&edges)
);
}
#[test]
fn test_edge_list_new_empty() {
let edges: [(usize, usize); 0] = [];
let edge_list = EdgeList::<10, usize, _>::new(edges);
assert_eq!(core::mem::size_of_val(&edge_list.edges), 0);
}
#[test]
fn test_edge_list_new_single_edge() {
let edges = [(42, 99)];
let edge_list = EdgeList::<10, usize, _>::new(edges);
assert_eq!(
core::mem::size_of_val(&edge_list.edges),
core::mem::size_of_val(&edges)
);
}
#[test]
fn test_edge_list_with_different_node_types() {
let edges_u32 = [(0u32, 1u32), (1u32, 2u32)];
let _edge_list_u32 = EdgeList::<10, u32, _>::new(edges_u32);
let edges_i32 = [(0i32, 1i32), (1i32, 2i32)];
let _edge_list_i32 = EdgeList::<10, i32, _>::new(edges_i32);
let edges_u8 = [(0u8, 1u8), (1u8, 2u8)];
let _edge_list_u8 = EdgeList::<10, u8, _>::new(edges_u8);
}
#[test]
fn test_edge_list_error_from_edge_node_error() {
let edge_node_error = EdgeNodeError::NotEnoughCapacity;
let edge_list_error = EdgeListError::<usize>::from(edge_node_error);
assert!(matches!(
edge_list_error,
EdgeListError::EdgeNodeError(EdgeNodeError::NotEnoughCapacity)
));
}
#[test]
fn test_edge_list_error_from_graph_error() {
let graph_error = GraphError::<usize>::NodeNotFound(0);
let edge_list_error = EdgeListError::<usize>::from(graph_error);
assert!(matches!(
edge_list_error,
EdgeListError::GraphError(GraphError::NodeNotFound(0))
));
}
#[test]
fn test_graph_error_from_edge_list_error() {
let edge_node_error =
EdgeListError::<usize>::EdgeNodeError(EdgeNodeError::NotEnoughCapacity);
let graph_error = GraphError::<usize>::from(edge_node_error);
assert!(matches!(graph_error, GraphError::OutOfCapacity));
let original_graph_error = GraphError::<usize>::NodeNotFound(42);
let edge_list_error = EdgeListError::<usize>::GraphError(original_graph_error);
let converted_graph_error = GraphError::<usize>::from(edge_list_error);
assert!(matches!(
converted_graph_error,
GraphError::NodeNotFound(42)
));
}
#[test]
fn test_edge_list_error_types() {
let edge_node_error = EdgeListError::<usize>::EdgeNodeError(EdgeNodeError::EmptyEdges);
assert!(matches!(
edge_node_error,
EdgeListError::EdgeNodeError(EdgeNodeError::EmptyEdges)
));
let capacity_error =
EdgeListError::<usize>::EdgeNodeError(EdgeNodeError::NotEnoughCapacity);
assert!(matches!(
capacity_error,
EdgeListError::EdgeNodeError(EdgeNodeError::NotEnoughCapacity)
));
let graph_error = EdgeListError::<usize>::GraphError(GraphError::NodeNotFound(0));
assert!(matches!(
graph_error,
EdgeListError::GraphError(GraphError::NodeNotFound(0))
));
}
#[test]
fn test_edge_list_with_vec_like_edges() {
let edge_array = [(0, 1), (1, 2), (2, 0)];
let _edge_list = EdgeList::<10, usize, _>::new(&edge_array[..]);
let edge_slice: &[(usize, usize)] = &[(0, 1), (1, 2)];
let _edge_list_slice = EdgeList::<10, usize, _>::new(edge_slice);
}
#[test]
fn test_edge_list_different_capacities() {
let edges = [(0, 1), (1, 2)];
let _edge_list_small = EdgeList::<3, usize, _>::new(edges);
let _edge_list_medium = EdgeList::<100, usize, _>::new(edges);
let _edge_list_large = EdgeList::<1000, usize, _>::new(edges);
}
#[test]
fn test_edge_list_graphval_functionality() {
let edges = [(0, 1), (1, 2), (2, 0)];
let edge_list = EdgeList::<10, usize, _>::new(edges);
let edges_iter = edge_list.iter_edges().unwrap();
assert_eq!(edges_iter.count(), 3);
let nodes_iter = edge_list.iter_nodes().unwrap();
let mut nodes = [0usize; 10];
let nodes_slice = collect_sorted(nodes_iter, &mut nodes);
assert_eq!(nodes_slice, &[0, 1, 2]);
}
#[test]
fn test_edge_list() {
let graph = EdgeList::<8, _, _>::new([(0usize, 1usize), (0, 2), (1, 2)]);
let _: () = graph.iter_nodes().unwrap().for_each(|_x| {});
}
#[test]
fn test_edge_list_with_values() {
let edge_data =
crate::edges::EdgeValueStruct([(0usize, 1usize, 5i32), (1, 2, 3), (0, 2, 8)]);
let graph = EdgeList::<8, _, _>::new(edge_data);
let edge_values = graph.iter_edge_values().unwrap();
let mut edges_with_values = [(0usize, 0usize, 0i32); 8];
let edges_slice = collect(
edge_values.filter_map(|(src, dst, weight_opt)| weight_opt.map(|w| (src, dst, *w))),
&mut edges_with_values,
);
assert_eq!(edges_slice, &[(0, 1, 5), (1, 2, 3), (0, 2, 8)]);
}
#[test]
fn test_edge_list_nodes_with_values() {
let edge_data = crate::edges::EdgeValueStruct([(0usize, 1usize, 10i32), (2, 3, 20)]);
let graph = EdgeList::<8, _, _>::new(edge_data);
let nodes = graph.iter_nodes().unwrap();
let mut node_list = [0usize; 8];
let node_slice = collect(nodes, &mut node_list);
assert_eq!(node_slice, &[0, 1, 2, 3]);
}
#[test]
fn test_edge_list_incoming_edge_values() {
let edge_data = crate::edges::EdgeValueStruct([
(0usize, 1usize, 5i32), (1, 2, 3), (0, 2, 8), (3, 1, 7), ]);
let graph = EdgeList::<8, _, _>::new(edge_data);
let mut incoming = [(0usize, 0i32); 8];
let incoming_slice = collect(
graph
.incoming_edge_values(1)
.unwrap()
.filter_map(|(src, weight)| weight.map(|w| (src, *w))),
&mut incoming,
);
assert_eq!(incoming_slice, &[(0, 5), (3, 7)]);
let mut incoming = [(0usize, 0i32); 8];
let incoming_slice = collect(
graph
.incoming_edge_values(2)
.unwrap()
.filter_map(|(src, weight)| weight.map(|w| (src, *w))),
&mut incoming,
);
assert_eq!(incoming_slice, &[(1, 3), (0, 8)]);
let mut incoming = [(0usize, 0i32); 8];
let incoming_slice = collect(
graph
.incoming_edge_values(0)
.unwrap()
.filter_map(|(src, weight)| weight.map(|w| (src, *w))),
&mut incoming,
);
assert_eq!(incoming_slice, &[]);
assert_eq!(graph.incoming_edge_values(99).unwrap().count(), 0);
}
#[test]
fn test_edge_list_add_edge_success() {
let edges = EdgeStructOption([None, None, None, None, None]); let mut graph = EdgeList::<10, usize, _>::new(edges);
assert_eq!(graph.iter_edges().unwrap().count(), 0);
assert!(graph.iter_nodes().is_err());
assert!(graph.add_edge(0, 1).is_ok());
assert!(graph.add_edge(1, 2).is_ok());
assert!(graph.add_edge(0, 2).is_ok());
let edge_count = graph.iter_edges().unwrap().count();
assert_eq!(edge_count, 3);
let node_count = graph.iter_nodes().unwrap().count();
assert_eq!(node_count, 3);
let mut edges = [(0usize, 0usize); 8];
let edges_slice = collect_sorted(graph.iter_edges().unwrap(), &mut edges);
assert_eq!(edges_slice, &[(0, 1), (0, 2), (1, 2)]);
}
#[test]
fn test_edge_list_add_edge_capacity_exceeded() {
let edges = EdgeStructOption([None, None]); let mut graph = EdgeList::<10, usize, _>::new(edges);
assert!(graph.add_edge(0, 1).is_ok());
assert!(graph.add_edge(1, 2).is_ok());
let result = graph.add_edge(0, 2);
assert!(matches!(
result,
Err(EdgeListError::GraphError(GraphError::OutOfCapacity))
));
}
#[test]
fn test_edge_list_remove_edge_success() {
let edges = EdgeStructOption([Some((0, 1)), Some((1, 2)), Some((0, 2)), None, None]);
let mut graph = EdgeList::<10, usize, _>::new(edges);
assert_eq!(graph.iter_edges().unwrap().count(), 3);
assert_eq!(graph.iter_nodes().unwrap().count(), 3);
assert!(graph.remove_edge(1, 2).is_ok());
assert_eq!(graph.iter_edges().unwrap().count(), 2);
let mut edges = [(0usize, 0usize); 8];
let edges_slice = collect_sorted(graph.iter_edges().unwrap(), &mut edges);
assert_eq!(edges_slice, &[(0, 1), (0, 2)]);
assert_eq!(graph.iter_nodes().unwrap().count(), 3);
}
#[test]
fn test_edge_list_remove_edge_isolates_node() {
let edges = EdgeStructOption([Some((0, 1)), Some((1, 2)), None, None, None]);
let mut graph = EdgeList::<10, usize, _>::new(edges);
assert!(graph.remove_edge(1, 2).is_ok());
assert_eq!(graph.iter_edges().unwrap().count(), 1);
let mut nodes = [0usize; 8];
let nodes_slice = collect_sorted(graph.iter_nodes().unwrap(), &mut nodes);
assert_eq!(nodes_slice, &[0, 1]); }
#[test]
fn test_edge_list_remove_edge_not_found() {
let edges = EdgeStructOption([Some((0, 1)), Some((1, 2)), None, None, None]);
let mut graph = EdgeList::<10, usize, _>::new(edges);
let result = graph.remove_edge(0, 2);
assert!(matches!(
result,
Err(EdgeListError::GraphError(GraphError::EdgeNotFound(0, 2)))
));
assert_eq!(graph.iter_edges().unwrap().count(), 2);
}
#[test]
fn test_edge_list_add_remove_edge_comprehensive() {
let edges = EdgeStructOption([None, None, None, None, None]);
let mut graph = EdgeList::<10, usize, _>::new(edges);
assert_eq!(graph.iter_edges().unwrap().count(), 0);
assert!(graph.iter_nodes().is_err());
assert!(graph.add_edge(0, 1).is_ok());
assert!(graph.add_edge(1, 2).is_ok());
assert!(graph.add_edge(2, 3).is_ok());
assert!(graph.add_edge(0, 3).is_ok());
assert_eq!(graph.iter_edges().unwrap().count(), 4);
assert_eq!(graph.iter_nodes().unwrap().count(), 4);
assert!(graph.remove_edge(1, 2).is_ok());
assert_eq!(graph.iter_edges().unwrap().count(), 3);
let result = graph.remove_edge(1, 2);
assert!(matches!(
result,
Err(EdgeListError::GraphError(GraphError::EdgeNotFound(1, 2)))
));
assert!(graph.add_edge(1, 2).is_ok());
assert_eq!(graph.iter_edges().unwrap().count(), 4);
let mut edges = [(0usize, 0usize); 8];
let edges_slice = collect_sorted(graph.iter_edges().unwrap(), &mut edges);
assert_eq!(edges_slice, &[(0, 1), (0, 3), (1, 2), (2, 3)]);
}
#[test]
fn test_edge_list_self_loops() {
let edges = EdgeStructOption([None, None, None, None, None]);
let mut graph = EdgeList::<10, usize, _>::new(edges);
assert!(graph.add_edge(0, 0).is_ok()); assert!(graph.add_edge(0, 1).is_ok());
assert!(graph.add_edge(1, 1).is_ok());
assert_eq!(graph.iter_edges().unwrap().count(), 3);
assert_eq!(graph.iter_nodes().unwrap().count(), 2);
assert!(graph.remove_edge(0, 0).is_ok());
assert_eq!(graph.iter_edges().unwrap().count(), 2);
assert_eq!(graph.iter_nodes().unwrap().count(), 2); }
#[test]
fn test_edge_list_from_graph() {
let mut dict = Dictionary::<usize, [usize; 2], 8>::new();
dict.insert(0, [1, 2]).unwrap();
dict.insert(1, [2, 0]).unwrap();
let source = MapAdjacencyList::new_unchecked(dict);
let edge_list: EdgeList<8, usize, EdgeStructOption<16, usize>> =
EdgeList::from_graph(&source).unwrap();
let mut edges = [(0usize, 0usize); 16];
let edges_slice = collect(edge_list.iter_edges().unwrap(), &mut edges);
assert_eq!(edges_slice, &[(0, 1), (0, 2), (1, 2), (1, 0)]);
}
#[test]
fn test_edge_list_from_empty_graph() {
let dict = Dictionary::<usize, [usize; 2], 8>::new();
let source = MapAdjacencyList::new_unchecked(dict);
let edge_list: EdgeList<8, usize, EdgeStructOption<16, usize>> =
EdgeList::from_graph(&source).unwrap();
let mut edges = [(0usize, 0usize); 16];
let edges_slice = collect(edge_list.iter_edges().unwrap(), &mut edges);
assert_eq!(edges_slice.len(), 0);
}
#[test]
fn test_edge_list_from_graph_trait() {
let mut dict = Dictionary::<usize, [usize; 2], 8>::new();
dict.insert(0, [1, 2]).unwrap(); dict.insert(1, [2, 0]).unwrap(); let source = MapAdjacencyList::new_unchecked(dict);
let edge_list: EdgeList<8, usize, EdgeStructOption<16, usize>> =
EdgeList::from_graph(&source).unwrap();
let mut edges = [(0usize, 0usize); 16];
let edges_slice = collect(edge_list.iter_edges().unwrap(), &mut edges);
assert_eq!(edges_slice, &[(0, 1), (0, 2), (1, 2), (1, 0)]);
}
}