use std::collections::HashMap;
use std::fmt::Debug;
use std::hash::Hash;
pub type NodeId = usize;
pub type EdgeId = usize;
pub trait NodeType: Clone + Eq + Hash + Debug {
fn as_string(&self) -> String;
}
#[derive(Debug)]
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);
}
}
}
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::*;
#[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(2, 0, 10);
assert_eq!(node.neighbors, vec![(2, vec![(0, 10)])]);
node.add_neighbor(2, 1, 20);
assert_eq!(node.neighbors, vec![(2, vec![(0, 10), (1, 20)])]);
node.add_neighbor(3, 2, 30);
assert_eq!(
node.neighbors,
vec![(2, vec![(0, 10), (1, 20)]), (3, vec![(2, 30)])]
);
}
#[test]
fn test_remove_edge() {
let mut node: HNode<f64, TestNode> = HNode::new(TestNode("Node1".to_string()));
node.add_neighbor(2, 0, 1.0);
node.add_neighbor(2, 1, 2.0);
node.add_neighbor(3, 2, 3.0);
node.remove_edge(2, 1);
assert_eq!(node.neighbors[0], (2, vec![(0, 1.0)]));
assert_eq!(node.neighbors[1], (3, vec![(2, 3.0)]));
node.remove_edge(2, 99);
assert_eq!(node.neighbors[0], (2, vec![(0, 1.0)]));
node.remove_edge(4, 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");
}
}