1use grafeo_common::types::{EdgeId, EpochId, NodeId, PropertyKey, Value};
7use serde::{Deserialize, Serialize};
8use std::collections::BTreeMap;
9use std::sync::Arc;
10
11#[derive(Debug, Clone)]
32pub struct Edge {
33 pub id: EdgeId,
35 pub src: NodeId,
37 pub dst: NodeId,
39 pub edge_type: Arc<str>,
41 pub properties: BTreeMap<PropertyKey, Value>,
43}
44
45impl Edge {
46 #[must_use]
48 pub fn new(id: EdgeId, src: NodeId, dst: NodeId, edge_type: impl Into<Arc<str>>) -> Self {
49 Self {
50 id,
51 src,
52 dst,
53 edge_type: edge_type.into(),
54 properties: BTreeMap::new(),
55 }
56 }
57
58 pub fn set_property(&mut self, key: impl Into<PropertyKey>, value: impl Into<Value>) {
60 self.properties.insert(key.into(), value.into());
61 }
62
63 #[must_use]
65 pub fn get_property(&self, key: &str) -> Option<&Value> {
66 self.properties.get(&PropertyKey::new(key))
67 }
68
69 pub fn remove_property(&mut self, key: &str) -> Option<Value> {
71 self.properties.remove(&PropertyKey::new(key))
72 }
73
74 #[must_use]
79 pub fn other_endpoint(&self, node: NodeId) -> Option<NodeId> {
80 if node == self.src {
81 Some(self.dst)
82 } else if node == self.dst {
83 Some(self.src)
84 } else {
85 None
86 }
87 }
88}
89
90#[repr(C)]
95#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
96pub struct EdgeRecord {
97 pub id: EdgeId,
99 pub src: NodeId,
101 pub dst: NodeId,
103 pub type_id: u32,
105 pub props_offset: u32,
107 pub props_count: u16,
109 pub flags: EdgeFlags,
111 pub epoch: EpochId,
113}
114
115impl EdgeRecord {
116 pub const FLAG_DELETED: u16 = 1 << 0;
118 pub const FLAG_HAS_VERSION: u16 = 1 << 1;
120
121 #[must_use]
123 pub const fn new(id: EdgeId, src: NodeId, dst: NodeId, type_id: u32, epoch: EpochId) -> Self {
124 Self {
125 id,
126 src,
127 dst,
128 type_id,
129 props_offset: 0,
130 props_count: 0,
131 flags: EdgeFlags(0),
132 epoch,
133 }
134 }
135
136 #[must_use]
138 pub const fn is_deleted(&self) -> bool {
139 self.flags.contains(Self::FLAG_DELETED)
140 }
141
142 pub fn set_deleted(&mut self, deleted: bool) {
144 if deleted {
145 self.flags.set(Self::FLAG_DELETED);
146 } else {
147 self.flags.clear(Self::FLAG_DELETED);
148 }
149 }
150}
151
152#[repr(transparent)]
154#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
155pub struct EdgeFlags(pub u16);
156
157impl EdgeFlags {
158 #[must_use]
160 pub const fn contains(&self, flag: u16) -> bool {
161 (self.0 & flag) != 0
162 }
163
164 pub fn set(&mut self, flag: u16) {
166 self.0 |= flag;
167 }
168
169 pub fn clear(&mut self, flag: u16) {
171 self.0 &= !flag;
172 }
173}
174
175#[cfg(test)]
176mod tests {
177 use super::*;
178
179 #[test]
180 fn test_edge_creation() {
181 let edge = Edge::new(EdgeId::new(1), NodeId::new(10), NodeId::new(20), "KNOWS");
182
183 assert_eq!(edge.id, EdgeId::new(1));
184 assert_eq!(edge.src, NodeId::new(10));
185 assert_eq!(edge.dst, NodeId::new(20));
186 assert_eq!(edge.edge_type.as_ref(), "KNOWS");
187 }
188
189 #[test]
190 fn test_edge_properties() {
191 let mut edge = Edge::new(EdgeId::new(1), NodeId::new(10), NodeId::new(20), "KNOWS");
192
193 edge.set_property("since", 2020i64);
194 edge.set_property("weight", 1.5f64);
195
196 assert_eq!(
197 edge.get_property("since").and_then(|v| v.as_int64()),
198 Some(2020)
199 );
200 assert_eq!(
201 edge.get_property("weight").and_then(|v| v.as_float64()),
202 Some(1.5)
203 );
204 }
205
206 #[test]
207 fn test_edge_other_endpoint() {
208 let edge = Edge::new(EdgeId::new(1), NodeId::new(10), NodeId::new(20), "KNOWS");
209
210 assert_eq!(edge.other_endpoint(NodeId::new(10)), Some(NodeId::new(20)));
211 assert_eq!(edge.other_endpoint(NodeId::new(20)), Some(NodeId::new(10)));
212 assert_eq!(edge.other_endpoint(NodeId::new(30)), None);
213 }
214
215 #[test]
216 fn test_edge_record_flags() {
217 let mut record = EdgeRecord::new(
218 EdgeId::new(1),
219 NodeId::new(10),
220 NodeId::new(20),
221 0,
222 EpochId::INITIAL,
223 );
224
225 assert!(!record.is_deleted());
226 record.set_deleted(true);
227 assert!(record.is_deleted());
228 }
229
230 #[test]
231 fn test_edge_record_size() {
232 let size = std::mem::size_of::<EdgeRecord>();
234 assert!(size <= 64, "EdgeRecord is {} bytes", size);
236 }
237}