1use crate::handle::Handle;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10#[repr(transparent)]
11pub struct GraphHandle(pub Handle);
12
13impl GraphHandle {
14 #[inline]
16 #[must_use]
17 pub const fn new(id: u32, generation: u32) -> Self {
18 Self(Handle::new(id, generation))
19 }
20
21 #[inline]
23 #[must_use]
24 pub const fn null() -> Self {
25 Self(Handle::null())
26 }
27
28 #[inline]
30 #[must_use]
31 pub const fn is_null(&self) -> bool {
32 self.0.is_null()
33 }
34
35 #[inline]
37 #[must_use]
38 pub const fn raw(&self) -> Handle {
39 self.0
40 }
41}
42
43impl Default for GraphHandle {
44 fn default() -> Self {
45 Self::null()
46 }
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
51#[repr(u8)]
52pub enum GraphMutationKind {
53 AddNode = 0,
55
56 RemoveNode = 1,
58
59 AddEdge = 2,
61
62 RemoveEdge = 3,
64
65 UpdateEdgeWeight = 4,
67
68 UpdateNodeMeta = 5,
70}
71
72impl GraphMutationKind {
73 #[inline]
75 #[must_use]
76 pub const fn as_str(&self) -> &'static str {
77 match self {
78 Self::AddNode => "AddNode",
79 Self::RemoveNode => "RemoveNode",
80 Self::AddEdge => "AddEdge",
81 Self::RemoveEdge => "RemoveEdge",
82 Self::UpdateEdgeWeight => "UpdateEdgeWeight",
83 Self::UpdateNodeMeta => "UpdateNodeMeta",
84 }
85 }
86
87 #[inline]
89 #[must_use]
90 pub const fn from_u8(value: u8) -> Option<Self> {
91 match value {
92 0 => Some(Self::AddNode),
93 1 => Some(Self::RemoveNode),
94 2 => Some(Self::AddEdge),
95 3 => Some(Self::RemoveEdge),
96 4 => Some(Self::UpdateEdgeWeight),
97 5 => Some(Self::UpdateNodeMeta),
98 _ => None,
99 }
100 }
101}
102
103#[derive(Debug, Clone, Copy, PartialEq)]
108#[repr(C)]
109pub struct GraphMutation {
110 pub kind: GraphMutationKind,
112
113 pub node_a: u64,
115
116 pub node_b: u64,
118
119 pub weight_fp: i32,
122
123 pub partition_hint: u32,
125}
126
127impl GraphMutation {
128 #[inline]
130 #[must_use]
131 pub const fn add_node(node_id: u64) -> Self {
132 Self {
133 kind: GraphMutationKind::AddNode,
134 node_a: node_id,
135 node_b: 0,
136 weight_fp: 0,
137 partition_hint: 0,
138 }
139 }
140
141 #[inline]
143 #[must_use]
144 pub const fn remove_node(node_id: u64) -> Self {
145 Self {
146 kind: GraphMutationKind::RemoveNode,
147 node_a: node_id,
148 node_b: 0,
149 weight_fp: 0,
150 partition_hint: 0,
151 }
152 }
153
154 #[inline]
156 #[must_use]
157 pub const fn add_edge(from: u64, to: u64, weight: f32) -> Self {
158 Self {
159 kind: GraphMutationKind::AddEdge,
160 node_a: from,
161 node_b: to,
162 weight_fp: (weight * 10000.0) as i32,
163 partition_hint: 0,
164 }
165 }
166
167 #[inline]
169 #[must_use]
170 pub const fn remove_edge(from: u64, to: u64) -> Self {
171 Self {
172 kind: GraphMutationKind::RemoveEdge,
173 node_a: from,
174 node_b: to,
175 weight_fp: 0,
176 partition_hint: 0,
177 }
178 }
179
180 #[inline]
182 #[must_use]
183 pub const fn update_edge_weight(from: u64, to: u64, weight: f32) -> Self {
184 Self {
185 kind: GraphMutationKind::UpdateEdgeWeight,
186 node_a: from,
187 node_b: to,
188 weight_fp: (weight * 10000.0) as i32,
189 partition_hint: 0,
190 }
191 }
192
193 #[inline]
195 #[must_use]
196 pub fn weight(&self) -> f32 {
197 self.weight_fp as f32 / 10000.0
198 }
199
200 #[inline]
202 #[must_use]
203 pub const fn with_partition_hint(mut self, partition_id: u32) -> Self {
204 self.partition_hint = partition_id;
205 self
206 }
207}
208
209impl Default for GraphMutation {
210 fn default() -> Self {
211 Self {
212 kind: GraphMutationKind::AddNode,
213 node_a: 0,
214 node_b: 0,
215 weight_fp: 0,
216 partition_hint: 0,
217 }
218 }
219}
220
221#[cfg(test)]
222mod tests {
223 use super::*;
224
225 #[test]
226 fn test_graph_handle() {
227 let h = GraphHandle::new(42, 7);
228 assert!(!h.is_null());
229 assert_eq!(h.raw().id, 42);
230 }
231
232 #[test]
233 fn test_graph_mutation_add_edge() {
234 let mutation = GraphMutation::add_edge(1, 2, 0.75);
235 assert_eq!(mutation.kind, GraphMutationKind::AddEdge);
236 assert_eq!(mutation.node_a, 1);
237 assert_eq!(mutation.node_b, 2);
238 assert!((mutation.weight() - 0.75).abs() < 0.001);
239 }
240
241 #[test]
242 fn test_graph_mutation_with_partition() {
243 let mutation = GraphMutation::add_node(100).with_partition_hint(5);
244 assert_eq!(mutation.partition_hint, 5);
245 }
246}