macroonz_compiler/closure/
type_contract.rs1use super::{ClosureError, ClosureIssue};
7use crate::bounded::{Bounded, Capping};
8use crate::diagnostic::{
9 CLOSURE_FAMILY, Family, LineBody, Observed, Phase, REPAIR_LIMIT, RefusalClass, Refused, Repair,
10};
11use crate::kind::Role;
12use core::fmt;
13
14impl<R: Role> ClosureIssue<R> {
15 #[must_use]
19 pub const fn slot(&self) -> u8 {
20 match self {
21 Self::MemberMissing { .. } => 0,
22 Self::MemberUnplanned { .. } => 1,
23 Self::MemberDuplicated { .. } => 2,
24 Self::OriginOrphan { .. } => 3,
25 Self::DigestMismatch { .. } => 4,
26 Self::SemanticKeyMismatch { .. } => 5,
27 Self::MaterializationMismatch { .. } => 6,
28 Self::MemberPlannedTwice { .. } => 7,
29 Self::MembershipDisagreement { .. } => 8,
30 Self::ReconstructionEmpty => 9,
31 Self::ReconstructionUndeclarable { .. } => 10,
32 Self::JoinedTreeUnbounded { .. } => 11,
33 Self::ArtifactAddressDoubled { .. } => 12,
34 Self::ArtifactAddressAbsent { .. } => 13,
35 }
36 }
37
38 #[must_use]
40 pub const fn role(&self) -> Option<R> {
41 match self {
42 Self::MemberMissing { role }
43 | Self::MemberUnplanned { role }
44 | Self::MemberDuplicated { role, .. }
45 | Self::OriginOrphan { role }
46 | Self::DigestMismatch { role }
47 | Self::SemanticKeyMismatch { role }
48 | Self::MaterializationMismatch { role }
49 | Self::MemberPlannedTwice { role, .. }
50 | Self::MembershipDisagreement { role }
51 | Self::ArtifactAddressDoubled { role, .. }
52 | Self::ArtifactAddressAbsent { role } => Some(*role),
53 Self::ReconstructionEmpty
54 | Self::ReconstructionUndeclarable { .. }
55 | Self::JoinedTreeUnbounded { .. } => None,
56 }
57 }
58
59 #[must_use]
61 pub const fn observed(&self) -> Observed {
62 match self {
63 Self::MemberMissing { .. }
64 | Self::ReconstructionEmpty
65 | Self::ArtifactAddressAbsent { .. } => Observed::SeatAbsent,
66 Self::MemberUnplanned { .. }
67 | Self::MemberDuplicated { .. }
68 | Self::MemberPlannedTwice { .. }
69 | Self::MembershipDisagreement { .. }
70 | Self::ArtifactAddressDoubled { .. } => Observed::ContractDisagreement,
71 Self::OriginOrphan { .. } => Observed::OriginAbsent,
72 Self::DigestMismatch { .. } | Self::SemanticKeyMismatch { .. } => {
73 Observed::IdentityDisagreement
74 }
75 Self::MaterializationMismatch { .. } => Observed::ProfileDisagreement,
76 Self::ReconstructionUndeclarable { .. } | Self::JoinedTreeUnbounded { .. } => {
77 Observed::BoundExceeded
78 }
79 }
80 }
81
82 #[must_use]
86 pub const fn class(&self) -> RefusalClass {
87 match self {
88 Self::ReconstructionUndeclarable { .. } | Self::JoinedTreeUnbounded { .. } => {
89 RefusalClass::MagnitudeNotHeld
90 }
91 Self::MemberMissing { .. }
92 | Self::MemberUnplanned { .. }
93 | Self::MemberDuplicated { .. }
94 | Self::OriginOrphan { .. }
95 | Self::DigestMismatch { .. }
96 | Self::SemanticKeyMismatch { .. }
97 | Self::MaterializationMismatch { .. }
98 | Self::MemberPlannedTwice { .. }
99 | Self::MembershipDisagreement { .. }
100 | Self::ReconstructionEmpty
101 | Self::ArtifactAddressDoubled { .. }
102 | Self::ArtifactAddressAbsent { .. } => RefusalClass::RenderingNotClosed,
103 }
104 }
105}
106
107impl<R: Role> fmt::Display for ClosureIssue<R> {
108 fn fmt(&self, into: &mut fmt::Formatter<'_>) -> fmt::Result {
109 match self {
110 Self::MemberMissing { role } => {
111 let seat = role.name();
112 write!(
113 into,
114 "the plan declares a member at {seat} and nothing rendered one"
115 )
116 }
117 Self::MemberUnplanned { role } => {
118 let seat = role.name();
119 write!(
120 into,
121 "a unit was rendered at {seat} and the plan declares none"
122 )
123 }
124 Self::MemberDuplicated { role, observed } => {
125 let seat = role.name();
126 write!(into, "{observed} units were rendered at {seat}")
127 }
128 Self::OriginOrphan { role } => {
129 let seat = role.name();
130 write!(
131 into,
132 "the unit at {seat} walks back to an origin the plan did not declare"
133 )
134 }
135 Self::DigestMismatch { role } => {
136 let seat = role.name();
137 write!(
138 into,
139 "the digest at {seat} is not the digest of the bytes that unit rendered"
140 )
141 }
142 Self::SemanticKeyMismatch { role } => {
143 let seat = role.name();
144 write!(
145 into,
146 "the unit at {seat} answers to a semantic key the plan declared elsewhere"
147 )
148 }
149 Self::MaterializationMismatch { role } => {
150 let seat = role.name();
151 write!(
152 into,
153 "the unit at {seat} names a profile or an address the plan did not declare"
154 )
155 }
156 Self::MemberPlannedTwice { role, observed } => {
157 let seat = role.name();
158 write!(
159 into,
160 "the plan itself declares {observed} members at {seat}"
161 )
162 }
163 Self::MembershipDisagreement { role } => {
164 let seat = role.name();
165 write!(
166 into,
167 "the rebuilt membership and the planned one are not the same set at {seat}"
168 )
169 }
170 Self::ReconstructionEmpty => into.write_str("the rebuild produced no member at all"),
171 Self::ReconstructionUndeclarable { observed } => write!(
172 into,
173 "the {observed} rebuilt members will not declare as a complete output set"
174 ),
175 Self::JoinedTreeUnbounded { destination } => {
176 let delivery = destination.name();
177 write!(
178 into,
179 "the tokens joined for {delivery} outgrow the declared magnitude"
180 )
181 }
182 Self::ArtifactAddressDoubled { role, address } => {
183 let seat = role.name();
184 let subject = address.subject;
185 write!(
186 into,
187 "the artifact at {seat} stands at an address under {subject} already taken"
188 )
189 }
190 Self::ArtifactAddressAbsent { role } => {
191 let seat = role.name();
192 write!(
193 into,
194 "the unit at {seat} is delivered to an address and the plan names none"
195 )
196 }
197 }
198 }
199}
200
201impl<R: Role> fmt::Display for ClosureError<R> {
202 fn fmt(&self, into: &mut fmt::Formatter<'_>) -> fmt::Result {
203 write!(into, "{}", self.first_issue())?;
204 let further = self.issues().count().saturating_sub(1);
205 if further > 0 {
206 write!(into, ", and {further} further issues")?;
207 }
208 if let Capping::Truncated { omitted } = self.capping() {
209 write!(into, ", {omitted} of them not carried")?;
210 }
211 Ok(())
212 }
213}
214
215impl<R: Role> core::error::Error for ClosureError<R> {}
216
217impl<R: Role> Refused for ClosureError<R> {
218 const PHASE: Phase = Phase::Closure;
219 const FAMILY: Family = CLOSURE_FAMILY;
220
221 fn class(&self) -> RefusalClass {
222 self.first_issue().class()
223 }
224
225 fn first(&self) -> String {
226 self.first_issue().to_string()
227 }
228
229 fn observed(&self) -> Observed {
230 self.first_issue().observed()
231 }
232
233 fn body(&self) -> LineBody {
234 let further = self.issues().count().saturating_sub(1);
235 let capping = self.capping();
236 if further == 0 && capping == Capping::Complete {
237 LineBody::SingleCause
238 } else {
239 LineBody::Body { further, capping }
240 }
241 }
242
243 fn related(&self) -> Vec<Vec<u8>> {
245 self.issues()
246 .iter()
247 .skip(1)
248 .map(ClosureIssue::canonical_bytes)
249 .collect()
250 }
251
252 fn repairs(&self) -> Bounded<Repair, REPAIR_LIMIT> {
256 Bounded::empty()
257 }
258}