1use pedant_types::ResolutionTier;
5use serde::Serialize;
6
7use crate::containment::ContainmentEdge;
8use crate::edge::{EdgeDraft, GraphEdge, GraphEdgeOrigin};
9use crate::error::GraphBuildError;
10use crate::id::{GraphEdgeId, GraphNodeId, GraphReferenceId, index_of, position};
11use crate::limits::{GraphCollection, GraphLimits};
12use crate::node::{GraphNode, NodeDraft};
13use crate::reference::{GraphReference, ReferenceDraft};
14
15#[derive(Serialize, Debug, PartialEq, Eq)]
22pub struct CodeGraph {
23 schema_version: u32,
24 tier: ResolutionTier,
25 nodes: Box<[GraphNode]>,
26 containment: Box<[ContainmentEdge]>,
27 references: Box<[GraphReference]>,
28 edges: Box<[GraphEdge]>,
29}
30
31impl CodeGraph {
32 pub const SCHEMA_VERSION: u32 = 1;
34
35 pub fn schema_version(&self) -> u32 {
37 self.schema_version
38 }
39
40 pub fn tier(&self) -> ResolutionTier {
42 self.tier
43 }
44
45 pub fn nodes(&self) -> &[GraphNode] {
47 &self.nodes
48 }
49
50 pub fn node(&self, id: GraphNodeId) -> Option<&GraphNode> {
52 self.nodes.get(index_of(id.index()))
53 }
54
55 pub fn containment(&self) -> &[ContainmentEdge] {
57 &self.containment
58 }
59
60 pub fn references(&self) -> &[GraphReference] {
62 &self.references
63 }
64
65 pub fn reference(&self, id: GraphReferenceId) -> Option<&GraphReference> {
67 self.references.get(index_of(id.index()))
68 }
69
70 pub fn edges(&self) -> &[GraphEdge] {
72 &self.edges
73 }
74
75 pub fn edge(&self, id: GraphEdgeId) -> Option<&GraphEdge> {
77 self.edges.get(index_of(id.index()))
78 }
79
80 pub(crate) fn admissible(&self, limits: GraphLimits) -> Result<(), GraphBuildError> {
88 [
89 (GraphCollection::Node, self.nodes.len()),
90 (GraphCollection::Reference, self.references.len()),
91 (GraphCollection::Edge, self.edges.len()),
92 ]
93 .into_iter()
94 .find(|(collection, held)| position(*held) > limits.ceiling(*collection))
95 .map_or(Ok(()), |(collection, _)| {
96 Err(GraphBuildError::CapacityExceeded {
97 collection,
98 limit: limits.ceiling(collection),
99 })
100 })
101 }
102}
103
104pub(crate) struct RecordCapacity {
109 pub(crate) nodes: usize,
111 pub(crate) references: usize,
113 pub(crate) edges: usize,
115}
116
117pub(crate) struct GraphRecords {
125 limits: GraphLimits,
126 nodes: Vec<GraphNode>,
127 containment: Vec<ContainmentEdge>,
128 references: Vec<(GraphReferenceId, ReferenceDraft)>,
129 reference_edges: Vec<Vec<GraphEdgeId>>,
130 edges: Vec<GraphEdge>,
131}
132
133impl GraphRecords {
134 pub(crate) fn new(limits: GraphLimits, capacity: RecordCapacity) -> Self {
136 let nodes = reserved(capacity.nodes, limits.ceiling(GraphCollection::Node));
137 let references = reserved(
138 capacity.references,
139 limits.ceiling(GraphCollection::Reference),
140 );
141 Self {
142 limits,
143 nodes: Vec::with_capacity(nodes),
144 containment: Vec::with_capacity(nodes),
145 references: Vec::with_capacity(references),
146 reference_edges: Vec::with_capacity(references),
147 edges: Vec::with_capacity(reserved(
148 capacity.edges,
149 limits.ceiling(GraphCollection::Edge),
150 )),
151 }
152 }
153
154 pub(crate) fn reserved(&self, collection: GraphCollection, stated: usize) -> usize {
160 reserved(stated, self.limits.ceiling(collection))
161 }
162
163 pub(crate) fn insert_node(&mut self, draft: NodeDraft) -> Result<GraphNodeId, GraphBuildError> {
165 let index = self.admit(GraphCollection::Node)?;
166 let id = GraphNodeId::new(index);
167 self.nodes.push(GraphNode::new(id, draft));
168 Ok(id)
169 }
170
171 pub(crate) fn insert_reference(
173 &mut self,
174 draft: ReferenceDraft,
175 ) -> Result<GraphReferenceId, GraphBuildError> {
176 let index = self.admit(GraphCollection::Reference)?;
177 let id = GraphReferenceId::new(index);
178 self.references.push((id, draft));
179 self.reference_edges.push(Vec::new());
180 Ok(id)
181 }
182
183 pub(crate) fn insert_edge(&mut self, draft: EdgeDraft) -> Result<GraphEdgeId, GraphBuildError> {
193 let index = self.admit(GraphCollection::Edge)?;
194 let id = GraphEdgeId::new(index);
195 self.link_origin(&draft.origin, id)?;
196 self.edges.push(GraphEdge::new(id, draft));
197 Ok(id)
198 }
199
200 fn link_origin(
205 &mut self,
206 origin: &GraphEdgeOrigin,
207 edge: GraphEdgeId,
208 ) -> Result<(), GraphBuildError> {
209 let reference = match origin {
210 GraphEdgeOrigin::Reference { reference } => *reference,
211 GraphEdgeOrigin::Dependency { .. } => return Ok(()),
212 };
213 match self.reference_edges.get_mut(index_of(reference.index())) {
214 Some(produced) => {
215 produced.push(edge);
216 Ok(())
217 }
218 None => Err(GraphBuildError::MissingReferenceRecord {
219 reference: reference.index(),
220 }),
221 }
222 }
223
224 pub(crate) fn contain(&mut self, parent: GraphNodeId, child: GraphNodeId) {
226 self.containment.push(ContainmentEdge::new(parent, child));
227 }
228
229 pub(crate) fn containment(&self) -> &[ContainmentEdge] {
231 &self.containment
232 }
233
234 pub(crate) fn node_count(&self) -> usize {
236 self.nodes.len()
237 }
238
239 pub(crate) fn finish(mut self, tier: ResolutionTier) -> CodeGraph {
247 self.containment
248 .sort_unstable_by_key(|edge| (edge.child(), edge.parent()));
249 let references = self
250 .references
251 .into_iter()
252 .zip(self.reference_edges)
253 .map(|((id, draft), edges)| GraphReference::new(id, draft, edges.into_boxed_slice()))
254 .collect();
255 CodeGraph {
256 schema_version: CodeGraph::SCHEMA_VERSION,
257 tier,
258 nodes: self.nodes.into_boxed_slice(),
259 containment: self.containment.into_boxed_slice(),
260 references,
261 edges: self.edges.into_boxed_slice(),
262 }
263 }
264
265 fn admit(&self, collection: GraphCollection) -> Result<u32, GraphBuildError> {
272 let count = match collection {
273 GraphCollection::Node => self.nodes.len(),
274 GraphCollection::Reference => self.references.len(),
275 GraphCollection::Edge => self.edges.len(),
276 };
277 let limit = self.limits.ceiling(collection);
278 u32::try_from(count)
279 .ok()
280 .filter(|next| *next < limit)
281 .ok_or(GraphBuildError::CapacityExceeded { collection, limit })
282 }
283}
284
285pub(crate) fn reserved(stated: usize, ceiling: u32) -> usize {
292 stated.min(index_of(ceiling))
293}