1use thiserror::Error;
11
12use crate::{
13 Codec,
14 codec::assert_unit_bounds,
15};
16
17use super::capacity_error::CapacityError;
18
19#[derive(Clone, Copy, Debug, Eq, Error, Hash, PartialEq)]
26#[non_exhaustive]
27pub enum TranscodeFailure {
28 #[error("invalid input index {index} for input length {input_len}")]
30 InvalidInputIndex {
31 index: usize,
33 input_len: usize,
35 },
36
37 #[error("invalid output index {index} for output length {output_len}")]
39 InvalidOutputIndex {
40 index: usize,
42 output_len: usize,
44 },
45
46 #[error(
48 "invalid output range at index {output_index} with length {range_len} for output length {output_len}"
49 )]
50 InvalidOutputRange {
51 output_index: usize,
53 range_len: usize,
55 output_len: usize,
57 },
58
59 #[error(
61 "insufficient output at index {output_index}: required {required} units, available {available}"
62 )]
63 InsufficientOutput {
64 output_index: usize,
66 required: usize,
68 available: usize,
70 },
71
72 #[error("output length arithmetic overflow")]
74 OutputLengthOverflow,
75
76 #[error("output allocation failed")]
78 AllocationFailed,
79
80 #[error(
82 "incomplete input at index {input_index}: at least {required} units required to retry, {available} available"
83 )]
84 IncompleteInput {
85 input_index: usize,
87 required: usize,
90 available: usize,
92 },
93
94 #[error(
96 "trailing input after value: consumed {consumed} units, remaining {remaining}"
97 )]
98 TrailingInput {
99 consumed: usize,
101 remaining: usize,
103 },
104
105 #[error(
107 "strict single-value decoding does not support lifecycle output: reset bound {reset_bound}, finish bound {finish_bound}"
108 )]
109 UnsupportedDecodeLifecycleOutput {
110 reset_bound: usize,
112 finish_bound: usize,
114 },
115
116 #[error("transcode called after finish without an intervening reset")]
118 TranscodeAfterFinish,
119
120 #[error("transcode called before reset")]
122 TranscodeBeforeReset,
123
124 #[error("finish called twice without an intervening reset")]
126 FinishAfterFinish,
127
128 #[error("finish called before reset")]
130 FinishBeforeReset,
131
132 #[error("transcoder lifecycle is poisoned; a successful reset is required")]
136 LifecyclePoisoned,
137}
138
139impl TranscodeFailure {
140 #[inline(always)]
142 #[must_use]
143 pub const fn invalid_input_index(index: usize, len: usize) -> Self {
144 Self::InvalidInputIndex {
145 index,
146 input_len: len,
147 }
148 }
149
150 #[inline(always)]
152 #[must_use]
153 pub const fn invalid_output_index(index: usize, len: usize) -> Self {
154 Self::InvalidOutputIndex {
155 index,
156 output_len: len,
157 }
158 }
159
160 #[inline(always)]
162 #[must_use]
163 pub const fn invalid_output_range(
164 output_index: usize,
165 range_len: usize,
166 output_len: usize,
167 ) -> Self {
168 Self::InvalidOutputRange {
169 output_index,
170 range_len,
171 output_len,
172 }
173 }
174
175 #[inline(always)]
177 #[must_use]
178 pub const fn insufficient_output(
179 output_index: usize,
180 required: usize,
181 available: usize,
182 ) -> Self {
183 Self::InsufficientOutput {
184 output_index,
185 required,
186 available,
187 }
188 }
189
190 #[inline(always)]
192 #[must_use]
193 pub const fn output_length_overflow() -> Self {
194 Self::OutputLengthOverflow
195 }
196
197 #[inline(always)]
199 #[must_use]
200 pub const fn allocation_failed() -> Self {
201 Self::AllocationFailed
202 }
203
204 #[inline(always)]
206 #[must_use]
207 pub const fn incomplete_input(
208 input_index: usize,
209 required: usize,
210 available: usize,
211 ) -> Self {
212 Self::IncompleteInput {
213 input_index,
214 required,
215 available,
216 }
217 }
218
219 #[inline(always)]
221 #[must_use]
222 pub const fn trailing_input(consumed: usize, remaining: usize) -> Self {
223 Self::TrailingInput {
224 consumed,
225 remaining,
226 }
227 }
228
229 #[inline(always)]
231 #[must_use]
232 pub const fn unsupported_decode_lifecycle_output(
233 reset_bound: usize,
234 finish_bound: usize,
235 ) -> Self {
236 Self::UnsupportedDecodeLifecycleOutput {
237 reset_bound,
238 finish_bound,
239 }
240 }
241
242 #[inline(always)]
257 pub(crate) fn ensure_no_decode_lifecycle_output<C>() -> Result<(), Self>
258 where
259 C: Codec,
260 {
261 assert_unit_bounds::<C>();
262 if C::MAX_DECODE_RESET_VALUES != 0 || C::MAX_DECODE_FINISH_VALUES != 0 {
263 return Err(Self::unsupported_decode_lifecycle_output(
264 C::MAX_DECODE_RESET_VALUES,
265 C::MAX_DECODE_FINISH_VALUES,
266 ));
267 }
268 Ok(())
269 }
270
271 #[inline]
273 pub fn ensure_input_index(
274 input_len: usize,
275 input_index: usize,
276 ) -> Result<(), Self> {
277 if input_index > input_len {
278 return Err(Self::invalid_input_index(input_index, input_len));
279 }
280 Ok(())
281 }
282
283 #[inline]
285 pub fn ensure_min_input(
286 input_len: usize,
287 input_index: usize,
288 min_required: usize,
289 ) -> Result<(), Self> {
290 Self::ensure_input_index(input_len, input_index)?;
291 let available = input_len - input_index;
292 if available < min_required {
293 return Err(Self::incomplete_input(
294 input_index,
295 min_required,
296 available,
297 ));
298 }
299 Ok(())
300 }
301
302 #[inline]
319 pub fn ensure_no_trailing_input(
320 consumed: usize,
321 input_len: usize,
322 ) -> Result<(), Self> {
323 Self::ensure_input_index(input_len, consumed)?;
324 let remaining = input_len - consumed;
325 if remaining != 0 {
326 return Err(Self::trailing_input(consumed, remaining));
327 }
328 Ok(())
329 }
330
331 #[inline]
333 pub fn ensure_output_index(
334 output_len: usize,
335 output_index: usize,
336 ) -> Result<(), Self> {
337 if output_index > output_len {
338 return Err(Self::invalid_output_index(output_index, output_len));
339 }
340 Ok(())
341 }
342
343 #[inline]
345 pub fn ensure_transcode_indices(
346 input_len: usize,
347 input_index: usize,
348 output_len: usize,
349 output_index: usize,
350 ) -> Result<(), Self> {
351 Self::ensure_input_index(input_len, input_index)?;
352 Self::ensure_output_index(output_len, output_index)
353 }
354
355 #[inline]
357 pub fn ensure_output_capacity(
358 output_len: usize,
359 output_index: usize,
360 required: usize,
361 ) -> Result<(), Self> {
362 Self::ensure_output_index(output_len, output_index)?;
363 let available = output_len - output_index;
364 if available < required {
365 return Err(Self::insufficient_output(
366 output_index,
367 required,
368 available,
369 ));
370 }
371 Ok(())
372 }
373
374 #[inline]
376 pub fn ensure_output_range(
377 output_len: usize,
378 output_index: usize,
379 range_len: usize,
380 required: usize,
381 ) -> Result<(), Self> {
382 Self::ensure_output_index(output_len, output_index)?;
383 let available = output_len - output_index;
384 if range_len > available {
385 return Err(Self::invalid_output_range(
386 output_index,
387 range_len,
388 output_len,
389 ));
390 }
391 if range_len < required {
392 return Err(Self::insufficient_output(
393 output_index,
394 required,
395 range_len,
396 ));
397 }
398 Ok(())
399 }
400}
401
402impl From<CapacityError> for TranscodeFailure {
403 #[inline(always)]
405 fn from(error: CapacityError) -> Self {
406 match error {
407 CapacityError::OutputLengthOverflow => Self::OutputLengthOverflow,
408 }
409 }
410}