use crate::conversions::FromGraph;
use crate::graph::{integrity_check, Graph, GraphError, GraphWithMutableEdges, NodeIndex};
use crate::nodes::{MutableNodes, NodesIterable};
pub struct SliceAdjacencyList<NI, E, T>
where
NI: NodeIndex,
E: NodesIterable<Node = NI>,
T: AsRef<[(NI, E)]>,
{
nodes_container: T,
_phantom: core::marker::PhantomData<E>,
}
impl<NI, E, T> SliceAdjacencyList<NI, E, T>
where
NI: NodeIndex,
E: NodesIterable<Node = NI>,
T: AsRef<[(NI, E)]>,
{
pub fn new(nodes_container: T) -> Result<Self, GraphError<NI>>
where
NI: Copy,
Self: Graph<NI, Error = GraphError<NI>>,
{
let result = Self::new_unchecked(nodes_container);
integrity_check::<NI, _>(&result)?;
Ok(result)
}
pub fn new_unchecked(nodes_container: T) -> Self {
Self {
nodes_container,
_phantom: core::marker::PhantomData,
}
}
}
impl<NI, E, T> Graph<NI> for SliceAdjacencyList<NI, E, T>
where
NI: NodeIndex,
E: NodesIterable<Node = NI>,
T: AsRef<[(NI, E)]>,
{
type Error = GraphError<NI>;
fn iter_nodes(&self) -> Result<impl Iterator<Item = NI>, Self::Error> {
Ok(self.nodes_container.as_ref().iter().map(|(n, _)| *n))
}
fn iter_edges(&self) -> Result<impl Iterator<Item = (NI, NI)>, Self::Error> {
Ok(self
.nodes_container
.as_ref()
.iter()
.flat_map(|(n, e_container)| e_container.iter_nodes().map(move |m| (*n, *m))))
}
fn contains_node(&self, node: NI) -> Result<bool, Self::Error> {
Ok(self
.nodes_container
.as_ref()
.iter()
.any(|(n, _)| *n == node))
}
fn outgoing_edges(&self, node: NI) -> Result<impl Iterator<Item = NI>, Self::Error> {
let edges_option = self
.nodes_container
.as_ref()
.iter()
.find(|(n, _)| *n == node)
.map(|(_, node_data)| node_data.iter_nodes());
Ok(edges_option.into_iter().flatten().copied())
}
}
impl<NI, E, T> GraphWithMutableEdges<NI> for SliceAdjacencyList<NI, E, T>
where
NI: NodeIndex + PartialEq,
E: NodesIterable<Node = NI> + MutableNodes<NI>,
T: AsRef<[(NI, E)]> + AsMut<[(NI, E)]>,
{
fn add_edge(&mut self, source: NI, destination: NI) -> Result<(), Self::Error> {
if !self.contains_node(source)? {
return Err(GraphError::EdgeHasInvalidNode(source));
}
if !self.contains_node(destination)? {
return Err(GraphError::EdgeHasInvalidNode(destination));
}
let nodes = self.nodes_container.as_mut();
for (node_id, edge_container) in nodes.iter_mut() {
if *node_id == source {
return edge_container
.add(destination)
.map(|_| ())
.ok_or(GraphError::OutOfCapacity);
}
}
Err(GraphError::EdgeHasInvalidNode(source))
}
fn remove_edge(&mut self, source: NI, destination: NI) -> Result<(), Self::Error> {
let nodes = self.nodes_container.as_mut();
for (node_id, edge_container) in nodes.iter_mut() {
if *node_id == source {
return edge_container
.remove(destination)
.map(|_| ())
.ok_or(GraphError::EdgeNotFound(source, destination));
}
}
Err(GraphError::EdgeNotFound(source, destination))
}
}
impl<NI, E, const N: usize> FromGraph<NI, GraphError<NI>>
for SliceAdjacencyList<NI, E, [(NI, E); N]>
where
NI: NodeIndex + Copy + Default,
E: NodesIterable<Node = NI> + crate::nodes::MutableNodes<NI> + Default,
{
fn from_graph<G>(source_graph: &G) -> Result<Self, GraphError<NI>>
where
G: Graph<NI>,
GraphError<NI>: From<G::Error>,
{
let node_count = source_graph.iter_nodes()?.count();
if node_count != N {
return Err(GraphError::OutOfCapacity);
}
let mut container =
core::array::from_fn::<(NI, E), N, _>(|_| (NI::default(), E::default()));
for (i, node) in source_graph.iter_nodes()?.enumerate() {
container[i] = (node, E::default());
}
for (node, edge_container) in container.iter_mut().take(N) {
let outgoing_iter = source_graph.outgoing_edges(*node)?;
for target in outgoing_iter {
if edge_container.add(target).is_none() {
return Err(GraphError::OutOfCapacity);
}
}
}
Ok(Self::new_unchecked(container))
}
}
#[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::EdgeStructOption;
use crate::graph::GraphWithMutableEdges;
use crate::nodes::NodeStructOption;
use crate::tests::{collect, collect_sorted};
#[test]
fn test_slice_adjacency_list_new() {
let adj_list_data = [(0, [1, 2]), (1, [2, 0]), (2, [0, 0])];
let graph = SliceAdjacencyList::new(adj_list_data).unwrap();
let mut nodes = [0usize; 4];
let nodes_slice = collect(graph.iter_nodes().unwrap(), &mut nodes);
assert_eq!(nodes_slice, &[0, 1, 2]);
}
#[test]
fn test_slice_adjacency_list_new_unchecked() {
let adj_list_data = [(0, [1, 2]), (1, [2, 0]), (2, [0, 0])];
let graph = SliceAdjacencyList::new_unchecked(adj_list_data);
let mut nodes = [0usize; 4];
let nodes_slice = collect(graph.iter_nodes().unwrap(), &mut nodes);
assert_eq!(nodes_slice, &[0, 1, 2]);
}
#[test]
fn test_slice_adjacency_list_with_empty_graph() {
let adj_list_data: [(usize, [usize; 0]); 0] = [];
let graph = SliceAdjacencyList::new(adj_list_data).unwrap();
assert_eq!(graph.iter_nodes().unwrap().count(), 0);
}
#[test]
fn test_slice_adjacency_list_single_node() {
let adj_list_data = [(42, [])];
let graph = SliceAdjacencyList::new(adj_list_data).unwrap();
let mut nodes = [0usize; 2];
let nodes_slice = collect(graph.iter_nodes().unwrap(), &mut nodes);
assert_eq!(nodes_slice, &[42]);
}
#[test]
fn test_graphval_iter_nodes() {
let adj_list_data = [(0, [1, 2]), (1, [2, 0]), (2, [0, 0])];
let graph = SliceAdjacencyList::new_unchecked(adj_list_data);
let mut nodes = [0usize; 4];
let nodes_slice = collect(graph.iter_nodes().unwrap(), &mut nodes);
assert_eq!(nodes_slice, &[0, 1, 2]);
}
#[test]
fn test_graphval_iter_edges() {
let adj_list_data = [(0, [1, 2]), (1, [2, 0]), (2, [0, 0])];
let graph = SliceAdjacencyList::new_unchecked(adj_list_data);
let mut edges = [(0usize, 0usize); 8];
let edges_slice = collect(graph.iter_edges().unwrap(), &mut edges);
assert_eq!(edges_slice.len(), 6);
assert_eq!(
edges_slice,
&[(0, 1), (0, 2), (1, 2), (1, 0), (2, 0), (2, 0)]
);
}
#[test]
fn test_graphval_contains_node() {
let adj_list_data = [(0, [1, 2]), (1, [2, 0]), (2, [0, 0])];
let graph = SliceAdjacencyList::new_unchecked(adj_list_data);
assert!(graph.contains_node(0).unwrap());
assert!(graph.contains_node(1).unwrap());
assert!(graph.contains_node(2).unwrap());
assert!(!graph.contains_node(3).unwrap());
assert!(!graph.contains_node(42).unwrap());
}
#[test]
fn test_graphval_outgoing_edges() {
let adj_list_data = [(0, [1, 2]), (1, [2, 0]), (2, [0, 0])];
let graph = SliceAdjacencyList::new_unchecked(adj_list_data);
let mut edges = [0usize; 4];
let edges_slice = collect(graph.outgoing_edges(0).unwrap(), &mut edges);
assert_eq!(edges_slice, &[1, 2]);
let mut edges = [0usize; 4];
let edges_slice = collect(graph.outgoing_edges(1).unwrap(), &mut edges);
assert_eq!(edges_slice, &[2, 0]);
let mut edges = [0usize; 4];
let edges_slice = collect(graph.outgoing_edges(2).unwrap(), &mut edges);
assert_eq!(edges_slice, &[0, 0]);
assert_eq!(graph.outgoing_edges(99).unwrap().count(), 0);
}
#[test]
fn test_graphval_empty_graph() {
let adj_list_data: [(usize, [usize; 0]); 0] = [];
let graph = SliceAdjacencyList::new_unchecked(adj_list_data);
assert_eq!(graph.iter_nodes().unwrap().count(), 0);
assert_eq!(graph.iter_edges().unwrap().count(), 0);
assert!(!graph.contains_node(0).unwrap());
assert!(!graph.contains_node(42).unwrap());
}
#[test]
fn test_graphval_self_loops() {
let adj_list_data = [(0, [0, 1]), (1, [1, 1])];
let graph = SliceAdjacencyList::new_unchecked(adj_list_data);
let mut edges = [(0usize, 0usize); 8];
let edges_slice = collect(graph.iter_edges().unwrap(), &mut edges);
assert_eq!(edges_slice, &[(0, 0), (0, 1), (1, 1), (1, 1)]);
let mut edges = [0usize; 4];
let edges_slice = collect(graph.outgoing_edges(0).unwrap(), &mut edges);
assert_eq!(edges_slice, &[0, 1]);
}
#[test]
fn test_graphval_single_node_no_edges() {
let adj_list_data = [(42, [])];
let graph = SliceAdjacencyList::new_unchecked(adj_list_data);
let mut nodes = [0usize; 2];
let nodes_slice = collect(graph.iter_nodes().unwrap(), &mut nodes);
assert_eq!(nodes_slice, &[42]);
assert!(graph.contains_node(42).unwrap());
assert!(!graph.contains_node(0).unwrap());
assert_eq!(graph.iter_edges().unwrap().count(), 0);
assert_eq!(graph.outgoing_edges(42).unwrap().count(), 0);
}
#[test]
fn test_graphval_multiple_nodes_same_target() {
let adj_list_data = [(0, [1, 0]), (2, [1, 0]), (1, [0, 0])];
let graph = SliceAdjacencyList::new_unchecked(adj_list_data);
let mut edges = [(0usize, 0usize); 8];
let edges_slice = collect(graph.iter_edges().unwrap(), &mut edges);
assert_eq!(
edges_slice,
&[(0, 1), (0, 0), (2, 1), (2, 0), (1, 0), (1, 0)]
);
assert!(graph.contains_node(0).unwrap());
assert!(graph.contains_node(1).unwrap());
assert!(graph.contains_node(2).unwrap());
}
#[test]
fn test_slice_adjacency_list_with_node_struct_option() {
let adj_list_data = [
(0, NodeStructOption([Some(1), Some(2), None])), (1, NodeStructOption([Some(2), None, None])), (2, NodeStructOption([Some(0), None, None])), ];
let graph = SliceAdjacencyList::new_unchecked(adj_list_data);
let mut nodes = [0usize; 4];
let nodes_slice = collect(graph.iter_nodes().unwrap(), &mut nodes);
assert_eq!(nodes_slice, &[0, 1, 2]);
let mut edges = [(0usize, 0usize); 8];
let edges_slice = collect(graph.iter_edges().unwrap(), &mut edges);
assert_eq!(edges_slice, &[(0, 1), (0, 2), (1, 2), (2, 0)]);
let mut edges = [0usize; 4];
let edges_slice = collect(graph.outgoing_edges(0).unwrap(), &mut edges);
assert_eq!(edges_slice, &[1, 2]);
let mut edges = [0usize; 4];
let edges_slice = collect(graph.outgoing_edges(1).unwrap(), &mut edges);
assert_eq!(edges_slice, &[2]);
let mut edges = [0usize; 4];
let edges_slice = collect(graph.outgoing_edges(2).unwrap(), &mut edges);
assert_eq!(edges_slice, &[0]);
}
#[test]
fn test_slice_adjacency_list_option_based_edges() {
let _edge_data =
EdgeStructOption([Some((0, 1)), Some((0, 2)), Some((1, 2)), Some((2, 0)), None]);
let adj_list_data = [
(0, NodeStructOption([Some(1), Some(2), None, None])), (1, NodeStructOption([Some(2), None, None, None])), (2, NodeStructOption([Some(0), None, None, None])), ];
let graph = SliceAdjacencyList::new_unchecked(adj_list_data);
let mut edges = [(0usize, 0usize); 8];
let edges_slice = collect(graph.iter_edges().unwrap(), &mut edges);
assert_eq!(edges_slice, &[(0, 1), (0, 2), (1, 2), (2, 0)]);
}
#[test]
fn test_mutable_edges_add_edge_success() {
let adj_list_data = [
(0, NodeStructOption([Some(1), None, None, None])), (1, NodeStructOption([None, None, None, None])), (2, NodeStructOption([Some(0), None, None, None])), ];
let mut graph = SliceAdjacencyList::new_unchecked(adj_list_data);
assert!(graph.add_edge(0, 2).is_ok()); assert!(graph.add_edge(1, 0).is_ok()); assert!(graph.add_edge(1, 2).is_ok());
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, 0), (1, 2), (2, 0)]);
}
#[test]
fn test_mutable_edges_add_edge_invalid_nodes() {
let adj_list_data = [
(0, NodeStructOption([Some(1), None, None])),
(1, NodeStructOption([None, None, None])),
];
let mut graph = SliceAdjacencyList::new_unchecked(adj_list_data);
let result = graph.add_edge(99, 1);
assert!(matches!(result, Err(GraphError::EdgeHasInvalidNode(99))));
let result = graph.add_edge(0, 99);
assert!(matches!(result, Err(GraphError::EdgeHasInvalidNode(99))));
let result = graph.add_edge(98, 99);
assert!(matches!(result, Err(GraphError::EdgeHasInvalidNode(98))));
}
#[test]
fn test_mutable_edges_add_edge_capacity_exceeded() {
let adj_list_data = [
(0, NodeStructOption([Some(1), Some(2)])), (1, NodeStructOption([None, None])),
(2, NodeStructOption([None, None])),
];
let mut graph = SliceAdjacencyList::new_unchecked(adj_list_data);
let result = graph.add_edge(0, 1); assert!(matches!(result, Err(GraphError::OutOfCapacity)));
assert!(graph.add_edge(1, 0).is_ok());
}
#[test]
fn test_mutable_edges_remove_edge_success() {
let adj_list_data = [
(0, NodeStructOption([Some(1), Some(2), None])), (1, NodeStructOption([Some(2), Some(0), None])), (2, NodeStructOption([Some(0), None, None])), ];
let mut graph = SliceAdjacencyList::new_unchecked(adj_list_data);
assert_eq!(graph.iter_edges().unwrap().count(), 5);
assert!(graph.remove_edge(0, 1).is_ok()); assert!(graph.remove_edge(1, 0).is_ok());
let mut edges = [(0usize, 0usize); 8];
let edges_slice = collect_sorted(graph.iter_edges().unwrap(), &mut edges);
assert_eq!(edges_slice, &[(0, 2), (1, 2), (2, 0)]);
}
#[test]
fn test_mutable_edges_remove_edge_not_found() {
let adj_list_data = [
(0, NodeStructOption([Some(1), None, None])), (1, NodeStructOption([Some(2), None, None])), (2, NodeStructOption([None, None, None])), ];
let mut graph = SliceAdjacencyList::new_unchecked(adj_list_data);
let result = graph.remove_edge(0, 2);
assert!(matches!(result, Err(GraphError::EdgeNotFound(0, 2))));
let result = graph.remove_edge(2, 0);
assert!(matches!(result, Err(GraphError::EdgeNotFound(2, 0))));
let result = graph.remove_edge(99, 1);
assert!(matches!(result, Err(GraphError::EdgeNotFound(99, 1))));
}
#[test]
fn test_mutable_edges_add_remove_comprehensive() {
let adj_list_data = [
(0, NodeStructOption([None, None, None, None])), (1, NodeStructOption([None, None, None, None])), (2, NodeStructOption([None, None, None, None])), ];
let mut graph = SliceAdjacencyList::new_unchecked(adj_list_data);
assert_eq!(graph.iter_edges().unwrap().count(), 0);
assert!(graph.add_edge(0, 1).is_ok());
assert!(graph.add_edge(0, 2).is_ok());
assert!(graph.add_edge(1, 2).is_ok());
assert!(graph.add_edge(2, 0).is_ok());
assert_eq!(graph.iter_edges().unwrap().count(), 4);
assert!(graph.remove_edge(0, 1).is_ok());
assert!(graph.remove_edge(1, 2).is_ok());
assert_eq!(graph.iter_edges().unwrap().count(), 2);
assert!(graph.add_edge(0, 1).is_ok());
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, 2), (1, 2), (2, 0)]);
}
#[test]
fn test_slice_adjacency_list_from_graph_exact_size() {
let mut dict = Dictionary::<usize, [usize; 2], 8>::new();
dict.insert(0, [1, 2]).unwrap(); dict.insert(1, [2, 0]).unwrap(); dict.insert(2, [0, 1]).unwrap(); let source = MapAdjacencyList::new_unchecked(dict);
let slice_graph: SliceAdjacencyList<
usize,
NodeStructOption<4, usize>,
[(usize, NodeStructOption<4, usize>); 3],
> = SliceAdjacencyList::from_graph(&source).unwrap();
let mut nodes = [0usize; 8];
let nodes_slice = collect_sorted(slice_graph.iter_nodes().unwrap(), &mut nodes);
assert_eq!(nodes_slice, &[0, 1, 2]);
let mut edges = [(0usize, 0usize); 16];
let edges_slice = collect_sorted(slice_graph.iter_edges().unwrap(), &mut edges);
assert_eq!(
edges_slice,
&[(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]
);
}
#[test]
fn test_slice_adjacency_list_from_graph_wrong_node_count() {
let mut dict = Dictionary::<usize, [usize; 2], 8>::new();
dict.insert(0, [1, 2]).unwrap();
dict.insert(1, [2, 0]).unwrap();
dict.insert(2, [0, 1]).unwrap();
let source = MapAdjacencyList::new_unchecked(dict);
let result: Result<
SliceAdjacencyList<
usize,
NodeStructOption<4, usize>,
[(usize, NodeStructOption<4, usize>); 4],
>,
_,
> = SliceAdjacencyList::from_graph(&source);
assert!(matches!(result, Err(GraphError::OutOfCapacity)));
}
}