wolf_graph/details/
node.rs

1use std::{borrow::Cow, sync::{Arc, RwLock}};
2
3#[cfg(feature = "serde")]
4use serde::{ser::{Serialize, Serializer}, de::{Deserialize, Deserializer}};
5
6use crate::{EdgeID, Edges, NodeID};
7
8#[derive(Debug, Clone)]
9pub struct Node<NData>
10where
11    NData: Clone + 'static,
12{
13    pub id: NodeID,
14    pub in_edges: Arc<RwLock<Edges>>,
15    pub out_edges: Arc<RwLock<Edges>>,
16    pub data: Cow<'static, NData>,
17}
18
19impl<NData> Node<NData>
20where
21    NData: Clone + 'static,
22{
23    pub fn new(id: NodeID, data: NData) -> Self {
24        Node {
25            id,
26            in_edges: Arc::new(RwLock::new(Edges::new())),
27            out_edges: Arc::new(RwLock::new(Edges::new())),
28            data: Cow::Owned(data),
29        }
30    }
31
32    pub fn setting_data(&self, data: NData) -> Self {
33        Node {
34            id: self.id.clone(),
35            in_edges: self.in_edges.clone(),
36            out_edges: self.out_edges.clone(),
37            data: Cow::Owned(data),
38        }
39    }
40
41    fn _update_in_edges(&mut self, f: impl FnOnce(&mut Edges)) {
42        let mut in_edges = self.in_edges.write().unwrap().clone();
43        f(&mut in_edges);
44        self.in_edges = Arc::new(RwLock::new(in_edges));
45    }
46
47    fn _update_out_edges(&mut self, f: impl FnOnce(&mut Edges)) {
48        let mut out_edges = self.out_edges.write().unwrap().clone();
49        f(&mut out_edges);
50        self.out_edges = Arc::new(RwLock::new(out_edges));
51    }
52
53    pub fn inserting_in_edge(&self, edge_id: EdgeID) -> Self {
54        let mut new_self = self.clone();
55        new_self._update_in_edges(|in_edges| {
56            in_edges.insert(edge_id);
57        });
58        new_self
59    }
60
61    pub fn removing_in_edge(&self, edge_id: &EdgeID) -> Self {
62        let mut new_self = self.clone();
63        new_self._update_in_edges(|in_edges| {
64            in_edges.remove(edge_id);
65        });
66        new_self
67    }
68
69    pub fn inserting_out_edge(&self, edge_id: EdgeID) -> Self {
70        let mut new_self = self.clone();
71        new_self._update_out_edges(|out_edges| {
72            out_edges.insert(edge_id);
73        });
74        new_self
75    }
76
77    pub fn removing_out_edge(&self, edge_id: &EdgeID) -> Self {
78        let mut new_self = self.clone();
79        new_self._update_out_edges(|out_edges| {
80            out_edges.remove(edge_id);
81        });
82        new_self
83    }
84}
85
86impl<NData> PartialEq for Node<NData>
87where
88    NData: Clone + PartialEq + 'static,
89{
90    fn eq(&self, other: &Self) -> bool {
91        // We do not compare the in edges or out edges
92        // because they are denormalized and derived from
93        // the edges of the graph.
94        self.id == other.id && self.data == other.data
95    }
96}
97
98#[cfg(feature = "serde")]
99impl<NData> Serialize for Node<NData>
100where
101    NData: Clone + Serialize + 'static,
102{
103    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
104    where
105        S: Serializer,
106    {
107        // If there is no data, we serialize just the node ID
108        if std::mem::size_of::<NData>() == 0 {
109            self.id.serialize(serializer)
110        } else {
111            // Otherwise, we serialize the node ID and the data as a tuple
112            (&self.id, &self.data).serialize(serializer)
113        }
114    }
115}
116
117#[cfg(feature = "serde")]
118impl<'de, NData> Deserialize<'de> for Node<NData>
119where
120    NData: Clone + Deserialize<'de> + 'static + Default,
121{
122    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
123    where
124        D: Deserializer<'de>,
125    {
126        if std::mem::size_of::<NData>() == 0 {
127            let node_id = NodeID::deserialize(deserializer)?;
128            Ok(Node::new(node_id, NData::default()))
129        } else {
130            let (node_id, data) = <(NodeID, NData)>::deserialize(deserializer)?;
131            Ok(Node::new(node_id, data))
132        }
133    }
134}
135
136#[cfg(all(test, feature = "serde", feature = "serde_json"))]
137mod tests {
138    use crate::nid;
139
140    use super::*;
141    use serde_test::{Token, assert_tokens, Configure};
142
143    #[test]
144    fn node_with_data_round_trip() {
145        let node: Node<i32> = Node::new(nid!("NodeA"), 99);
146
147        assert_tokens(
148            &node.compact(),
149            &[
150                Token::Tuple { len: 2 },
151                Token::Str("NodeA"),
152                Token::I32(99),
153                Token::TupleEnd,
154            ],
155        );
156    }
157
158    #[test]
159    fn node_with_unit_data_round_trip() {
160        let node: Node<()> = Node::new(nid!("NodeB"), ());
161
162        assert_tokens(
163            &node.compact(),
164            &[
165                Token::Str("NodeB"),
166            ],
167        );
168    }
169
170    #[test]
171    fn node_with_data_json_round_trip() {
172        let node: Node<i32> = Node::new(nid!("NodeA"), 99);
173        let json = serde_json::to_string(&node).unwrap();
174        assert_eq!(json, r#"["NodeA",99]"#);
175
176        let deserialized_node: Node<i32> = serde_json::from_str(&json).unwrap();
177        assert_eq!(deserialized_node, node);
178    }
179
180    #[test]
181    fn node_with_unit_data_json_round_trip() {
182        let node: Node<()> = Node::new(nid!("NodeB"), ());
183
184        let json = serde_json::to_string(&node).unwrap();
185        assert_eq!(json, r#""NodeB""#);
186
187        let deserialized_node: Node<()> = serde_json::from_str(&json).unwrap();
188        assert_eq!(deserialized_node, node);
189    }
190}