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}