pedant_graph/analysis/
partition.rs1use crate::graph::CodeGraph;
10use crate::id::{GraphNodeId, index_of, position};
11use crate::node::GraphNodeKind;
12
13use super::error::GraphAnalysisError;
14use super::index::SelectedIndexes;
15
16pub struct DeclaredModulePartition {
21 owners: Box<[GraphNodeId]>,
22 roots: Box<[GraphNodeId]>,
23 members: Box<[Box<[GraphNodeId]>]>,
24}
25
26impl DeclaredModulePartition {
27 pub fn owner(&self, node: GraphNodeId) -> Option<GraphNodeId> {
30 self.owners.get(index_of(node.index())).copied()
31 }
32
33 pub fn roots(&self) -> &[GraphNodeId] {
35 &self.roots
36 }
37
38 pub(crate) fn owners(&self) -> &[GraphNodeId] {
45 &self.owners
46 }
47
48 pub fn members(&self, root: GraphNodeId) -> Option<&[GraphNodeId]> {
50 self.roots
51 .binary_search(&root)
52 .ok()
53 .and_then(|at| self.members.get(at))
54 .map(|held| &**held)
55 }
56}
57
58struct Ownership {
60 containers: Box<[bool]>,
61 owners: Box<[Option<GraphNodeId>]>,
62 chain: Vec<GraphNodeId>,
63}
64
65impl Ownership {
66 fn new(graph: &CodeGraph) -> Self {
68 let containers: Box<[bool]> = graph
69 .nodes()
70 .iter()
71 .map(|node| matches!(node.kind(), GraphNodeKind::Container { .. }))
72 .collect();
73 let owners = vec![None; containers.len()].into_boxed_slice();
74 Self {
75 containers,
76 owners,
77 chain: Vec::new(),
78 }
79 }
80
81 fn settled(&self, node: GraphNodeId) -> Option<GraphNodeId> {
83 self.owners.get(index_of(node.index())).copied().flatten()
84 }
85
86 fn is_container(&self, node: GraphNodeId) -> bool {
88 self.containers
89 .get(index_of(node.index()))
90 .copied()
91 .unwrap_or(false)
92 }
93
94 fn push(&mut self, node: GraphNodeId) {
96 self.chain.push(node);
97 }
98
99 fn settle(&mut self, owner: GraphNodeId) {
101 for node in self.chain.drain(..) {
102 if let Some(slot) = self.owners.get_mut(index_of(node.index())) {
103 *slot = Some(owner);
104 }
105 }
106 }
107
108 fn abandon(&mut self) {
110 self.chain.clear();
111 }
112
113 fn width(&self) -> usize {
115 self.owners.len()
116 }
117
118 fn finish(self) -> Result<DeclaredModulePartition, GraphAnalysisError> {
120 let unsettled = self.owners.iter().position(Option::is_none);
121 match unsettled {
122 Some(at) => Err(GraphAnalysisError::ConsumedGraphInvariant {
123 node: GraphNodeId::new(position(at)),
124 }),
125 None => Ok(assembled(
126 self.owners.iter().flatten().copied().collect(),
127 &self.containers,
128 )),
129 }
130 }
131}
132
133pub(crate) fn derive(
139 graph: &CodeGraph,
140 indexes: &SelectedIndexes,
141) -> Result<DeclaredModulePartition, GraphAnalysisError> {
142 let mut ownership = Ownership::new(graph);
143 for node in graph.nodes() {
144 let owner = nearest_container(&mut ownership, indexes, node.id());
145 match owner {
146 Some(found) => ownership.settle(found),
147 None => ownership.abandon(),
148 }
149 }
150 ownership.finish()
151}
152
153fn nearest_container(
158 ownership: &mut Ownership,
159 indexes: &SelectedIndexes,
160 start: GraphNodeId,
161) -> Option<GraphNodeId> {
162 let mut current = Some(start);
163 for _ in 0..ownership.width() {
164 let node = current?;
165 let settled = ownership.settled(node);
166 match settled {
167 Some(owner) => return Some(owner),
168 None => ownership.push(node),
169 }
170 match ownership.is_container(node) {
171 true => return Some(node),
172 false => current = indexes.parent(node),
173 }
174 }
175 None
176}
177
178fn assembled(owners: Box<[GraphNodeId]>, containers: &[bool]) -> DeclaredModulePartition {
180 let roots: Box<[GraphNodeId]> = containers
181 .iter()
182 .enumerate()
183 .filter(|(_, container)| **container)
184 .map(|(at, _)| GraphNodeId::new(position(at)))
185 .collect();
186 let members = grouped(&owners, &roots);
187 DeclaredModulePartition {
188 owners,
189 roots,
190 members,
191 }
192}
193
194fn grouped(owners: &[GraphNodeId], roots: &[GraphNodeId]) -> Box<[Box<[GraphNodeId]>]> {
196 let mut buckets: Vec<Vec<GraphNodeId>> = vec![Vec::new(); roots.len()];
197 for (at, owner) in owners.iter().enumerate() {
198 record(&mut buckets, roots, *owner, GraphNodeId::new(position(at)));
199 }
200 buckets
201 .into_iter()
202 .map(Vec::into_boxed_slice)
203 .collect::<Vec<Box<[GraphNodeId]>>>()
204 .into_boxed_slice()
205}
206
207fn record(
209 buckets: &mut [Vec<GraphNodeId>],
210 roots: &[GraphNodeId],
211 owner: GraphNodeId,
212 node: GraphNodeId,
213) {
214 let bucket = roots
215 .binary_search(&owner)
216 .ok()
217 .and_then(|at| buckets.get_mut(at));
218 if let Some(held) = bucket {
219 held.push(node);
220 }
221}