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 insert_node(&mut self, draft: NodeDraft) -> Result<GraphNodeId, GraphBuildError> {
156 let index = self.admit(GraphCollection::Node)?;
157 let id = GraphNodeId::new(index);
158 self.nodes.push(GraphNode::new(id, draft));
159 Ok(id)
160 }
161
162 pub(crate) fn insert_reference(
164 &mut self,
165 draft: ReferenceDraft,
166 ) -> Result<GraphReferenceId, GraphBuildError> {
167 let index = self.admit(GraphCollection::Reference)?;
168 let id = GraphReferenceId::new(index);
169 self.references.push((id, draft));
170 self.reference_edges.push(Vec::new());
171 Ok(id)
172 }
173
174 pub(crate) fn insert_edge(&mut self, draft: EdgeDraft) -> Result<GraphEdgeId, GraphBuildError> {
184 let index = self.admit(GraphCollection::Edge)?;
185 let id = GraphEdgeId::new(index);
186 self.link_origin(&draft.origin, id)?;
187 self.edges.push(GraphEdge::new(id, draft));
188 Ok(id)
189 }
190
191 fn link_origin(
196 &mut self,
197 origin: &GraphEdgeOrigin,
198 edge: GraphEdgeId,
199 ) -> Result<(), GraphBuildError> {
200 let reference = match origin {
201 GraphEdgeOrigin::Reference { reference } => *reference,
202 GraphEdgeOrigin::Dependency { .. } => return Ok(()),
203 };
204 match self.reference_edges.get_mut(index_of(reference.index())) {
205 Some(produced) => {
206 produced.push(edge);
207 Ok(())
208 }
209 None => Err(GraphBuildError::MissingReferenceRecord {
210 reference: reference.index(),
211 }),
212 }
213 }
214
215 pub(crate) fn contain(&mut self, parent: GraphNodeId, child: GraphNodeId) {
217 self.containment.push(ContainmentEdge::new(parent, child));
218 }
219
220 pub(crate) fn containment(&self) -> &[ContainmentEdge] {
222 &self.containment
223 }
224
225 pub(crate) fn node_count(&self) -> usize {
227 self.nodes.len()
228 }
229
230 pub(crate) fn finish(mut self, tier: ResolutionTier) -> CodeGraph {
238 self.containment
239 .sort_unstable_by_key(|edge| (edge.child(), edge.parent()));
240 let references = self
241 .references
242 .into_iter()
243 .zip(self.reference_edges)
244 .map(|((id, draft), edges)| GraphReference::new(id, draft, edges.into_boxed_slice()))
245 .collect();
246 CodeGraph {
247 schema_version: CodeGraph::SCHEMA_VERSION,
248 tier,
249 nodes: self.nodes.into_boxed_slice(),
250 containment: self.containment.into_boxed_slice(),
251 references,
252 edges: self.edges.into_boxed_slice(),
253 }
254 }
255
256 fn admit(&self, collection: GraphCollection) -> Result<u32, GraphBuildError> {
263 let count = match collection {
264 GraphCollection::Node => self.nodes.len(),
265 GraphCollection::Reference => self.references.len(),
266 GraphCollection::Edge => self.edges.len(),
267 };
268 let limit = self.limits.ceiling(collection);
269 u32::try_from(count)
270 .ok()
271 .filter(|next| *next < limit)
272 .ok_or(GraphBuildError::CapacityExceeded { collection, limit })
273 }
274}
275
276pub(crate) fn reserved(stated: usize, ceiling: u32) -> usize {
283 stated.min(index_of(ceiling))
284}