use std::{borrow::Cow, sync::{Arc, RwLock}};
#[cfg(feature = "serde")]
use serde::{ser::{Serialize, Serializer}, de::{Deserialize, Deserializer}};
use crate::{EdgeID, Edges, NodeID};
#[derive(Debug, Clone)]
pub struct Node<NData>
where
NData: Clone + 'static,
{
pub id: NodeID,
pub in_edges: Arc<RwLock<Edges>>,
pub out_edges: Arc<RwLock<Edges>>,
pub data: Cow<'static, NData>,
}
impl<NData> Node<NData>
where
NData: Clone + 'static,
{
pub fn new(id: NodeID, data: NData) -> Self {
Node {
id,
in_edges: Arc::new(RwLock::new(Edges::new())),
out_edges: Arc::new(RwLock::new(Edges::new())),
data: Cow::Owned(data),
}
}
pub fn setting_data(&self, data: NData) -> Self {
Node {
id: self.id.clone(),
in_edges: self.in_edges.clone(),
out_edges: self.out_edges.clone(),
data: Cow::Owned(data),
}
}
fn _update_in_edges(&mut self, f: impl FnOnce(&mut Edges)) {
let mut in_edges = self.in_edges.write().unwrap().clone();
f(&mut in_edges);
self.in_edges = Arc::new(RwLock::new(in_edges));
}
fn _update_out_edges(&mut self, f: impl FnOnce(&mut Edges)) {
let mut out_edges = self.out_edges.write().unwrap().clone();
f(&mut out_edges);
self.out_edges = Arc::new(RwLock::new(out_edges));
}
pub fn inserting_in_edge(&self, edge_id: EdgeID) -> Self {
let mut new_self = self.clone();
new_self._update_in_edges(|in_edges| {
in_edges.insert(edge_id);
});
new_self
}
pub fn removing_in_edge(&self, edge_id: &EdgeID) -> Self {
let mut new_self = self.clone();
new_self._update_in_edges(|in_edges| {
in_edges.remove(edge_id);
});
new_self
}
pub fn inserting_out_edge(&self, edge_id: EdgeID) -> Self {
let mut new_self = self.clone();
new_self._update_out_edges(|out_edges| {
out_edges.insert(edge_id);
});
new_self
}
pub fn removing_out_edge(&self, edge_id: &EdgeID) -> Self {
let mut new_self = self.clone();
new_self._update_out_edges(|out_edges| {
out_edges.remove(edge_id);
});
new_self
}
}
impl<NData> PartialEq for Node<NData>
where
NData: Clone + PartialEq + 'static,
{
fn eq(&self, other: &Self) -> bool {
self.id == other.id && self.data == other.data
}
}
#[cfg(feature = "serde")]
impl<NData> Serialize for Node<NData>
where
NData: Clone + Serialize + 'static,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if std::mem::size_of::<NData>() == 0 {
self.id.serialize(serializer)
} else {
(&self.id, &self.data).serialize(serializer)
}
}
}
#[cfg(feature = "serde")]
impl<'de, NData> Deserialize<'de> for Node<NData>
where
NData: Clone + Deserialize<'de> + 'static + Default,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
if std::mem::size_of::<NData>() == 0 {
let node_id = NodeID::deserialize(deserializer)?;
Ok(Node::new(node_id, NData::default()))
} else {
let (node_id, data) = <(NodeID, NData)>::deserialize(deserializer)?;
Ok(Node::new(node_id, data))
}
}
}
#[cfg(all(test, feature = "serde", feature = "serde_json"))]
mod tests {
use crate::nid;
use super::*;
use serde_test::{Token, assert_tokens, Configure};
#[test]
fn node_with_data_round_trip() {
let node: Node<i32> = Node::new(nid!("NodeA"), 99);
assert_tokens(
&node.compact(),
&[
Token::Tuple { len: 2 },
Token::Str("NodeA"),
Token::I32(99),
Token::TupleEnd,
],
);
}
#[test]
fn node_with_unit_data_round_trip() {
let node: Node<()> = Node::new(nid!("NodeB"), ());
assert_tokens(
&node.compact(),
&[
Token::Str("NodeB"),
],
);
}
#[test]
fn node_with_data_json_round_trip() {
let node: Node<i32> = Node::new(nid!("NodeA"), 99);
let json = serde_json::to_string(&node).unwrap();
assert_eq!(json, r#"["NodeA",99]"#);
let deserialized_node: Node<i32> = serde_json::from_str(&json).unwrap();
assert_eq!(deserialized_node, node);
}
#[test]
fn node_with_unit_data_json_round_trip() {
let node: Node<()> = Node::new(nid!("NodeB"), ());
let json = serde_json::to_string(&node).unwrap();
assert_eq!(json, r#""NodeB""#);
let deserialized_node: Node<()> = serde_json::from_str(&json).unwrap();
assert_eq!(deserialized_node, node);
}
}