1use thiserror::Error;
11
12use super::capacity_error::CapacityError;
13use crate::Codec;
14use crate::codec::assert_unit_bounds;
15
16#[derive(Clone, Copy, Debug, Eq, Error, Hash, PartialEq)]
23#[non_exhaustive]
24pub enum TranscodeFailure {
25 #[error("invalid input index {index} for input length {input_len}")]
27 InvalidInputIndex {
28 index: usize,
30 input_len: usize,
32 },
33
34 #[error("invalid output index {index} for output length {output_len}")]
36 InvalidOutputIndex {
37 index: usize,
39 output_len: usize,
41 },
42
43 #[error("invalid output range at index {output_index} with length {range_len} for output length {output_len}")]
45 InvalidOutputRange {
46 output_index: usize,
48 range_len: usize,
50 output_len: usize,
52 },
53
54 #[error("insufficient output at index {output_index}: required {required} units, available {available}")]
56 InsufficientOutput {
57 output_index: usize,
59 required: usize,
61 available: usize,
63 },
64
65 #[error("output length arithmetic overflow")]
67 OutputLengthOverflow,
68
69 #[error("output allocation failed")]
71 AllocationFailed,
72
73 #[error(
75 "incomplete input at index {input_index}: at least {required} units required to retry, {available} available"
76 )]
77 IncompleteInput {
78 input_index: usize,
80 required: usize,
83 available: usize,
85 },
86
87 #[error("trailing input after value: consumed {consumed} units, remaining {remaining}")]
89 TrailingInput {
90 consumed: usize,
92 remaining: usize,
94 },
95
96 #[error(
98 "strict single-value decoding does not support lifecycle output: reset bound {reset_bound}, finish bound {finish_bound}"
99 )]
100 UnsupportedDecodeLifecycleOutput {
101 reset_bound: usize,
103 finish_bound: usize,
105 },
106
107 #[error("transcode called after finish without an intervening reset")]
109 TranscodeAfterFinish,
110
111 #[error("transcode called before reset")]
113 TranscodeBeforeReset,
114
115 #[error("finish called twice without an intervening reset")]
117 FinishAfterFinish,
118
119 #[error("finish called before reset")]
121 FinishBeforeReset,
122
123 #[error("transcoder lifecycle is poisoned; a successful reset is required")]
127 LifecyclePoisoned,
128}
129
130impl TranscodeFailure {
131 #[inline(always)]
133 #[must_use]
134 pub const fn invalid_input_index(index: usize, len: usize) -> Self {
135 Self::InvalidInputIndex { index, input_len: len }
136 }
137
138 #[inline(always)]
140 #[must_use]
141 pub const fn invalid_output_index(index: usize, len: usize) -> Self {
142 Self::InvalidOutputIndex { index, output_len: len }
143 }
144
145 #[inline(always)]
147 #[must_use]
148 pub const fn invalid_output_range(output_index: usize, range_len: usize, output_len: usize) -> Self {
149 Self::InvalidOutputRange {
150 output_index,
151 range_len,
152 output_len,
153 }
154 }
155
156 #[inline(always)]
158 #[must_use]
159 pub const fn insufficient_output(output_index: usize, required: usize, available: usize) -> Self {
160 Self::InsufficientOutput {
161 output_index,
162 required,
163 available,
164 }
165 }
166
167 #[inline(always)]
169 #[must_use]
170 pub const fn output_length_overflow() -> Self {
171 Self::OutputLengthOverflow
172 }
173
174 #[inline(always)]
176 #[must_use]
177 pub const fn allocation_failed() -> Self {
178 Self::AllocationFailed
179 }
180
181 #[inline(always)]
183 #[must_use]
184 pub const fn incomplete_input(input_index: usize, required: usize, available: usize) -> Self {
185 Self::IncompleteInput {
186 input_index,
187 required,
188 available,
189 }
190 }
191
192 #[inline(always)]
194 #[must_use]
195 pub const fn trailing_input(consumed: usize, remaining: usize) -> Self {
196 Self::TrailingInput { consumed, remaining }
197 }
198
199 #[inline(always)]
201 #[must_use]
202 pub const fn unsupported_decode_lifecycle_output(reset_bound: usize, finish_bound: usize) -> Self {
203 Self::UnsupportedDecodeLifecycleOutput {
204 reset_bound,
205 finish_bound,
206 }
207 }
208
209 #[inline(always)]
224 pub(crate) fn ensure_no_decode_lifecycle_output<C>() -> Result<(), Self>
225 where
226 C: Codec,
227 {
228 assert_unit_bounds::<C>();
229 if C::MAX_DECODE_RESET_VALUES != 0 || C::MAX_DECODE_FINISH_VALUES != 0 {
230 return Err(Self::unsupported_decode_lifecycle_output(
231 C::MAX_DECODE_RESET_VALUES,
232 C::MAX_DECODE_FINISH_VALUES,
233 ));
234 }
235 Ok(())
236 }
237
238 #[inline]
240 pub fn ensure_input_index(input_len: usize, input_index: usize) -> Result<(), Self> {
241 if input_index > input_len {
242 return Err(Self::invalid_input_index(input_index, input_len));
243 }
244 Ok(())
245 }
246
247 #[inline]
249 pub fn ensure_min_input(input_len: usize, input_index: usize, min_required: usize) -> Result<(), Self> {
250 Self::ensure_input_index(input_len, input_index)?;
251 let available = input_len - input_index;
252 if available < min_required {
253 return Err(Self::incomplete_input(input_index, min_required, available));
254 }
255 Ok(())
256 }
257
258 #[inline]
275 pub fn ensure_no_trailing_input(consumed: usize, input_len: usize) -> Result<(), Self> {
276 Self::ensure_input_index(input_len, consumed)?;
277 let remaining = input_len - consumed;
278 if remaining != 0 {
279 return Err(Self::trailing_input(consumed, remaining));
280 }
281 Ok(())
282 }
283
284 #[inline]
286 pub fn ensure_output_index(output_len: usize, output_index: usize) -> Result<(), Self> {
287 if output_index > output_len {
288 return Err(Self::invalid_output_index(output_index, output_len));
289 }
290 Ok(())
291 }
292
293 #[inline]
295 pub fn ensure_transcode_indices(
296 input_len: usize,
297 input_index: usize,
298 output_len: usize,
299 output_index: usize,
300 ) -> Result<(), Self> {
301 Self::ensure_input_index(input_len, input_index)?;
302 Self::ensure_output_index(output_len, output_index)
303 }
304
305 #[inline]
307 pub fn ensure_output_capacity(output_len: usize, output_index: usize, required: usize) -> Result<(), Self> {
308 Self::ensure_output_index(output_len, output_index)?;
309 let available = output_len - output_index;
310 if available < required {
311 return Err(Self::insufficient_output(output_index, required, available));
312 }
313 Ok(())
314 }
315
316 #[inline]
318 pub fn ensure_output_range(
319 output_len: usize,
320 output_index: usize,
321 range_len: usize,
322 required: usize,
323 ) -> Result<(), Self> {
324 Self::ensure_output_index(output_len, output_index)?;
325 let available = output_len - output_index;
326 if range_len > available {
327 return Err(Self::invalid_output_range(output_index, range_len, output_len));
328 }
329 if range_len < required {
330 return Err(Self::insufficient_output(output_index, required, range_len));
331 }
332 Ok(())
333 }
334}
335
336impl From<CapacityError> for TranscodeFailure {
337 #[inline(always)]
339 fn from(error: CapacityError) -> Self {
340 match error {
341 CapacityError::OutputLengthOverflow => Self::OutputLengthOverflow,
342 }
343 }
344}