1use core::num::NonZeroUsize;
4
5#[path = "contracts/reporting.rs"]
6mod reporting;
7
8#[allow(unused_imports)]
11pub(crate) use super::lifecycle::Lifecycle;
12#[allow(unused_imports)]
13pub use super::lifecycle::SourceSpan;
14#[allow(unused_imports)]
15pub use reporting::{AssuranceClass, Atomicity, BackendClass, ProtocolScope};
16
17#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
19pub struct Progress {
20 input_consumed: usize,
21 output_produced: usize,
22}
23
24impl Progress {
25 pub const ZERO: Self = Self::new(0, 0);
27
28 pub(crate) const fn new(input_consumed: usize, output_produced: usize) -> Self {
30 Self {
31 input_consumed,
32 output_produced,
33 }
34 }
35
36 #[must_use]
38 pub const fn input_consumed(self) -> usize {
39 self.input_consumed
40 }
41
42 #[must_use]
44 pub const fn output_produced(self) -> usize {
45 self.output_produced
46 }
47}
48
49#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
51pub struct OutputFull {
52 minimum_output: NonZeroUsize,
53}
54
55impl OutputFull {
56 pub(crate) const fn new(minimum_output: NonZeroUsize) -> Self {
58 Self { minimum_output }
59 }
60
61 #[must_use]
63 pub const fn minimum_output(self) -> NonZeroUsize {
64 self.minimum_output
65 }
66}
67
68#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
70#[non_exhaustive]
71pub enum Status {
72 NeedInput,
74 OutputFull(OutputFull),
76 Complete,
78}
79
80impl Status {
81 #[must_use]
83 pub const fn as_str(&self) -> &'static str {
84 match self {
85 Self::NeedInput => "need-input",
86 Self::OutputFull(_) => "output-full",
87 Self::Complete => "complete",
88 }
89 }
90}
91
92#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
94pub struct Step {
95 progress: Progress,
96 status: Status,
97}
98
99impl Step {
100 pub(crate) const fn new(progress: Progress, status: Status) -> Self {
101 Self { progress, status }
102 }
103
104 #[must_use]
106 pub const fn progress(self) -> Progress {
107 self.progress
108 }
109
110 #[must_use]
112 pub const fn status(self) -> Status {
113 self.status
114 }
115}
116
117#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
119#[non_exhaustive]
120pub enum InputErrorKind {
121 InvalidByte,
123 InvalidPadding,
125 NonCanonicalTrailingBits,
127 InvalidLength,
129 TruncatedInput,
131 TrailingData,
133 InvalidLineWrap,
135}
136
137impl InputErrorKind {
138 #[must_use]
140 pub const fn as_str(self) -> &'static str {
141 match self {
142 Self::InvalidByte => "invalid-byte",
143 Self::InvalidPadding => "invalid-padding",
144 Self::NonCanonicalTrailingBits => "noncanonical-trailing-bits",
145 Self::InvalidLength => "invalid-length",
146 Self::TruncatedInput => "truncated-input",
147 Self::TrailingData => "trailing-data",
148 Self::InvalidLineWrap => "invalid-line-wrap",
149 }
150 }
151}
152
153#[derive(Clone, Copy, Eq, Hash, PartialEq)]
158#[non_exhaustive]
159pub enum InputError {
160 InvalidByte {
162 index: usize,
164 byte: u8,
166 },
167 InvalidPadding {
169 index: usize,
171 },
172 NonCanonicalTrailingBits {
174 index: usize,
176 },
177 InvalidLength,
179 TruncatedInput {
181 index: usize,
183 },
184 TrailingData {
186 index: usize,
188 },
189 InvalidLineWrap {
191 index: usize,
193 },
194}
195
196impl InputError {
197 #[must_use]
199 pub const fn kind(self) -> InputErrorKind {
200 match self {
201 Self::InvalidByte { .. } => InputErrorKind::InvalidByte,
202 Self::InvalidPadding { .. } => InputErrorKind::InvalidPadding,
203 Self::NonCanonicalTrailingBits { .. } => InputErrorKind::NonCanonicalTrailingBits,
204 Self::InvalidLength => InputErrorKind::InvalidLength,
205 Self::TruncatedInput { .. } => InputErrorKind::TruncatedInput,
206 Self::TrailingData { .. } => InputErrorKind::TrailingData,
207 Self::InvalidLineWrap { .. } => InputErrorKind::InvalidLineWrap,
208 }
209 }
210}
211
212impl core::fmt::Debug for InputError {
213 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
214 formatter
215 .debug_struct("InputError")
216 .field("kind", &self.kind())
217 .finish_non_exhaustive()
218 }
219}
220
221impl core::fmt::Display for InputError {
222 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
223 match self {
224 Self::InvalidByte { index, byte } => {
225 write!(
226 formatter,
227 "invalid byte 0x{byte:02x} at source index {index}"
228 )
229 }
230 Self::InvalidPadding { index } => {
231 write!(formatter, "invalid padding at source index {index}")
232 }
233 Self::NonCanonicalTrailingBits { index } => {
234 write!(
235 formatter,
236 "noncanonical trailing bits at source index {index}"
237 )
238 }
239 Self::InvalidLength => formatter.write_str("invalid encoded input length"),
240 Self::TruncatedInput { index } => {
241 write!(formatter, "truncated input at source index {index}")
242 }
243 Self::TrailingData { index } => {
244 write!(formatter, "trailing data at source index {index}")
245 }
246 Self::InvalidLineWrap { index } => {
247 write!(formatter, "invalid line wrapping at source index {index}")
248 }
249 }
250 }
251}
252
253#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
255#[non_exhaustive]
256pub enum BackendFault {
257 SelfTestFailed,
259 OutputMismatch,
261 ImpossibleState,
263 ScalarRetryFailed,
265}
266
267impl BackendFault {
268 #[must_use]
270 pub const fn as_str(self) -> &'static str {
271 match self {
272 Self::SelfTestFailed => "backend-self-test-failed",
273 Self::OutputMismatch => "backend-output-mismatch",
274 Self::ImpossibleState => "backend-impossible-state",
275 Self::ScalarRetryFailed => "backend-scalar-retry-failed",
276 }
277 }
278}
279
280#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
282#[non_exhaustive]
283pub enum Failure {
284 Input(InputError),
286 PositionOverflow,
288 Backend(BackendFault),
290 ResourceLimit,
292}
293
294impl Failure {
295 #[must_use]
297 pub const fn as_str(self) -> &'static str {
298 match self {
299 Self::Input(error) => error.kind().as_str(),
300 Self::PositionOverflow => "position-overflow",
301 Self::Backend(fault) => fault.as_str(),
302 Self::ResourceLimit => "resource-limit",
303 }
304 }
305}
306
307#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
309#[non_exhaustive]
310pub enum TerminalError {
311 InputAfterFinish,
313 InputAfterComplete,
315}
316
317impl TerminalError {
318 #[must_use]
320 pub const fn as_str(self) -> &'static str {
321 match self {
322 Self::InputAfterFinish => "input-after-finish",
323 Self::InputAfterComplete => "input-after-complete",
324 }
325 }
326}
327
328#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
330#[non_exhaustive]
331pub enum OperationError {
332 Failed(Failure),
334 Terminal(TerminalError),
336}
337
338impl OperationError {
339 #[must_use]
341 pub const fn as_str(self) -> &'static str {
342 match self {
343 Self::Failed(failure) => failure.as_str(),
344 Self::Terminal(error) => error.as_str(),
345 }
346 }
347}
348
349impl core::fmt::Display for OperationError {
350 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
351 match self {
352 Self::Failed(Failure::Input(error)) => error.fmt(formatter),
353 Self::Failed(failure) => formatter.write_str(failure.as_str()),
354 Self::Terminal(error) => formatter.write_str(error.as_str()),
355 }
356 }
357}
358
359impl core::error::Error for OperationError {}