use std::collections::HashMap;
use super::types::{Edge, Node, MAX_TUI_NODES};
#[derive(Debug, Clone)]
pub struct Graph<N, E> {
pub(crate) nodes: HashMap<String, Node<N>>,
pub(crate) edges: Vec<Edge<E>>,
adjacency: HashMap<String, Vec<String>>,
}
impl<N, E> Default for Graph<N, E> {
fn default() -> Self {
Self::new()
}
}
impl<N, E> Graph<N, E> {
#[must_use]
pub fn new() -> Self {
Self { nodes: HashMap::new(), edges: Vec::new(), adjacency: HashMap::new() }
}
pub fn add_node(&mut self, node: Node<N>) {
let id = node.id.clone();
self.nodes.insert(id.clone(), node);
self.adjacency.entry(id).or_default();
}
pub fn add_edge(&mut self, edge: Edge<E>) {
self.adjacency.entry(edge.from.clone()).or_default().push(edge.to.clone());
self.edges.push(edge);
}
#[must_use]
pub fn node_count(&self) -> usize {
self.nodes.len()
}
#[must_use]
pub fn edge_count(&self) -> usize {
self.edges.len()
}
#[must_use]
pub fn get_node(&self, id: &str) -> Option<&Node<N>> {
self.nodes.get(id)
}
pub fn get_node_mut(&mut self, id: &str) -> Option<&mut Node<N>> {
self.nodes.get_mut(id)
}
pub fn nodes(&self) -> impl Iterator<Item = &Node<N>> {
self.nodes.values()
}
pub fn nodes_mut(&mut self) -> impl Iterator<Item = &mut Node<N>> {
self.nodes.values_mut()
}
pub fn edges(&self) -> impl Iterator<Item = &Edge<E>> {
self.edges.iter()
}
#[must_use]
pub fn neighbors(&self, id: &str) -> Vec<&str> {
self.adjacency.get(id).map(|v| v.iter().map(String::as_str).collect()).unwrap_or_default()
}
#[must_use]
pub fn exceeds_tui_limit(&self) -> bool {
self.nodes.len() > MAX_TUI_NODES
}
#[must_use]
pub fn top_nodes_by_importance(&self, n: usize) -> Vec<&Node<N>> {
let mut nodes: Vec<_> = self.nodes.values().collect();
nodes.sort_by(|a, b| {
b.importance.partial_cmp(&a.importance).unwrap_or(std::cmp::Ordering::Equal)
});
nodes.into_iter().take(n).collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_graph_new() {
let graph: Graph<(), ()> = Graph::new();
assert_eq!(graph.node_count(), 0);
assert_eq!(graph.edge_count(), 0);
}
#[test]
fn test_graph_default() {
let graph: Graph<i32, &str> = Graph::default();
assert_eq!(graph.node_count(), 0);
}
#[test]
fn test_graph_add_node() {
let mut graph: Graph<i32, ()> = Graph::new();
graph.add_node(Node::new("A", 42));
assert_eq!(graph.node_count(), 1);
assert!(graph.get_node("A").is_some());
}
#[test]
fn test_graph_add_edge() {
let mut graph: Graph<(), &str> = Graph::new();
graph.add_node(Node::new("A", ()));
graph.add_node(Node::new("B", ()));
graph.add_edge(Edge::new("A", "B", "connects"));
assert_eq!(graph.edge_count(), 1);
}
#[test]
fn test_graph_get_node_not_found() {
let graph: Graph<(), ()> = Graph::new();
assert!(graph.get_node("X").is_none());
}
#[test]
fn test_graph_get_node_mut() {
let mut graph: Graph<i32, ()> = Graph::new();
graph.add_node(Node::new("A", 10));
if let Some(node) = graph.get_node_mut("A") {
node.importance = 5.0;
}
assert_eq!(graph.get_node("A").expect("unexpected failure").importance, 5.0);
}
#[test]
fn test_graph_nodes_iterator() {
let mut graph: Graph<i32, ()> = Graph::new();
graph.add_node(Node::new("A", 1));
graph.add_node(Node::new("B", 2));
let count = graph.nodes().count();
assert_eq!(count, 2);
}
#[test]
fn test_graph_nodes_mut_iterator() {
let mut graph: Graph<i32, ()> = Graph::new();
graph.add_node(Node::new("A", 1));
for node in graph.nodes_mut() {
node.importance = 0.5;
}
assert_eq!(graph.get_node("A").expect("unexpected failure").importance, 0.5);
}
#[test]
fn test_graph_edges_iterator() {
let mut graph: Graph<(), i32> = Graph::new();
graph.add_node(Node::new("A", ()));
graph.add_node(Node::new("B", ()));
graph.add_edge(Edge::new("A", "B", 100));
let edges: Vec<_> = graph.edges().collect();
assert_eq!(edges.len(), 1);
assert_eq!(edges[0].data, 100);
}
#[test]
fn test_graph_neighbors() {
let mut graph: Graph<(), ()> = Graph::new();
graph.add_node(Node::new("A", ()));
graph.add_node(Node::new("B", ()));
graph.add_node(Node::new("C", ()));
graph.add_edge(Edge::new("A", "B", ()));
graph.add_edge(Edge::new("A", "C", ()));
let neighbors = graph.neighbors("A");
assert_eq!(neighbors.len(), 2);
}
#[test]
fn test_graph_neighbors_empty() {
let graph: Graph<(), ()> = Graph::new();
let neighbors = graph.neighbors("X");
assert!(neighbors.is_empty());
}
#[test]
fn test_graph_exceeds_tui_limit() {
let graph: Graph<(), ()> = Graph::new();
assert!(!graph.exceeds_tui_limit());
}
#[test]
fn test_graph_top_nodes_by_importance() {
let mut graph: Graph<(), ()> = Graph::new();
for i in 0..5 {
let mut node = Node::new(format!("n{}", i), ());
node.importance = i as f32;
graph.add_node(node);
}
let top = graph.top_nodes_by_importance(3);
assert_eq!(top.len(), 3);
assert!(top[0].importance >= top[1].importance);
assert!(top[1].importance >= top[2].importance);
}
#[test]
fn test_graph_top_nodes_fewer_than_n() {
let mut graph: Graph<(), ()> = Graph::new();
graph.add_node(Node::new("A", ()));
let top = graph.top_nodes_by_importance(10);
assert_eq!(top.len(), 1);
}
}