use std::collections::HashMap;
use std::fmt::Debug;
use std::hash::Hash;
pub use crate::core::view::{EdgeId, NodeId};
pub trait NodeType: Clone + Eq + Hash + Debug {
fn as_string(&self) -> String;
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct HNode<W, N: NodeType> {
pub data: N,
pub neighbors: Vec<(NodeId, Vec<(EdgeId, W)>)>,
pub attributes: HashMap<String, String>,
}
impl<W, N: NodeType> HNode<W, N> {
pub fn new(data: N) -> Self {
Self {
data,
neighbors: Vec::new(),
attributes: HashMap::new(),
}
}
pub fn add_neighbor(&mut self, neighbor: NodeId, edge_id: EdgeId, weight: W) {
if let Some((_, edges)) = self.neighbors.iter_mut().find(|(id, _)| *id == neighbor) {
edges.push((edge_id, weight));
} else {
self.neighbors.push((neighbor, vec![(edge_id, weight)]));
}
}
pub fn remove_edge(&mut self, neighbor: NodeId, edge_id: EdgeId) {
if let Some((_, edges)) = self.neighbors.iter_mut().find(|(id, _)| *id == neighbor) {
edges.retain(|&(id, _)| id != edge_id);
}
self.neighbors.retain(|(_, edges)| !edges.is_empty());
}
pub fn remove_neighbor(&mut self, neighbor: NodeId) -> Vec<EdgeId> {
let mut removed = Vec::new();
self.neighbors.retain(|(id, edges)| {
if *id == neighbor {
removed.extend(edges.iter().map(|&(edge_id, _)| edge_id));
false
} else {
true
}
});
removed
}
}
impl NodeType for String {
fn as_string(&self) -> String {
self.clone()
}
}
impl NodeType for i32 {
fn as_string(&self) -> String {
self.to_string()
}
}
impl NodeType for i64 {
fn as_string(&self) -> String {
self.to_string()
}
}
impl NodeType for u64 {
fn as_string(&self) -> String {
self.to_string()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::view::{EdgeId, NodeId};
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
struct TestNode(String);
impl NodeType for TestNode {
fn as_string(&self) -> String {
self.0.clone()
}
}
#[test]
fn test_node_creation() {
let node: HNode<f64, TestNode> = HNode::new(TestNode("Node1".to_string()));
assert_eq!(node.data.as_string(), "Node1");
assert!(node.neighbors.is_empty());
assert!(node.attributes.is_empty());
}
#[test]
fn test_add_neighbor() {
let mut node: HNode<u32, TestNode> = HNode::new(TestNode("Node1".to_string()));
node.add_neighbor(NodeId::from_index(2), EdgeId::from_index(0), 10);
assert_eq!(
node.neighbors,
vec![(NodeId::from_index(2), vec![(EdgeId::from_index(0), 10)])]
);
node.add_neighbor(NodeId::from_index(2), EdgeId::from_index(1), 20);
assert_eq!(
node.neighbors,
vec![(
NodeId::from_index(2),
vec![(EdgeId::from_index(0), 10), (EdgeId::from_index(1), 20)]
)]
);
node.add_neighbor(NodeId::from_index(3), EdgeId::from_index(2), 30);
assert_eq!(
node.neighbors,
vec![
(
NodeId::from_index(2),
vec![(EdgeId::from_index(0), 10), (EdgeId::from_index(1), 20)]
),
(NodeId::from_index(3), vec![(EdgeId::from_index(2), 30)])
]
);
}
#[test]
fn test_remove_edge() {
let mut node: HNode<f64, TestNode> = HNode::new(TestNode("Node1".to_string()));
node.add_neighbor(NodeId::from_index(2), EdgeId::from_index(0), 1.0);
node.add_neighbor(NodeId::from_index(2), EdgeId::from_index(1), 2.0);
node.add_neighbor(NodeId::from_index(3), EdgeId::from_index(2), 3.0);
node.remove_edge(NodeId::from_index(2), EdgeId::from_index(1));
assert_eq!(
node.neighbors[0],
(NodeId::from_index(2), vec![(EdgeId::from_index(0), 1.0)])
);
assert_eq!(
node.neighbors[1],
(NodeId::from_index(3), vec![(EdgeId::from_index(2), 3.0)])
);
node.remove_edge(NodeId::from_index(2), EdgeId::from_index(99));
assert_eq!(
node.neighbors[0],
(NodeId::from_index(2), vec![(EdgeId::from_index(0), 1.0)])
);
node.remove_edge(NodeId::from_index(4), EdgeId::from_index(0));
assert_eq!(node.neighbors.len(), 2);
}
#[test]
fn test_attributes() {
let mut node: HNode<i32, TestNode> = HNode::new(TestNode("Node1".to_string()));
node.attributes
.insert("key1".to_string(), "value1".to_string());
node.attributes
.insert("key2".to_string(), "value2".to_string());
assert_eq!(node.attributes.get("key1"), Some(&"value1".to_string()));
assert_eq!(node.attributes.get("key2"), Some(&"value2".to_string()));
assert_eq!(node.attributes.len(), 2);
node.attributes
.insert("key1".to_string(), "new_value".to_string());
assert_eq!(node.attributes.get("key1"), Some(&"new_value".to_string()));
}
#[test]
fn test_node_type_primitives() {
let string_node: HNode<f64, String> = HNode::new("Test".to_string());
assert_eq!(string_node.data.as_string(), "Test");
let i32_node: HNode<f64, i32> = HNode::new(42);
assert_eq!(i32_node.data.as_string(), "42");
let i64_node: HNode<f64, i64> = HNode::new(1234567890);
assert_eq!(i64_node.data.as_string(), "1234567890");
let u64_node: HNode<f64, u64> = HNode::new(9876543210);
assert_eq!(u64_node.data.as_string(), "9876543210");
}
}