graphos_core/graph/lpg/
node.rs1use graphos_common::types::{EpochId, NodeId, PropertyKey, Value};
4use std::collections::BTreeMap;
5use std::sync::Arc;
6
7#[derive(Debug, Clone)]
11pub struct Node {
12 pub id: NodeId,
14 pub labels: Vec<Arc<str>>,
16 pub properties: BTreeMap<PropertyKey, Value>,
18}
19
20impl Node {
21 #[must_use]
23 pub fn new(id: NodeId) -> Self {
24 Self {
25 id,
26 labels: Vec::new(),
27 properties: BTreeMap::new(),
28 }
29 }
30
31 #[must_use]
33 pub fn with_labels(id: NodeId, labels: impl IntoIterator<Item = impl Into<Arc<str>>>) -> Self {
34 Self {
35 id,
36 labels: labels.into_iter().map(Into::into).collect(),
37 properties: BTreeMap::new(),
38 }
39 }
40
41 pub fn add_label(&mut self, label: impl Into<Arc<str>>) {
43 let label = label.into();
44 if !self.labels.iter().any(|l| l.as_ref() == label.as_ref()) {
45 self.labels.push(label);
46 }
47 }
48
49 pub fn remove_label(&mut self, label: &str) -> bool {
51 if let Some(pos) = self.labels.iter().position(|l| l.as_ref() == label) {
52 self.labels.remove(pos);
53 true
54 } else {
55 false
56 }
57 }
58
59 #[must_use]
61 pub fn has_label(&self, label: &str) -> bool {
62 self.labels.iter().any(|l| l.as_ref() == label)
63 }
64
65 pub fn set_property(&mut self, key: impl Into<PropertyKey>, value: impl Into<Value>) {
67 self.properties.insert(key.into(), value.into());
68 }
69
70 #[must_use]
72 pub fn get_property(&self, key: &str) -> Option<&Value> {
73 self.properties.get(&PropertyKey::new(key))
74 }
75
76 pub fn remove_property(&mut self, key: &str) -> Option<Value> {
78 self.properties.remove(&PropertyKey::new(key))
79 }
80}
81
82#[repr(C)]
87#[derive(Debug, Clone, Copy)]
88pub struct NodeRecord {
89 pub id: NodeId,
91 pub label_bits: u64,
93 pub props_offset: u32,
95 pub props_count: u16,
97 pub flags: NodeFlags,
99 pub epoch: EpochId,
101}
102
103impl NodeRecord {
104 pub const FLAG_DELETED: u16 = 1 << 0;
106 pub const FLAG_HAS_VERSION: u16 = 1 << 1;
108
109 #[must_use]
111 pub const fn new(id: NodeId, epoch: EpochId) -> Self {
112 Self {
113 id,
114 label_bits: 0,
115 props_offset: 0,
116 props_count: 0,
117 flags: NodeFlags(0),
118 epoch,
119 }
120 }
121
122 #[must_use]
124 pub const fn is_deleted(&self) -> bool {
125 self.flags.contains(Self::FLAG_DELETED)
126 }
127
128 pub fn set_deleted(&mut self, deleted: bool) {
130 if deleted {
131 self.flags.set(Self::FLAG_DELETED);
132 } else {
133 self.flags.clear(Self::FLAG_DELETED);
134 }
135 }
136
137 #[must_use]
139 pub const fn has_label_bit(&self, bit: u8) -> bool {
140 if bit >= 64 {
141 return false;
142 }
143 (self.label_bits & (1 << bit)) != 0
144 }
145
146 pub fn set_label_bit(&mut self, bit: u8) {
148 if bit < 64 {
149 self.label_bits |= 1 << bit;
150 }
151 }
152
153 pub fn clear_label_bit(&mut self, bit: u8) {
155 if bit < 64 {
156 self.label_bits &= !(1 << bit);
157 }
158 }
159
160 pub fn label_bits_iter(&self) -> impl Iterator<Item = u8> + '_ {
162 (0..64).filter(|&bit| self.has_label_bit(bit))
163 }
164}
165
166#[repr(transparent)]
168#[derive(Debug, Clone, Copy, Default)]
169pub struct NodeFlags(pub u16);
170
171impl NodeFlags {
172 #[must_use]
174 pub const fn contains(&self, flag: u16) -> bool {
175 (self.0 & flag) != 0
176 }
177
178 pub fn set(&mut self, flag: u16) {
180 self.0 |= flag;
181 }
182
183 pub fn clear(&mut self, flag: u16) {
185 self.0 &= !flag;
186 }
187}
188
189#[cfg(test)]
190mod tests {
191 use super::*;
192
193 #[test]
194 fn test_node_record_size() {
195 assert_eq!(std::mem::size_of::<NodeRecord>(), 32);
197 }
198
199 #[test]
200 fn test_node_labels() {
201 let mut node = Node::new(NodeId::new(1));
202
203 node.add_label("Person");
204 assert!(node.has_label("Person"));
205 assert!(!node.has_label("Animal"));
206
207 node.add_label("Employee");
208 assert!(node.has_label("Employee"));
209
210 node.add_label("Person");
212 assert_eq!(node.labels.len(), 2);
213
214 assert!(node.remove_label("Person"));
216 assert!(!node.has_label("Person"));
217 assert!(!node.remove_label("NotExists"));
218 }
219
220 #[test]
221 fn test_node_properties() {
222 let mut node = Node::new(NodeId::new(1));
223
224 node.set_property("name", "Alice");
225 node.set_property("age", 30i64);
226
227 assert_eq!(node.get_property("name").and_then(|v| v.as_str()), Some("Alice"));
228 assert_eq!(node.get_property("age").and_then(|v| v.as_int64()), Some(30));
229 assert!(node.get_property("missing").is_none());
230
231 let removed = node.remove_property("name");
232 assert!(removed.is_some());
233 assert!(node.get_property("name").is_none());
234 }
235
236 #[test]
237 fn test_node_record_flags() {
238 let mut record = NodeRecord::new(NodeId::new(1), EpochId::INITIAL);
239
240 assert!(!record.is_deleted());
241 record.set_deleted(true);
242 assert!(record.is_deleted());
243 record.set_deleted(false);
244 assert!(!record.is_deleted());
245 }
246
247 #[test]
248 fn test_node_record_label_bits() {
249 let mut record = NodeRecord::new(NodeId::new(1), EpochId::INITIAL);
250
251 assert!(!record.has_label_bit(0));
252 record.set_label_bit(0);
253 assert!(record.has_label_bit(0));
254
255 record.set_label_bit(5);
256 record.set_label_bit(63);
257 assert!(record.has_label_bit(5));
258 assert!(record.has_label_bit(63));
259
260 let bits: Vec<_> = record.label_bits_iter().collect();
261 assert_eq!(bits, vec![0, 5, 63]);
262
263 record.clear_label_bit(5);
264 assert!(!record.has_label_bit(5));
265 }
266}