Skip to main content

weavatrix_graph/working/
freeze.rs

1use super::{StableEdgeKey, StableNodeKey, WorkingGraph};
2use crate::{EdgeIndex, Graph, NodeIndex, Result};
3use std::collections::HashMap;
4
5#[derive(Debug, Clone, PartialEq, Eq)]
6pub struct FreezeMap {
7    nodes: HashMap<StableNodeKey, NodeIndex>,
8    edges: HashMap<StableEdgeKey, EdgeIndex>,
9}
10
11impl FreezeMap {
12    #[must_use]
13    pub fn node(&self, key: StableNodeKey) -> Option<NodeIndex> {
14        self.nodes.get(&key).copied()
15    }
16
17    #[must_use]
18    pub fn edge(&self, key: StableEdgeKey) -> Option<EdgeIndex> {
19        self.edges.get(&key).copied()
20    }
21}
22
23#[derive(Debug, Clone, PartialEq, Eq)]
24pub struct FrozenGraph {
25    graph: Graph,
26    indices: FreezeMap,
27}
28
29impl FrozenGraph {
30    #[must_use]
31    pub const fn graph(&self) -> &Graph {
32        &self.graph
33    }
34
35    #[must_use]
36    pub const fn indices(&self) -> &FreezeMap {
37        &self.indices
38    }
39
40    #[must_use]
41    pub fn into_parts(self) -> (Graph, FreezeMap) {
42        (self.graph, self.indices)
43    }
44}
45
46impl WorkingGraph {
47    /// Canonicalizes the working graph and returns stable-to-compact remapping.
48    ///
49    /// # Errors
50    ///
51    /// Returns an error if an internal endpoint invariant is violated.
52    pub fn freeze(self) -> Result<FrozenGraph> {
53        let mut keyed_nodes = self
54            .nodes
55            .into_iter()
56            .enumerate()
57            .filter_map(|(slot, entry)| {
58                Some((
59                    StableNodeKey::new(u32::try_from(slot).ok()?, entry.generation),
60                    entry.value?,
61                ))
62            })
63            .collect::<Vec<_>>();
64        keyed_nodes.sort_unstable_by(|left, right| left.1.id.cmp(&right.1.id));
65
66        let mut node_map = HashMap::with_capacity(keyed_nodes.len());
67        let mut nodes = Vec::with_capacity(keyed_nodes.len());
68        for (index, (key, node)) in keyed_nodes.into_iter().enumerate() {
69            let index =
70                u32::try_from(index).map_err(|_| crate::GraphError::IndexCapacityExceeded {
71                    category: "frozen nodes",
72                    count: nodes.len(),
73                })?;
74            node_map.insert(key, NodeIndex::new(index));
75            nodes.push(node);
76        }
77
78        let mut keyed_edges = self
79            .edges
80            .into_iter()
81            .enumerate()
82            .filter_map(|(slot, entry)| {
83                Some((
84                    StableEdgeKey::new(u32::try_from(slot).ok()?, entry.generation),
85                    entry.value?.value,
86                ))
87            })
88            .collect::<Vec<_>>();
89        keyed_edges.sort_unstable_by(|left, right| left.1.cmp(&right.1));
90
91        let mut edge_map = HashMap::with_capacity(keyed_edges.len());
92        let mut edges = Vec::with_capacity(keyed_edges.len());
93        for (key, edge) in keyed_edges {
94            let index = if edges.last() == Some(&edge) {
95                edges.len() - 1
96            } else {
97                edges.push(edge);
98                edges.len() - 1
99            };
100            let index =
101                u32::try_from(index).map_err(|_| crate::GraphError::IndexCapacityExceeded {
102                    category: "frozen edges",
103                    count: edges.len(),
104                })?;
105            edge_map.insert(key, EdgeIndex::new(index));
106        }
107
108        let graph = Graph::from_validated_sorted_parts(nodes, edges)?;
109        Ok(FrozenGraph {
110            graph,
111            indices: FreezeMap {
112                nodes: node_map,
113                edges: edge_map,
114            },
115        })
116    }
117}