weavatrix_graph/working/
mutate.rs1use super::{StableEdgeKey, StableNodeKey, WorkingGraph};
2use crate::ToString;
3use crate::graph::validate::{validate_edge, validate_node};
4use crate::{Edge, GraphError, Node, Result};
5
6impl WorkingGraph {
7 pub fn remove_edge(&mut self, key: StableEdgeKey) -> Option<Edge> {
8 let endpoints = self.edge_endpoints(key)?;
9 let edge = self.edge_slot_mut(key)?.value.take()?.value;
10 self.node_slot_mut(endpoints.source())?
11 .outgoing
12 .retain(|candidate| *candidate != key);
13 self.node_slot_mut(endpoints.target())?
14 .incoming
15 .retain(|candidate| *candidate != key);
16 self.edge_count -= 1;
17 self.retire_edge_slot(key);
18 Some(edge)
19 }
20
21 pub fn remove_node(&mut self, key: StableNodeKey) -> Option<Node> {
22 let slot = self.node_slot(key)?;
23 let id = slot.value.as_ref()?.id.clone();
24 let mut incident = slot.outgoing.clone();
25 incident.extend(slot.incoming.iter().copied());
26 incident.sort_unstable();
27 incident.dedup();
28 for edge in incident {
29 self.remove_edge(edge);
30 }
31
32 let node = self.node_slot_mut(key)?.value.take()?;
33 self.node_by_id.remove(&id);
34 self.node_count -= 1;
35 self.retire_node_slot(key);
36 Some(node)
37 }
38
39 pub fn replace_node(&mut self, key: StableNodeKey, node: Node) -> Result<Option<Node>> {
45 validate_node(&node)?;
46 let Some(current) = self.node(key) else {
47 return Ok(None);
48 };
49 let old_id = current.id.clone();
50 if self
51 .node_by_id
52 .get(&node.id)
53 .is_some_and(|existing| *existing != key)
54 {
55 return Err(GraphError::ConflictingNode {
56 id: node.id.to_string(),
57 });
58 }
59
60 if old_id != node.id {
61 let new_id = node.id.clone();
62 let Some(incident) = self.node_slot(key).map(|slot| {
63 let mut keys = slot.outgoing.clone();
64 keys.extend(slot.incoming.iter().copied());
65 keys.sort_unstable();
66 keys.dedup();
67 keys
68 }) else {
69 return Ok(None);
70 };
71 for edge in incident {
72 if let Some(working) = self
73 .edge_slot_mut(edge)
74 .and_then(|slot| slot.value.as_mut())
75 {
76 if working.source == key {
77 working.value.source = new_id.clone();
78 }
79 if working.target == key {
80 working.value.target = new_id.clone();
81 }
82 }
83 }
84 self.node_by_id.remove(&old_id);
85 self.node_by_id.insert(new_id, key);
86 }
87 Ok(self
88 .node_slot_mut(key)
89 .and_then(|slot| slot.value.replace(node)))
90 }
91
92 pub fn replace_edge(&mut self, key: StableEdgeKey, edge: Edge) -> Result<Option<Edge>> {
98 validate_edge(&edge)?;
99 let Some(old_endpoints) = self.edge_endpoints(key) else {
100 return Ok(None);
101 };
102 let source =
103 self.node_key(edge.source.as_str())
104 .ok_or_else(|| GraphError::MissingEdgeSource {
105 id: edge.source.to_string(),
106 })?;
107 let target =
108 self.node_key(edge.target.as_str())
109 .ok_or_else(|| GraphError::MissingEdgeTarget {
110 id: edge.target.to_string(),
111 })?;
112
113 if let Some(slot) = self.node_slot_mut(old_endpoints.source()) {
114 slot.outgoing.retain(|candidate| *candidate != key);
115 }
116 if let Some(slot) = self.node_slot_mut(old_endpoints.target()) {
117 slot.incoming.retain(|candidate| *candidate != key);
118 }
119 if let Some(slot) = self.node_slot_mut(source) {
120 slot.outgoing.push(key);
121 }
122 if let Some(slot) = self.node_slot_mut(target) {
123 slot.incoming.push(key);
124 }
125
126 let Some(working) = self.edge_slot_mut(key).and_then(|slot| slot.value.as_mut()) else {
127 return Ok(None);
128 };
129 working.source = source;
130 working.target = target;
131 Ok(Some(core::mem::replace(&mut working.value, edge)))
132 }
133
134 fn retire_node_slot(&mut self, key: StableNodeKey) {
135 let slot = &mut self.nodes[key.index()];
136 slot.outgoing.clear();
137 slot.incoming.clear();
138 if let Some(generation) = slot.generation.checked_add(1) {
139 slot.generation = generation;
140 self.free_nodes.push(key.slot());
141 }
142 }
143
144 fn retire_edge_slot(&mut self, key: StableEdgeKey) {
145 let slot = &mut self.edges[key.index()];
146 if let Some(generation) = slot.generation.checked_add(1) {
147 slot.generation = generation;
148 self.free_edges.push(key.slot());
149 }
150 }
151}