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};
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
81pub(crate) struct RecordCapacity {
86 pub(crate) nodes: usize,
88 pub(crate) references: usize,
90 pub(crate) edges: usize,
92}
93
94pub(crate) struct GraphRecords {
102 limits: GraphLimits,
103 nodes: Vec<GraphNode>,
104 containment: Vec<ContainmentEdge>,
105 references: Vec<(GraphReferenceId, ReferenceDraft)>,
106 reference_edges: Vec<Vec<GraphEdgeId>>,
107 edges: Vec<GraphEdge>,
108}
109
110impl GraphRecords {
111 pub(crate) fn new(limits: GraphLimits, capacity: RecordCapacity) -> Self {
113 let nodes = reserved(capacity.nodes, limits.ceiling(GraphCollection::Node));
114 let references = reserved(
115 capacity.references,
116 limits.ceiling(GraphCollection::Reference),
117 );
118 Self {
119 limits,
120 nodes: Vec::with_capacity(nodes),
121 containment: Vec::with_capacity(nodes),
122 references: Vec::with_capacity(references),
123 reference_edges: Vec::with_capacity(references),
124 edges: Vec::with_capacity(reserved(
125 capacity.edges,
126 limits.ceiling(GraphCollection::Edge),
127 )),
128 }
129 }
130
131 pub(crate) fn insert_node(&mut self, draft: NodeDraft) -> Result<GraphNodeId, GraphBuildError> {
133 let index = self.admit(GraphCollection::Node)?;
134 let id = GraphNodeId::new(index);
135 self.nodes.push(GraphNode::new(id, draft));
136 Ok(id)
137 }
138
139 pub(crate) fn insert_reference(
141 &mut self,
142 draft: ReferenceDraft,
143 ) -> Result<GraphReferenceId, GraphBuildError> {
144 let index = self.admit(GraphCollection::Reference)?;
145 let id = GraphReferenceId::new(index);
146 self.references.push((id, draft));
147 self.reference_edges.push(Vec::new());
148 Ok(id)
149 }
150
151 pub(crate) fn insert_edge(&mut self, draft: EdgeDraft) -> Result<GraphEdgeId, GraphBuildError> {
161 let index = self.admit(GraphCollection::Edge)?;
162 let id = GraphEdgeId::new(index);
163 self.link_origin(&draft.origin, id)?;
164 self.edges.push(GraphEdge::new(id, draft));
165 Ok(id)
166 }
167
168 fn link_origin(
173 &mut self,
174 origin: &GraphEdgeOrigin,
175 edge: GraphEdgeId,
176 ) -> Result<(), GraphBuildError> {
177 let reference = match origin {
178 GraphEdgeOrigin::Reference { reference } => *reference,
179 GraphEdgeOrigin::Dependency { .. } => return Ok(()),
180 };
181 match self.reference_edges.get_mut(index_of(reference.index())) {
182 Some(produced) => {
183 produced.push(edge);
184 Ok(())
185 }
186 None => Err(GraphBuildError::MissingReferenceRecord {
187 reference: reference.index(),
188 }),
189 }
190 }
191
192 pub(crate) fn contain(&mut self, parent: GraphNodeId, child: GraphNodeId) {
194 self.containment.push(ContainmentEdge::new(parent, child));
195 }
196
197 pub(crate) fn containment(&self) -> &[ContainmentEdge] {
199 &self.containment
200 }
201
202 pub(crate) fn node_count(&self) -> usize {
204 self.nodes.len()
205 }
206
207 pub(crate) fn finish(mut self, tier: ResolutionTier) -> CodeGraph {
215 self.containment
216 .sort_unstable_by_key(|edge| (edge.child(), edge.parent()));
217 let references = self
218 .references
219 .into_iter()
220 .zip(self.reference_edges)
221 .map(|((id, draft), edges)| GraphReference::new(id, draft, edges.into_boxed_slice()))
222 .collect();
223 CodeGraph {
224 schema_version: CodeGraph::SCHEMA_VERSION,
225 tier,
226 nodes: self.nodes.into_boxed_slice(),
227 containment: self.containment.into_boxed_slice(),
228 references,
229 edges: self.edges.into_boxed_slice(),
230 }
231 }
232
233 fn admit(&self, collection: GraphCollection) -> Result<u32, GraphBuildError> {
240 let count = match collection {
241 GraphCollection::Node => self.nodes.len(),
242 GraphCollection::Reference => self.references.len(),
243 GraphCollection::Edge => self.edges.len(),
244 };
245 let limit = self.limits.ceiling(collection);
246 u32::try_from(count)
247 .ok()
248 .filter(|next| *next < limit)
249 .ok_or(GraphBuildError::CapacityExceeded { collection, limit })
250 }
251}
252
253pub(crate) fn reserved(stated: usize, ceiling: u32) -> usize {
260 stated.min(index_of(ceiling))
261}