pedant_types/resolution/error.rs
1//! Every refusal the resolution report contract produces.
2//!
3//! One error type covers both writer boundaries — the builder and custom
4//! deserialization — because both reach the same validator, and a consumer
5//! comparing a builder refusal with a wire refusal should compare one value.
6
7use std::fmt;
8
9use thiserror::Error;
10
11use crate::Language;
12
13use super::ResolutionGap;
14
15/// Which report collection a structural rule names.
16#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
17pub enum ReportCollection {
18 /// The report's resolution units.
19 Units,
20 /// The report's symbol definitions.
21 Definitions,
22 /// The report's symbol references.
23 References,
24 /// The report's resolution records.
25 Resolutions,
26}
27
28impl fmt::Display for ReportCollection {
29 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
30 formatter.write_str(match self {
31 Self::Units => "units",
32 Self::Definitions => "definitions",
33 Self::References => "references",
34 Self::Resolutions => "resolutions",
35 })
36 }
37}
38
39/// A rejected resolution report, or a rejected write into one.
40#[derive(Clone, Debug, Error, PartialEq, Eq)]
41pub enum ResolutionReportError {
42 /// A unit handle another builder issued.
43 #[error("the unit handle belongs to another builder")]
44 ForeignUnitHandle,
45 /// A definition handle another builder issued.
46 #[error("the definition handle belongs to another builder")]
47 ForeignDefinitionHandle,
48 /// A reference handle another builder issued.
49 #[error("the reference handle belongs to another builder")]
50 ForeignReferenceHandle,
51 /// The configured or fixed-width unit capacity is reached.
52 #[error("the report already holds its limit of {limit} units")]
53 UnitCapacityExceeded {
54 /// The capacity that refused the insertion.
55 limit: u32,
56 },
57 /// The configured or fixed-width definition capacity is reached.
58 #[error("the report already holds its limit of {limit} definitions")]
59 DefinitionCapacityExceeded {
60 /// The capacity that refused the insertion.
61 limit: u32,
62 },
63 /// The configured or fixed-width reference capacity is reached.
64 #[error("the report already holds its limit of {limit} references")]
65 ReferenceCapacityExceeded {
66 /// The capacity that refused the insertion.
67 limit: u32,
68 },
69 /// The configured or fixed-width resolution-record capacity is reached.
70 ///
71 /// A document may state more records than it states references, so this
72 /// ceiling is reached by a decoded report rather than by a writer.
73 #[error("the report already holds its limit of {limit} resolution records")]
74 ResolutionCapacityExceeded {
75 /// The capacity that refused the record.
76 limit: u32,
77 },
78 /// More than one record names one reference.
79 #[error("reference {reference} already carries a resolution record")]
80 DuplicateResolution {
81 /// The reference named twice.
82 reference: u32,
83 },
84 /// A definition or reference names a unit the report does not contain.
85 #[error("unit {unit} is not in the report")]
86 UnknownUnit {
87 /// The absent unit identifier.
88 unit: u32,
89 },
90 /// A parent, enclosing definition, or candidate names an absent definition.
91 #[error("definition {definition} is not in the report")]
92 UnknownDefinition {
93 /// The absent definition identifier.
94 definition: u32,
95 },
96 /// A record names a reference the report does not contain.
97 #[error("reference {reference} is not in the report")]
98 UnknownReference {
99 /// The absent reference identifier.
100 reference: u32,
101 },
102 /// An identifier does not equal its own sorted slice position.
103 #[error("{collection} position {position} carries identifier {id}")]
104 NonDenseId {
105 /// The collection holding the entry.
106 collection: ReportCollection,
107 /// The entry's position in the collection.
108 position: u32,
109 /// The identifier the entry carried.
110 id: u32,
111 },
112 /// A collection is not in its stable structural order.
113 #[error("{collection} position {position} breaks the structural order")]
114 UnsortedEntries {
115 /// The collection holding the entry.
116 collection: ReportCollection,
117 /// The position that follows a greater predecessor.
118 position: u32,
119 },
120 /// Two units share one stable key.
121 #[error("two units share the key `{key}`")]
122 DuplicateUnitKey {
123 /// The repeated key.
124 key: Box<str>,
125 },
126 /// A definition or reference contradicts its unit's language.
127 ///
128 /// The offender is named by its own coordinates, so a bad definition and a
129 /// bad reference at two positions never produce one value.
130 #[error("{collection} position {position} claims {claimed:?} in {unit_language:?} unit {unit}")]
131 UnitLanguageMismatch {
132 /// The collection holding the offending record.
133 collection: ReportCollection,
134 /// The offender's position in that collection.
135 position: u32,
136 /// The unit whose language was contradicted.
137 unit: u32,
138 /// The language the record claimed.
139 claimed: Language,
140 /// The language the unit states.
141 unit_language: Language,
142 },
143 /// A parent definition belongs to another unit.
144 #[error("definition {definition} has parent {parent} from another unit")]
145 ForeignParentDefinition {
146 /// The child definition.
147 definition: u32,
148 /// The parent in the other unit.
149 parent: u32,
150 },
151 /// An enclosing definition belongs to another unit.
152 #[error("reference {reference} is enclosed by definition {enclosing} from another unit")]
153 ForeignEnclosingDefinition {
154 /// The reference.
155 reference: u32,
156 /// The enclosing definition in the other unit.
157 enclosing: u32,
158 },
159 /// The definition-parent relation contains a cycle.
160 #[error("definition {definition} is its own ancestor")]
161 DefinitionParentCycle {
162 /// A definition on the cycle.
163 definition: u32,
164 },
165 /// A reference carries no resolution record.
166 #[error("reference {reference} carries no resolution record")]
167 MissingResolution {
168 /// The unrecorded reference.
169 reference: u32,
170 },
171 /// One record names one definition twice.
172 #[error("reference {reference} names candidate definition {definition} twice")]
173 DuplicateCandidate {
174 /// The record's reference.
175 reference: u32,
176 /// The repeated candidate definition.
177 definition: u32,
178 },
179 /// A record's candidates are out of order.
180 #[error("reference {reference} carries candidates out of order at position {position}")]
181 UnsortedCandidates {
182 /// The record's reference.
183 reference: u32,
184 /// The position that follows a greater predecessor.
185 position: u32,
186 },
187 /// One record names one gap twice.
188 #[error("reference {reference} names the gap {gap:?} twice")]
189 DuplicateGap {
190 /// The record's reference.
191 reference: u32,
192 /// The repeated gap.
193 gap: ResolutionGap,
194 },
195 /// A record's gaps are out of order.
196 #[error("reference {reference} carries gaps out of order at position {position}")]
197 UnsortedGaps {
198 /// The record's reference.
199 reference: u32,
200 /// The position that follows a greater predecessor.
201 position: u32,
202 },
203 /// A record mixes resolved and possible candidates.
204 #[error("reference {reference} mixes resolved and possible candidates")]
205 MixedCandidateCertainty {
206 /// The record's reference.
207 reference: u32,
208 },
209 /// A resolved record does not name exactly one definition.
210 #[error("reference {reference} is resolved to {candidates} candidates")]
211 ResolvedCandidateCount {
212 /// The record's reference.
213 reference: u32,
214 /// How many candidates the record carried.
215 candidates: u32,
216 },
217 /// A resolved record carries a gap.
218 #[error("reference {reference} is resolved and still carries a gap")]
219 ResolvedWithGaps {
220 /// The record's reference.
221 reference: u32,
222 },
223 /// A candidate-free record carries no gap.
224 #[error("reference {reference} has neither a candidate nor a gap")]
225 EmptyResolution {
226 /// The record's reference.
227 reference: u32,
228 },
229 /// A span names a path that is not normalized repository-relative.
230 #[error("`{path}` is not a normalized repository-relative path")]
231 InvalidSourcePath {
232 /// The rejected path.
233 path: Box<str>,
234 },
235 /// A span ends before it starts.
236 #[error("a span in `{path}` ends before it starts")]
237 ReversedSiteSpan {
238 /// The span's path.
239 path: Box<str>,
240 },
241 /// A span covers no source.
242 #[error("a span in `{path}` is zero width")]
243 EmptySiteSpan {
244 /// The span's path.
245 path: Box<str>,
246 },
247}