Skip to main content

qubit_codec/codec/
codec_encode_error.rs

1// =============================================================================
2//    Copyright (c) 2026 Haixing Hu.
3//
4//    SPDX-License-Identifier: Apache-2.0
5//
6//    Licensed under the Apache License, Version 2.0.
7// =============================================================================
8//! Generic encode error used by codec-backed encoder adapters.
9
10use thiserror::Error;
11
12/// Error reported by codec-backed buffered encoder adapters.
13///
14/// The wrapped codec remains responsible for domain-specific encode failures.
15/// This type adds adapter-level failures that cannot be represented by the
16/// wrapped codec itself, such as a buffered encoder receiving an invalid input
17/// or output start index.
18#[derive(Clone, Copy, Debug, Eq, Error, Hash, PartialEq)]
19pub enum CodecEncodeError<E> {
20    /// The wrapped codec reported an encode error.
21    #[error("codec encode error at input index {input_index}: {source}")]
22    Encode {
23        /// Error returned by the wrapped codec.
24        #[source]
25        source: E,
26        /// Absolute input index of the value being encoded.
27        input_index: usize,
28    },
29
30    /// The wrapped codec cannot represent the input value.
31    #[error("unencodable value at input index {input_index}")]
32    UnencodableValue {
33        /// Absolute input index of the value being encoded.
34        input_index: usize,
35    },
36
37    /// The caller supplied an input index outside the input slice.
38    #[error("invalid input index {index} for input length {len}")]
39    InvalidInputIndex {
40        /// Invalid input index supplied by the caller.
41        index: usize,
42        /// Length of the input slice.
43        len: usize,
44    },
45
46    /// The caller supplied an output index outside the output slice.
47    #[error("invalid output index {index} for output length {len}")]
48    InvalidOutputIndex {
49        /// Invalid output index supplied by the caller.
50        index: usize,
51        /// Length of the output slice.
52        len: usize,
53    },
54
55    /// The output slice cannot hold all output required by the adapter call.
56    #[error(
57        "insufficient output at index {output_index}: required {required} units, available {available}"
58    )]
59    InsufficientOutput {
60        /// Absolute output index where writing would start.
61        output_index: usize,
62        /// Output units required from `output_index`.
63        required: usize,
64        /// Output units available from `output_index`.
65        available: usize,
66    },
67
68    /// Output length arithmetic overflowed while planning encoded output.
69    #[error("output length arithmetic overflow")]
70    OutputLengthOverflow,
71}
72
73impl<E> CodecEncodeError<E> {
74    /// Creates an error wrapping a codec-specific encode error.
75    ///
76    /// # Parameters
77    ///
78    /// - `source`: Error returned by the wrapped codec.
79    /// - `input_index`: Absolute input index of the value being encoded.
80    ///
81    /// # Returns
82    ///
83    /// Returns a codec encode error wrapper.
84    #[must_use]
85    #[inline(always)]
86    pub const fn encode(source: E, input_index: usize) -> Self {
87        Self::Encode {
88            source,
89            input_index,
90        }
91    }
92
93    /// Creates an unencodable-value error.
94    ///
95    /// # Parameters
96    ///
97    /// - `input_index`: Absolute input index of the value being encoded.
98    ///
99    /// # Returns
100    ///
101    /// Returns an unencodable-value error.
102    #[must_use]
103    #[inline(always)]
104    pub const fn unencodable_value(input_index: usize) -> Self {
105        Self::UnencodableValue { input_index }
106    }
107
108    /// Creates an invalid-input-index error.
109    ///
110    /// # Parameters
111    ///
112    /// - `index`: Invalid input index supplied by the caller.
113    /// - `len`: Length of the input slice.
114    ///
115    /// # Returns
116    ///
117    /// Returns an invalid-input-index error.
118    #[must_use]
119    #[inline(always)]
120    pub const fn invalid_input_index(index: usize, len: usize) -> Self {
121        Self::InvalidInputIndex { index, len }
122    }
123
124    /// Creates an invalid-output-index error.
125    ///
126    /// # Parameters
127    ///
128    /// - `index`: Invalid output index supplied by the caller.
129    /// - `len`: Length of the output slice.
130    ///
131    /// # Returns
132    ///
133    /// Returns an invalid-output-index error.
134    #[must_use]
135    #[inline(always)]
136    pub const fn invalid_output_index(index: usize, len: usize) -> Self {
137        Self::InvalidOutputIndex { index, len }
138    }
139
140    /// Creates an insufficient-output error.
141    ///
142    /// # Parameters
143    ///
144    /// - `output_index`: Output index supplied by the caller.
145    /// - `required`: Output units required from `output_index`.
146    /// - `available`: Output units available from `output_index`.
147    ///
148    /// # Returns
149    ///
150    /// Returns an insufficient-output error.
151    #[must_use]
152    #[inline(always)]
153    pub const fn insufficient_output(
154        output_index: usize,
155        required: usize,
156        available: usize,
157    ) -> Self {
158        Self::InsufficientOutput {
159            output_index,
160            required,
161            available,
162        }
163    }
164
165    /// Creates an output-length-overflow error.
166    ///
167    /// # Returns
168    ///
169    /// Returns an output-length-overflow error.
170    #[must_use]
171    #[inline(always)]
172    pub const fn output_length_overflow() -> Self {
173        Self::OutputLengthOverflow
174    }
175
176    /// Validates that `input_index` is within an input slice.
177    ///
178    /// # Parameters
179    ///
180    /// - `input_len`: Length of the input slice.
181    /// - `input_index`: Input index supplied by the caller.
182    ///
183    /// # Returns
184    ///
185    /// Returns `Ok(())` when `input_index <= input_len`.
186    ///
187    /// # Errors
188    ///
189    /// Returns an invalid-input-index error when `input_index` is beyond the
190    /// slice.
191    #[inline]
192    pub fn ensure_input_index(
193        input_len: usize,
194        input_index: usize,
195    ) -> Result<(), Self> {
196        if input_index > input_len {
197            return Err(Self::invalid_input_index(input_index, input_len));
198        }
199        Ok(())
200    }
201
202    /// Validates that `output_index` is within an output slice.
203    ///
204    /// # Parameters
205    ///
206    /// - `output_len`: Length of the output slice.
207    /// - `output_index`: Output index supplied by the caller.
208    ///
209    /// # Returns
210    ///
211    /// Returns `Ok(())` when `output_index <= output_len`.
212    ///
213    /// # Errors
214    ///
215    /// Returns an invalid-output-index error when `output_index` is beyond the
216    /// slice.
217    #[inline]
218    pub fn ensure_output_index(
219        output_len: usize,
220        output_index: usize,
221    ) -> Result<(), Self> {
222        if output_index > output_len {
223            return Err(Self::invalid_output_index(output_index, output_len));
224        }
225        Ok(())
226    }
227
228    /// Validates that an output slice can hold required adapter output.
229    ///
230    /// # Parameters
231    ///
232    /// - `output_len`: Length of the output slice.
233    /// - `output_index`: Output index supplied by the caller.
234    /// - `required`: Output units required from `output_index`.
235    ///
236    /// # Returns
237    ///
238    /// Returns `Ok(())` when output capacity is sufficient.
239    ///
240    /// # Errors
241    ///
242    /// Returns an invalid-output-index error when `output_index` is beyond the
243    /// slice, or an insufficient-output error when fewer than `required` units
244    /// are writable from `output_index`.
245    #[inline]
246    pub fn ensure_output_capacity(
247        output_len: usize,
248        output_index: usize,
249        required: usize,
250    ) -> Result<(), Self> {
251        Self::ensure_output_index(output_len, output_index)?;
252        let available = output_len - output_index;
253        if available < required {
254            return Err(Self::insufficient_output(
255                output_index,
256                required,
257                available,
258            ));
259        }
260        Ok(())
261    }
262}