1use std::sync::Arc;
8
9use crate::Language;
10
11use super::definition::SymbolKind;
12use super::error::ResolutionReportError;
13use super::finish::assemble;
14use super::handle::{
15 BuilderBrand, CandidateInput, DefinitionHandle, ReferenceHandle, ResolutionUnitHandle,
16};
17use super::record::{ResolutionCertainty, ResolutionGap};
18use super::reference::ReferenceKind;
19use super::report::{ResolutionReport, ResolutionTier};
20use super::span::SourceSpan;
21
22#[derive(Clone, Copy, Debug, PartialEq, Eq)]
30pub struct ResolutionReportLimits {
31 pub max_units: u32,
33 pub max_definitions: u32,
35 pub max_references: u32,
40}
41
42impl Default for ResolutionReportLimits {
43 fn default() -> Self {
44 Self {
45 max_units: u32::MAX,
46 max_definitions: u32::MAX,
47 max_references: u32::MAX,
48 }
49 }
50}
51
52impl ResolutionReportLimits {
53 pub fn admit_unit(&self, count: usize) -> Result<u32, ResolutionReportError> {
55 admit(count, self.max_units, |limit| {
56 ResolutionReportError::UnitCapacityExceeded { limit }
57 })
58 }
59
60 pub fn admit_definition(&self, count: usize) -> Result<u32, ResolutionReportError> {
62 admit(count, self.max_definitions, |limit| {
63 ResolutionReportError::DefinitionCapacityExceeded { limit }
64 })
65 }
66
67 pub fn admit_reference(&self, count: usize) -> Result<u32, ResolutionReportError> {
69 admit(count, self.max_references, |limit| {
70 ResolutionReportError::ReferenceCapacityExceeded { limit }
71 })
72 }
73}
74
75fn admit(
78 count: usize,
79 limit: u32,
80 exceeded: impl Fn(u32) -> ResolutionReportError,
81) -> Result<u32, ResolutionReportError> {
82 u32::try_from(count)
83 .ok()
84 .filter(|next| *next < limit)
85 .ok_or_else(|| exceeded(limit))
86}
87
88pub(crate) struct DraftUnit {
90 pub(crate) language: Language,
91 pub(crate) key: Arc<str>,
92 pub(crate) name: Arc<str>,
93}
94
95pub(crate) struct DraftDefinition {
97 pub(crate) unit: u32,
98 pub(crate) kind: SymbolKind,
99 pub(crate) name: Arc<str>,
100 pub(crate) span: SourceSpan,
101 pub(crate) parent: Option<u32>,
102}
103
104pub(crate) struct DraftReference {
106 pub(crate) unit: u32,
107 pub(crate) kind: ReferenceKind,
108 pub(crate) text: Arc<str>,
109 pub(crate) span: SourceSpan,
110 pub(crate) enclosing: Option<u32>,
111}
112
113pub(crate) struct DraftResolution {
115 pub(crate) candidates: Box<[(u32, ResolutionCertainty)]>,
116 pub(crate) gaps: Box<[ResolutionGap]>,
117}
118
119pub struct ResolutionReportBuilder {
121 brand: Arc<BuilderBrand>,
122 tier: ResolutionTier,
123 limits: ResolutionReportLimits,
124 units: Vec<DraftUnit>,
125 definitions: Vec<DraftDefinition>,
126 references: Vec<DraftReference>,
127 resolutions: Vec<Option<DraftResolution>>,
128}
129
130impl ResolutionReportBuilder {
131 pub fn new(tier: ResolutionTier, limits: ResolutionReportLimits) -> Self {
133 Self {
134 brand: Arc::new(BuilderBrand),
135 tier,
136 limits,
137 units: Vec::new(),
138 definitions: Vec::new(),
139 references: Vec::new(),
140 resolutions: Vec::new(),
141 }
142 }
143
144 pub fn add_unit(
146 &mut self,
147 language: Language,
148 key: Arc<str>,
149 name: Arc<str>,
150 ) -> Result<ResolutionUnitHandle, ResolutionReportError> {
151 let index = self.limits.admit_unit(self.units.len())?;
152 self.units.push(DraftUnit {
153 language,
154 key,
155 name,
156 });
157 Ok(ResolutionUnitHandle::new(&self.brand, index))
158 }
159
160 pub fn add_definition(
162 &mut self,
163 unit: &ResolutionUnitHandle,
164 kind: SymbolKind,
165 name: Arc<str>,
166 span: SourceSpan,
167 parent: Option<&DefinitionHandle>,
168 ) -> Result<DefinitionHandle, ResolutionReportError> {
169 let unit = self.local_unit(unit)?;
170 let parent = self.local_definition_option(parent)?;
171 let index = self.limits.admit_definition(self.definitions.len())?;
172 self.definitions.push(DraftDefinition {
173 unit,
174 kind,
175 name,
176 span,
177 parent,
178 });
179 Ok(DefinitionHandle::new(&self.brand, index))
180 }
181
182 pub fn add_reference(
184 &mut self,
185 unit: &ResolutionUnitHandle,
186 kind: ReferenceKind,
187 text: Arc<str>,
188 span: SourceSpan,
189 enclosing_definition: Option<&DefinitionHandle>,
190 ) -> Result<ReferenceHandle, ResolutionReportError> {
191 let unit = self.local_unit(unit)?;
192 let enclosing = self.local_definition_option(enclosing_definition)?;
193 let index = self.limits.admit_reference(self.references.len())?;
194 self.references.push(DraftReference {
195 unit,
196 kind,
197 text,
198 span,
199 enclosing,
200 });
201 self.resolutions.push(None);
202 Ok(ReferenceHandle::new(&self.brand, index))
203 }
204
205 pub fn set_resolution(
207 &mut self,
208 reference: &ReferenceHandle,
209 candidates: Box<[CandidateInput]>,
210 gaps: Box<[ResolutionGap]>,
211 ) -> Result<(), ResolutionReportError> {
212 let index = reference
213 .resolve(&self.brand)
214 .ok_or(ResolutionReportError::ForeignReferenceHandle)?;
215 let stated = candidates
216 .into_vec()
217 .into_iter()
218 .map(|candidate| {
219 let (definition, certainty) = candidate.into_parts();
220 self.local_definition(&definition)
221 .map(|definition| (definition, certainty))
222 })
223 .collect::<Result<Vec<_>, _>>()?;
224 let slot = self
225 .resolutions
226 .get_mut(index as usize)
227 .ok_or(ResolutionReportError::ForeignReferenceHandle)?;
228 match slot.is_some() {
229 true => Err(ResolutionReportError::DuplicateResolution { reference: index }),
230 false => {
231 *slot = Some(DraftResolution {
232 candidates: stated.into_boxed_slice(),
233 gaps,
234 });
235 Ok(())
236 }
237 }
238 }
239
240 pub fn finish(self) -> Result<ResolutionReport, ResolutionReportError> {
245 assemble(
246 self.tier,
247 self.units,
248 self.definitions,
249 self.references,
250 self.resolutions,
251 )
252 }
253
254 fn local_unit(&self, unit: &ResolutionUnitHandle) -> Result<u32, ResolutionReportError> {
255 unit.resolve(&self.brand)
256 .ok_or(ResolutionReportError::ForeignUnitHandle)
257 }
258
259 fn local_definition(
260 &self,
261 definition: &DefinitionHandle,
262 ) -> Result<u32, ResolutionReportError> {
263 definition
264 .resolve(&self.brand)
265 .ok_or(ResolutionReportError::ForeignDefinitionHandle)
266 }
267
268 fn local_definition_option(
269 &self,
270 definition: Option<&DefinitionHandle>,
271 ) -> Result<Option<u32>, ResolutionReportError> {
272 definition
273 .map(|handle| self.local_definition(handle))
274 .transpose()
275 }
276}